Open antulik opened 3 years ago
A workaround
User.each_row do |attributes|
user = User.instantiate attributes
# do stuff
end
Note: it only works for simple queries where returned columns map directly to model columns
Looking at rails code, rails defaults column types instead of relying on postgres.
while postgresql_cursor
gem forces all column types from postgres
We had the same issue with an enum
column and I suspect this would do to this as well for our columns using store_model
.
Our workaround was to use the cursor instance directly to override the klass param passed to each_instance:
class ModelInstantiator
def initialize(model)
@model = model
end
def instantiate(row, column_types)
column_types = column_types.reject { |k, _| @model.attribute_types.key?(k) }
@model.instantiate(row, column_types)
end
end
SomeModel.all.each_row(**some_kwargs).each_instance(ModelInstantiator.new(SomeModel)) do |record|
# .... do something with record
end
I have an issue with DateTime
which is solved by running eg. created_at.in_time_zone.to_fs(:dmy)
, else it is printing UTC.
activerecord (= 7.0.5.1)
Update: I endup following to what Rails has been doing with column_types
by rejecting if the attribute_types has the mapping keys column_types.reject { |k, _| klass.attribute_types.key?(k) }
, the column_types
then becomes an empty hash.
def each_instance(klass = nil, &block)
klass ||= @type
each_tuple do |row|
if ::ActiveRecord::VERSION::MAJOR < 4
model = klass.send(:instantiate, row)
else
@column_types ||= column_types.reject { |k, _| klass.attribute_types.key?(k) }
model = klass.send(:instantiate, row, @column_types)
end
block.call(model)
end
end
def each_instance_batch(klass = nil, &block)
klass ||= @type
each_batch do |batch|
models = batch.map do |row|
if ::ActiveRecord::VERSION::MAJOR < 4
klass.send(:instantiate, row)
else
@column_types ||= column_types.reject { |k, _| klass.attribute_types.key?(k) }
klass.send(:instantiate, row, @column_types)
end
end
block.call(models)
end
end
and it works
each_instance
incorrectly sets the column types, for exampleExpected. in the example above objects from both queries should be identical
rails -v => Rails 6.0.3.4 ruby -v => ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin19]