Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

attr_accessor not accessible through accepts_nested_attributes_for

#5939

I'm on rails v2.3.9 and I'm seeing strange behaviour (to me anyways) in accepts_nested_attributes_for. In a certain circumstance the attr_accessor is not available on the nested model.

Tracker 
  has_many :samples
  accepts_nested_attributes_for :samples, :allow_destroy => true

Sample
  attr_accessor :current_user
  belongs_to :tracker

  after_destroy do |sample|
    puts sample.current_user
  end

On the console...

>>t = Tracker.first

>>tracker_attributes = {:note=>"a note",:samples_attributes=>{"1"=>{:sample_note=>"new sample", :current_user=>"console user", :_destroy=>false}}}

>>t.update_attributes(tracker_attributes)
=> '' # no output because _destroy is set to false

>>tracker_attributes = {:note=>"a note",:samples_attributes=>{"1"=>{:id=>1, :sample_note=>"new sample", :current_user=>"console user", :_destroy=>true}}

>>t.update_attributes(tracker_attributes)
=> 'console user'

In the above example everything works as expected and the sample is deleted. If I reload the Tracker after the Sample is created then current_user is not available.

>>t = Tracker.first

>>tracker_attributes = {:note=>"a note",:samples_attributes=>{"1"=>{:sample_note=>"new sample", :current_user=>"console user", :_destroy=>false}}}

>>t.update_attributes(tracker_attributes)
=> 'console user'

>>t = Tracker.first

>>tracker_attributes = {:note=>"a note",:samples_attributes=>{"1"=>{:id=>1, :sample_note=>"new sample", :current_user=>"console user", :_destroy=>true}}

>>t.update_attributes(tracker_attributes)
=> '' # console_user is expected but nil was printed

I'm reloading the Tracker to simulate what I see in a controller. In a controller action I would find the Tracker and then update the attributes. I hope I'm making sense.

Reported by Chris Anderson · November 9th, 2010 @ 07:17 PM

State: resolved
Milestone: 3.x
Assigned to: José Valim José Valim
Importance: Low

Activity

  1. Neeraj Singh
    Neeraj Singh
    • Importance changed from to Low

    I followed what you have shown in console. I am still not sure what is the issue? Can you elaborate on what you mean by "the attr_accessor is not available on the nested model." ?

    November 10th, 2010 @ 03:08 PM

  2. Chris Anderson
    Chris Anderson

    Sure. When "accepts_nested_attributes_for :allow_destroy => true" is set, if I set the :_destroy field of a nested model record in my form to true then it will delete the child records associated with the model. This works as expected and the destroy callbacks are called.

    In that same form if I set a field that's also an attr_accessor for the nested model, in this case :current_user, :current_user is not available in the destroy callbacks. It is available in the other callbacks, however.

    Basically, I'm trying to use :current_user for an audit log to track who did what and when I delete child records in this fashion :current_user is not available to put the person's name into the log.

    In the examples above I've tried to show that it will work if the parent record is not reloaded, but if it is (like when a form is submitted you fetch the parent record again) then it fails to retain the attr_accessor so it can be called in a destroy callback.

    November 10th, 2010 @ 03:36 PM

  3. Neeraj Singh
    Neeraj Singh

    @cpanderson thanks for the quick reply.

    I updated the original ticket to better reflect the expected vs actual values. Can you confirm that my editing rightly reflects your issue.

    Thankss

    November 10th, 2010 @ 04:22 PM

  4. Chris Anderson
    Chris Anderson

    Thanks, Neeraj.

    Basically, that would work except that :current_user won't be outputted in the first case because :_destroy => false. And in the second case it doesn't seem to return nil...it returns nothing at all, like it's being ignored entirely.

    November 10th, 2010 @ 04:29 PM

  5. Chris Anderson
    Chris Anderson

    If I manually add a virtual attribute via getter and setter methods instead of using attr_accessor like this...

    def current_user=(user)
      @current_user = user
    end
    
    def current_user
      @current_user || "this was not set"
    end
    

    ...then it will return "this was not set". In all other cases (save, update) the @current_user is returned properly.

    PS. How do I add syntax highlighting like I see in other posts for ruby?

    November 10th, 2010 @ 04:44 PM

  6. Neeraj Singh
    Neeraj Singh
    • State changed from new to open
    • Milestone set to 2.x
    • Tag set to 2.3.x, patched
    • Assigned user set to José Valim

    Attached is a code fix with test.

    Thanks a ton to Chris for helping me understand the issue.

    I will investigate if it is an issue with Rails3 too?

    November 10th, 2010 @ 08:34 PM

  7. Chris Anderson
    Chris Anderson

    I haven't migrated to v3 yet so I'll leave that up to you guys.

    This is my first foray into submitting a bug for rails. You have attached a patch. What's the best way to handle it?

    Thanks!

    Chris

    November 10th, 2010 @ 08:38 PM

  8. Neeraj Singh
    Neeraj Singh

    @Chrirs First of all thanks for submitting the issue.

    As you can see I have assigned the ticket to José Valim. He will take a look at the attached patch and will provide feedback when he gets time.

    November 10th, 2010 @ 08:54 PM

  9. Neeraj Singh
    Neeraj Singh

    This issue is present in Rails 3 too.

    If the patch looks okay then I can create a patch for Rails 3 too?

    November 11th, 2010 @ 03:53 PM

  10. Chris Anderson
    Chris Anderson

    This patch seems to work for me. Thank you!

    November 11th, 2010 @ 03:58 PM

  11. José Valim
  12. Neeraj Singh
  13. Neeraj Singh
    Neeraj Singh
    • Milestone changed from 2.x to 3.x

    November 16th, 2010 @ 06:52 PM

  14. Repository
    Repository
    • State changed from open to resolved

    (from [66212f69acc3d51af10ff76a18ff4c0bfa305ea5]) If a nested_attribute is being marked for destruction and at the same time an attr_accessor value is being assigned then the value being assigned is being ignored. This patch is a fix for that issue.

    [#5939 attr_accessor not accessible through accepts_nested_attributes_for state:resolved]

    Signed-off-by: José Valim jose.valim@gmail.com
    https://github.com/rails/rails/commit/66212f69acc3d51af10ff76a18ff4...

    November 24th, 2010 @ 09:09 PM

  15. Repository
    Repository

    (from [1e2981fa6bd67089e4cae35d40fd1044f29cb6a6]) If a nested_attribute is being marked for destruction and at the same time an attr_accessor value is being assigned then the value being assigned is being ignored. This patch is a fix for that issue.

    [#5939 attr_accessor not accessible through accepts_nested_attributes_for state:resolved]

    Signed-off-by: José Valim jose.valim@gmail.com
    https://github.com/rails/rails/commit/1e2981fa6bd67089e4cae35d40fd1...

    November 24th, 2010 @ 09:10 PM

  16. Aaron Patterson
    Aaron Patterson

    @Neeraj The patch that you wrote is causing warnings on master. Can you possibly rewrite this test to not use global variables?

    https://github.com/rails/rails/commit/66212f69

    December 1st, 2010 @ 01:56 AM

  17. joson
    joson

    A Replica Breitling is a timepiece of high quality and functionality and you will have all the class, prestige and luxury of a wealthy, successful individual. By choosing from our selection of luxury Replica Watches , you can improve your self-esteem and feel confident to enter new circles of business associates and friends. These Rolex Replicas will surely enhance your style and only you will know the watch you wear did not cost you $1,000's of dollars.

    April 29th, 2011 @ 09:13 AM