Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails/ActiveRecord: save changes to a model's associated collections

Do I have to save modifications to individual items in a collection for a model, or is there a method I can call to save them when I save the model.

#save doesn't seem to do it. For example:

irb> rental = #...
#=> #<Rental id: 18737, customer_id: 61, dvd_id: 3252, date_rented: "2008-12-16 05:00:00", date_shipped: "2008-12-16 05:00:00", date_returned: "2008-12-22 05:00:00">
irb> rental.dvd
#=> #<Dvd id: 3252, title: "The Women of Summer", year: 1986, copies: 20, is_new: false, is_discontinued: false, list_price: #<BigDecimal:1a48f0c,'0.1599E2',8(8)>, sale_price: #<BigDecimal:1a48ed0,'0.1599E2',8(8)>>
irb> rental.dvd.copies += 1
#=> 21
irb> rental.save
#=> true
irb> rental.dvd
#=> #<Dvd id: 3252, title: "The Women of Summer", year: 1986, copies: 21, is_new: false, is_discontinued: false, list_price: #<BigDecimal:1a2e9cc,'0.1599E2',8(8)>, sale_price: #<BigDecimal:1a2e97c,'0.1599E2',8(8)>>
irb> Dvd.find_by_title('The Women of Summer')
#=> #<Dvd id: 3252, title: "The Women of Summer", year: 1986, copies: 20, is_new: false, is_discontinued: false, list_price: #<BigDecimal:1a30164,'0.1599E2',8(8)>, sale_price: #<BigDecimal:1a30128,'0.1599E2',8(8)>>

In the above example, the copy of the DVD that the rental has doesn't seem to update the copy in the DB (note the differing number of copies).

like image 255
rampion Avatar asked May 15 '09 17:05

rampion


3 Answers

You can configure ActiveRecord to cascade-save changes to items in a collection for a model by adding the :autosave => true option when declaring the association. Read more.

Example:

class Payment < ActiveRecord::Base
    belongs_to :cash_order, :autosave => true
    ...
end
like image 157
mockaroodev Avatar answered Sep 20 '22 20:09

mockaroodev


just do a rental.dvd.save after you increment the value or in the above case you could use

rental.dvd.increment!(:copies)

which will also automatically save, note the '!' on increment!

like image 26
Corban Brook Avatar answered Sep 19 '22 20:09

Corban Brook


You have to do this yourself

This isnt entirely true. You can use the "build" method which will force a save. For the sake of example assume that you have a Company model and Employees (Company has_many Employees). You could do something like:

acme = Company.new({:name => "Acme, Inc"})
acme.employees.build({:first_name => "John"})
acme.employees.build({:first_name => "Mary"})
acme.employees.build({:first_name => "Sue"})
acme.save

Would create all 4 records, the Company record and the 3 Employee records and the company_id would be pushed down to the Employee object appropriately.

like image 23
Cody Caughlan Avatar answered Sep 23 '22 20:09

Cody Caughlan