This project is archived and is in readonly mode.
accepts_nested_attributes_for and attr_accessor
Reported by ryanza | June 23rd, 2010 @ 11:18 AM
I have a model that has one attr_accessor, When that gets updated through a nested_attributes form, it does not pick up the change to the attr_accessor, and does not run any of the callbacks.
I have to edit another attribute that is actually part of the model, for the callbacks to occur.
For example:
class Resource < ActiveRecord::Base
# ...
has_many :items
accepts_nested_attributes_for :items, :allow_destroy => true
end
class Item < ActiveRecord::Base
belongs_to :resource
before_validation :clear_if_available
attr_accessor :unavailable
def clear_if_available
if @unavailable == 'yes'
# ...
end
end
end
# Resource.rb
=> r = Resource.new
#<Resource id: 1, quantity: 1, maximum_capacity: 10, name: "Lolcat", supplier_id: 1, created_at: "2010-06-22 15:09:57", updated_at: "2010-06-22 15:09:57", category: "other">
=> Item.first
#<Item id: 1, name: "Lolcat Item", resource_id: 1, out_from: nil, out_to: nil, created_at: "2010-06-22 15:09:57", updated_at: "2010-06-23 09:30:36", mobile_number: nil, email: nil, link_id: 1, points: 0, unavailable: false>
=> r.update_attributes(:items_attributes => { :id => 1, :name => "Lolcat changed, :unavailable => 'yes' })
true # This does the callbacks and does my update
=> r.update_attributes(:items_attributes => { :id => 1, :unavailable => 'yes' })
true # This ignores my update to unavailable and does nothing
This used to work in Rails 2.3.5 now not working in Rails 2.3.8?
Comments and changes to this ticket
-
Neeraj Singh June 26th, 2010 @ 05:22 AM
If I understand you correctly then attribute "unavailable" is not a column on Item table. In that case r.update_attributes(:items_attributes => { :id => 1, :unavailable => 'yes' }) has nothing to do.
Am I missing something here?
-
Brad Crawford July 7th, 2010 @ 08:21 AM
- Importance changed from to Low
You are missing the fact that in 2.3.5, this worked. :)
-
Brad Crawford July 7th, 2010 @ 08:31 AM
Ryanza, I am having the same issue but after creating a blank 2.3.8 project it no longer occurs. I am thinking that it is probably a gem/plugin issue. I will try and track it down and get back to you.
-
ryanza July 7th, 2010 @ 08:45 AM
Neeraj Singh,
Its not firing off any of the hooks in the Item model, where it used to in 2.3.5 (on update_attributes and saves). I do understand that the way it is now (2.3.8) should actually be the correct response (do nothing as nothing is being modified), but it is breaking my old functionality, is there a workaround? :)
Brad Crawford,
I saw alot of code was changed/refactored in the accepts_nested_attributes_for method, I haven't had enough time to actually dig through it, I'll pull out a diff tonight and see if i can spot anything.
Ill try test this in a new Rails 2.3.8 project; makes no sense that it would work?
Thanks :)
-
Neeraj Singh July 7th, 2010 @ 11:18 AM
@ryanza can you show us full implementation of method clear_if_available?
-
ryanza July 7th, 2010 @ 11:21 AM
Sure:
def clear_dates_if_available if self.unavailable == false || !self.book_out_expired? self.out_from, self.out_to = nil, nil end end
-
Brad Crawford July 7th, 2010 @ 11:42 AM
Ok I might have spoken too soon, it doesn't actually work for a blank 2.3.8 app. I haven't looked into the code but as you said, none of the callbacks are being executed on the nested model when update_attributes is called on the parent after setting an attr_accessor attribute on the nested model. It is not dirty I guess. Any ideas for a workaround? 2.3.8 is a no go until I find one.
-
ryanza July 7th, 2010 @ 12:03 PM
I thought it had to do with dirty attributes, so i tried to fake it by writing my own dirty methods for the attr_accessor, and had no luck there either.. Hopefully some sort of solution is figured out for this, as its not REALLY a bug..
-
ryanza July 7th, 2010 @ 12:37 PM
Maybe "accepts_nested_attributes_for :items, :ignore_dirty => true" or something similar?
-
Neeraj Singh July 7th, 2010 @ 12:48 PM
Is it true that in the example that is mentioned at the very top you are changing :unavailable from false to 'yes'; from boolean to string?
-
Neeraj Singh July 16th, 2010 @ 04:19 AM
Not able to reproduce the problem in rails edge. I am getting the callbacks.
Here is what I did
ActiveRecord::Schema.define(:version => 20100716030954) do create_table "questions", :force => true do |t| t.text "name" t.integer "survey_id" end create_table "surveys", :force => true do |t| t.string "name" end end class Question < ActiveRecord::Base belongs_to :survey before_validation :doit def doit puts 'done' * 20 end attr_accessor :sex end class Survey < ActiveRecord::Base has_many :questions, :dependent => :destroy accepts_nested_attributes_for :questions, :allow_destroy => true validates_presence_of :name def self.lab survey = Survey.create!(:name => "Current Trend in Programming") question = survey.questions.create!(:name => "Java", :sex => 'a') survey.update_attributes({:name => 'hello', :questions_attributes => [{:id => question.id, :sex => 'b' }]}) end end
-
Andreas Mayer July 26th, 2010 @ 05:17 PM
Solved it using
class TutorialStep < ActiveRecord::Base belongs_to :tutorial attr_accessor :download_remove ... def download_remove=(remove) self.download = nil if remove == '1' end end
which doesn't require a callback and solves the dirty issue because setting download_remove changes download and makes the record dirty (because the download shall be removed)
-
matthew.willhite (at gmail) October 29th, 2010 @ 07:02 PM
I am having the same issue as the original post.
# page.rb class Page < ActiveRecord::Base has_many :page_elements, :dependent => :destroy accepts_nested_attributes_for :page_elements, :allow_destroy => true end # page_element.rb class PageElement < ActiveRecord::Base belongs_to :page belongs_to :media, :polymorphic => true attr_accessor :media_attributes after_update :update_media def update_media self.media.update_attributes(media_attributes) end end
Page.find(2).update_attributes(:page_elements_attributes => [{ :id=>3, :scale => 2, :media_attributes => { :source => "iphone"} }])
(This will trigger the page element callbacks because an actual (non-virtual) attribute is being modified)
Page.find(2).update_attributes(:page_elements_attributes => [{ :id=>3, :media_attributes => { :source => "test15"} }])
(This will not trigger the page element callbacks because only the virtual attribute is being modified)
Is this the intended behavior? If not, I think this ticket needs to be reopened.
Using Rails 3.0.1, Ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-darwin10.4.0]
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>