rampion
rampion

Reputation: 89093

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).

Upvotes: 7

Views: 12287

Answers (5)

mockaroodev
mockaroodev

Reputation: 2071

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

Upvotes: 22

F&#225;bio Miranda
F&#225;bio Miranda

Reputation: 546

This post can be useful: http://erikonrails.snowedin.net/?p=267

Erik describe how to use "accepts_nested_attributes_for" in the model and <% f.fields_for %> in the view to do the job.

Its detailed description can be found in: http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

Upvotes: 1

Corban Brook
Corban Brook

Reputation: 21378

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!

Upvotes: 2

Cody Caughlan
Cody Caughlan

Reputation: 32758

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.

Upvotes: 2

jmay
jmay

Reputation: 471

You have to do this yourself. Active Record does not cascade save operations in has_many relations after the initial save.

You could automate the process with a before_save callback.

Upvotes: 1

Related Questions