ruby-on-rails-3nested-attributesmass-assignment

Can't mass-assign protected attributes: document


I have two models Employee and Documents which are as follows:

Employee.rb

class Employee < ActiveRecord::Base
  has_one :document #,dependent: :destroy
  attr_accessible :age, :dob, :empNo, :first_name, :gender, :last_name, :middle_name, :document_attributes
  accepts_nested_attributes_for :document
  validates :first_name, presence: true , length: { maximum: 50 }
  validates :empNo, presence: true, uniqueness:{ case_sensitive: false }
  validates_length_of :empNo, :minimum => 5, :maximum => 5

  #before save { |user| user.email = email.downcase }
end

Document.rb

class Document < ActiveRecord::Base
  belongs_to :employee,foreign_key: "empno"
  attr_accessible :idate, :iedate, :insuranceno, :iqamano, :iqedate, :iqidate, :passportno, :pedate, :pidate, :vedate, :vidate, :visano
end

and the controller file is employees_controller.rb(I have only shown new,create,show funcs)

  def show
    @employee = Employee.find(params[:id])
    @document=Document.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @employee }
    end
  end

  # GET /employees/new
  # GET /employees/new.json
  def new
    @employee = Employee.new
    @document= Document.new

    respond_to do |format|
      format.html # new.html.erb
      format.json { render :json=>{:employee=> @employee,:document=>@document}, status: :created, :location=>{:employee=> @employee,:document=>@document} }
    end
  end

  # POST /employees
  # POST /employees.json
  def create
    @employee = Employee.create!(params[:employee])
    @document = Document.create!(params[:document])
    respond_to do |format|
      if @employee.save and @document.save
        format.html { redirect_to @employee, notice: 'Employee was successfully created.' }
        format.json { render :json=>{:employee=> @employee,:document=>@document}, status: :created, location: @employee }
      else
        format.html { render action: "new" }
        format.json { render json: @employee.errors, status: :unprocessable_entity }
      end
    end
  end

When I create a new employee I get the following error

 ActiveModel::MassAssignmentSecurity::Error in EmployeesController#create
 Can't mass-assign protected attributes: document

The requsts parameters are fine as seen below

{"utf8"=>"✓",
 "authenticity_token"=>"vXSnbdi+wlAhR5p8xXvTWhi85+AVZgOZufClx73gc8Q=",
 "employee"=>{"empNo"=>"11111",
 "first_name"=>"Thaha",
 "middle_name"=>"Muhammed",
 "last_name"=>"Hashim",
 "age"=>"25",
 "gender"=>"M",
 "dob(1i)"=>"2014",
 "dob(2i)"=>"7",
 "dob(3i)"=>"18",
 "document"=>{"passportno"=>"bycucde63"}},
 "commit"=>"Create Employee"}

I have gone through nearly all posts on stackoverflow dealing with this issue and mostly the issue is related to

  1. not using attr_accessible
  2. not using accepts_nested_attributes_for
  3. not using :document_attributes

If I change the value of config.active_record.whitelist_attributes to false then the error goes away(There is a warning in developer log about the same) and both the models are created but only attributes of employee model is filled with passed values wheras the attributes of document model is nil.

EDIT #1 If I tried to add :document to attr_accessible then I get the following error

ActiveRecord::AssociationTypeMismatch in EmployeesController#create 

What is that I am doing wrong here?


Solution

  • Understanding Mass Assignment

    Mass Assignment is the name Rails gives to the act of constructing your object with a parameters hash. It is "mass assignment" in that you are assigning multiple values to attributes via a single assignment operator.

    The following snippets perform mass assignment of the name and topic attribute of the Post model:

    Post.new(:name => "John", :topic => "Something")
    
    Post.create(:name => "John", :topic => "Something")
    
    Post.update_attributes(:name => "John", :topic => "Something")
    

    In order for this to work, your model must allow mass assignments for each attribute in the hash you're passing in.

    There are two situations in which this will fail:

    You have an attr_accessible declaration which does not include :name

    You have an attr_protected which does include :name

    It recently became the default that attributes had to be manually white-listed via a attr_accessible in order for mass assignment to succeed. Prior to this, the default was for attributes to be assignable unless they were explicitly black-listed attr_protected or any other attribute was white-listed with attr_acessible.