0

I am trying to do an update_attributes of a nested model and keep running into a mass assignment error. Here are my models:

class Lineup < ActiveRecord::Base

  belongs_to :user
  has_many :piece_lineups
  has_many :pieces, through: :piece_lineups

  accepts_nested_attributes_for :piece_lineups

end

class Piece < ActiveRecord::Base
  attr_accessible :cost, :description, :name, :category

  has_many :piece_lineups
  has_many :lineups, through: :piece_lineups

end

class PieceLineup < ActiveRecord::Base
  attr_accessible :piece

  belongs_to :piece
  belongs_to :lineup

end

User has_one lineup by the way. So I thought that by adding accepts_nested_attributes_for to the lineup model that it would work but it is not. Here's my form:

  - @lineup.piece_lineups.build(:piece => piece)
  = form_for(@lineup) do |f|
    = f.fields_for :piece_lineups do |piece_lineup|
      = piece_lineup.hidden_field(:piece_id, :value => piece.id)
    = f.submit

and my Lineup controller action:

  def update
    @lineup = current_user.lineup
    @lineup.update_attributes(params[:lineup])

and finally, the error:

Can't mass-assign protected attributes: piece_lineups_attributes

What am i missing here? Thanks!

Matthew Berman
  • 8,481
  • 10
  • 49
  • 98

2 Answers2

3

accepts_nested_attributes_for creates an attribute writer -- in your case, piece_lineups_attributes= -- for passing attributes to another model. So, you need to add attr_accessible :piece_lineups_attributes to your Lineup model to make it mass-assignable.

UPDATE

There is a better way of going about this.

If you add attr_accessible :piece_ids to your Lineup model, then change your view to

= form_for(@lineup) do |f|
  = f.hidden_field(:piece_ids, :value => piece.id)
  = f.submit

You don't need nested attributes at all.

Nick Colgan
  • 5,488
  • 25
  • 36
-1

Mass Assignment usually means passing attributes into the call that creates an object as part of an attributes hash. So add piece_lineup's fields to your list of attr_accessors for that model, OR try this:

@lineup = current_user.lineup
@lineup.piece_id = params[:piece_id]
@lineup.save

Also see:

http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html

Anil
  • 3,899
  • 1
  • 20
  • 28
  • can you clarify what you mean by 'add piece_lineup's fields to your list of attr_accessors' ? thanks – Matthew Berman Jun 21 '12 at 03:38
  • also, if I do the non-mass assign suggestion you gave (the first suggestion), do I still need to do - @lineup.piece_lineups.build(:piece => piece) before the form? – Matthew Berman Jun 21 '12 at 03:39
  • @MatthewBerman Can you post your params hash so that I can be more specific. – Anil Jun 21 '12 at 04:13
  • "lineup"=>{"piece_lineups_attributes"=>{"0"=>{"piece_id"=>"1", "id"=>"4"}, "1"=>{"piece_id"=>"1"}}}, "commit"=>"Update Lineup", "action"=>"update", "controller"=>"lineups", "id"=>"2"} – Matthew Berman Jun 21 '12 at 04:19