Using accepts_nested_attributes_for + mass assignment protection in Rails
Asked Answered
P

1

6

Say you have this structure:

class House < ActiveRecord::Base
  has_many :rooms
  accepts_nested_attributes_for :rooms
  attr_accessible :rooms_attributes
end

class Room < ActiveRecord::Base 
  has_one :tv
  accepts_nested_attributes_for :tv
  attr_accessible :tv_attributes
end

class Tv 
  belongs_to :user
  attr_accessible :manufacturer
  validates_presence_of :user
end

Notice that Tv's user is not accessible on purpose. So you have a tripple-nested form that allows you to enter house, rooms, and tvs on one page.

Here's the controller's create method:

def create
  @house = House.new(params[:house])

  if @house.save
    # ... standard stuff
  else
    # ... standard stuff
  end
end

Question: How in the world would you populate user_id for each tv (it should come from current_user.id)? What's the good practice?

Here's the catch22 I see in this.

  1. Populate user_ids directly into params hash (they're pretty deeply nested)
    • Save will fail because user_ids are not mass-assignable
  2. Populate user for every tv after #save is finished
    • Save will fail because user_id must be present
    • Even if we bypass the above, tvs will be without ids for a moment of time - sucks

Any decent way to do this?

Pantechnicon answered 14/8, 2009 at 1:22 Comment(1)
Thanks for your question. The 'attr_accessible :rooms_attributes' helped me solve a mass-assigned problem with Rails 2.3'S accepts_nested_attributes_for feature. I was getting an error that read 'WARNING: Can't mass-assign these protected attributes: XXX_attributes'.Chuff
D
2

Anything wrong with this?

def create
  @house = House.new(params[:house])
  @house.rooms.map {|room| room.tv }.each {|tv| tv.user = current_user }
  if @house.save
    # ... standard stuff
  else
    # ... standard stuff
  end
end

I haven't tried this out, but it seems like the objects should be built and accessible at this point, even if not saved.

Duckling answered 14/8, 2009 at 2:19 Comment(2)
You're right, I don't know where my head was when I was asking this.Pantechnicon
It happens to all of us. Glad I could help. BTW - tweeting the URL was a good idea, I'll have to remember to do that myself.Duckling

© 2022 - 2024 — McMap. All rights reserved.