Albert Català
Albert Català

Reputation: 2044

How to manipulate an ActiveRecord::Relation result and filter it without query to the database again

I want to retrieve records form table, initialize some fields, and then update data on memory (not saving to database) after some filter. But this second filter makes a new query to the database, so I can't initialize these fields.

How can I solve this issue?

res=where(code: 0)          # (1) retrieve objects from db, as a template
res.each{|r| r.amount=10}    # (2) change amount field with 10 in res

Here I expect 10+2 but the result is 0+2: because next line executes query on database, so line (2) it has no effect

 res.where("caconana='1221").first.amount+= 2  

Possible answer: Is there a better solution than convert 'res' to an array?

res=where(code: 0).to_a
res.each{|r| r.amount=10}
i=res.find_index{|r| r.caconana=='1221'}
res[i]+=2

Thanks to PSKocit I have the solution: find method does not execute query to database

Upvotes: 2

Views: 1459

Answers (1)

Petr Skocik
Petr Skocik

Reputation: 60058

That each method call on res will cause all the matching ActiveRecords object to be fully constructed anyway. So if you do want them constructed, you might as well use the caconana attributes that got loaded:

res.each {|r| r.amount = 10 }
res.find {|r| r.caconana == 1221 }.amount+=2

(Then you'd need to save each record to have that committed to the database.)

You can avoid some ActiveRecord object construction with:

where(code: 0).update_all(amount: 10) #One query to the database, no AR objects constructed in memory

Then for the incrementing (this is with AR object construction, but it's just for one record)

obj = where(code: 0).where(caconana: 1221).limit(1).first
obj.amount+=2
#obj.save!

Upvotes: 2

Related Questions