Search code examples
ruby-on-railsparametersmass-assignment

using build in has_many relationship in create action results in mass assignment error


I have a mass assignment error I can only fix with UGLY code. I must be doing something wrong. Let me explain:

I my rails application clients have many contacts. The Client page shows a list of contacts belonging to that client. I want to be able to add a new contact to the list. So I pass the client to the contact controller using...

<%= link_to('new contact', new_contact_path(client_id: @client)) %> 

In the ContactsController....

def new
 client=Client.find(params[:client_id])
 @contact=client.contacts.new
end


def create
  @client = Client.find(params[:contact][:client_id])
  @contact= @client.contacts.build(params[:contact])
      if @contact.save
 ...

The 'save' results in an unsurprising error:

Can't mass-assign protected attributes: client_id

because the contact params include the client_id which is not (and should not be) attr_accessible in the contact model

The only way I know how to fix the problem is to set every parameter individually (excluding the client_id) as follows:

@contact= @client.contacts.build(first_name: params[:contact][:first_name], last_name:     params[:contact][:first_name], email: params[:contact][:email])

This approach works but it just all seems wrong. Surely is some more elegant alternative. Any help is appreciated. (yes i am new to rails)


Solution

  • To skip the part to tell you how you should fix your error, I would like to tell you how you should do the coding in the first place :) Correct if I am wrong.

    In Routes.rb you should have put(if not so already):

    resources :client do
        resources : contacts
    end
    

    Then, second in you view file you should put something like this:

    <%= link_to('new contact', new_client_contact_path(@client)) %> 
    

    In that way, you don't have to do anything in your create action, rails will manage all other things. That is the way it is supposed to be done

    Edit:

    just to make it more clear. In new action in your contacts controller you should put:

    user= user.find(params[:user_id])
    #2nd you build a new one
    @contact= user.contacts.build
    

    And in your create action in contacts controller , you should put:

    user = User.find(params[:user_id])
    #2nd you create the contact with arguments in params[:contact ]
    @contact = user.contact.create(params[:contact ])
    response .....