Use ActiveModelSerializers with rawSQL query result

347 Views Asked by At

I would like to use ActiveModelSerializers on the result of a rawSQL query in Rails. Can't find a way to do it.

sql = "SELECT * FROM table"
results = ActiveRecord::Base.connection.exec_query(sql)
options = { each_serializer: MySerializer }
output = ActiveModelSerializers::SerializableResource.new(results, options).as_json

I've tried several options:

ActiveRecord::Base.connection.execute(sql)

give a PG::Result

ActiveRecord::Base.connection.exec_query(sql)

give a ActiveRecords::Result

But none of that can be serialized.

2

There are 2 best solutions below

0
Dmitry Barskov On

active_model_serializers doesn't seem to be supported so consider choosing another library.

Hashes can't be serialized with your custom serializer, because they don't have read_attribute_for_serialization. So we can wrap hashes of results with such a class:

class SerializableHash
  def initialize(original_hash)
    @original_hash = original_hash
  end

  def read_attribute_for_serialization(attribute)
    @original_hash[attribute]
  end
end

After that they can be serialized:

sql = "SELECT * FROM table"
results = ActiveRecord::Base.connection.exec_query(sql).map do |item|
  SerializableHash.new(item)
end

options = { each_serializer: UserSerializer }
output = ActiveModelSerializers::SerializableResource.new(results, options).as_json
0
Dmitry Barskov On

active_model_serializers doesn't seem to be supported so consider choosing another library.

This isn't the best way, monkey patching is not recommended

Hashes can't be serialized with your custom serializer, because they don't have read_attribute_for_serialization. So the simplest way to solve this problem is to monkey patch the Hash class:

class Hash
  alias_method :read_attribute_for_serialization, :[]
end

Then it should work as expected:

sql = "SELECT * FROM table"
results = ActiveRecord::Base.connection.exec_query(sql)
options = { each_serializer: UserSerializer }
output = ActiveModelSerializers::SerializableResource.new(results, options).as_json