Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using accepts_nested_attributes_for + mass assignment protection in Rails

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?

like image 915
Max Chernyak Avatar asked Aug 14 '09 01:08

Max Chernyak


1 Answers

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.

like image 197
Matt Van Horn Avatar answered Oct 26 '22 18:10

Matt Van Horn