问题
I want to update a column in a Supply model that updates with its stock based on a sum of a subset. The thing is that actually hits two queries to make it works.
total_stock = History.sum(:quantity) # first query
Supply.update_columns(stock: total_stock) # second query
Then, I tried to write a subquery so:
total_stock_subquery = mysubset.select(Arel.sql('SUM(quantity)')).to_sql
Supply.update_columns(stock: total_stock_subquery) # it should be only one query
But, ActiveRecord will replace the total_stock_subquery variable as a string inside the resulting sql statement, then query fails.
I tried to wrap the total_stock_subquery parameter inside an Arel.sql thinking that ActiveRecord will detect that the parameter is not a string, but Arel.sql, and would escape this as raw sql, but it didnt work.
Supply.update_columns(stock: Arel.sql(total_stock_subquery)) # dont work too
Then, do you know how can I pass an sql subquery as parameter for a column inside .update_column, o maybe how to tell ActiveRecord that some parameter should be treated as pure sql not as string?
I know I could write this update as raw sql but I think it would be off Rails style.
EDIT: Table definitions
History
- id: integer
- supply_id: reference
- quantity: decimal(9,2)
Supply
- id: integer
- product: string
- stock: decimal(9,2)
class History
belongs_to: supply
end
class Supply
has_many: histories
end
We use the History model to track in and out (positive for in, negative for out) of supplies, then the sum of the histories will be the current stock.
Of course I can implement an after_save on History model to update the stock when some quantity changes it, but for this example, Im implementing a "rebase" or "recalculate" method for all supplies stock, then I need to make the sum for each Supply.
来源:https://stackoverflow.com/questions/61703714/activerecord-model-update-column-with-subquery