Search code examples
ruby-on-railsactiverecordnested-attributesmass-assignment

how to avoid mass assignment error with has_many :through relationship


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!


Solution

  • 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.