Search code examples
ruby-on-railsruby-on-rails-4has-and-belongs-to-manystrong-parameters

How to cleanly update a list of HABTM associations in Rails 4?


I'm trying to update a User record with the list of associated Addresses, connected through the has and belongs to many association.

The request body I'm sending through javascript is:

{"id":10,"name":"John Smith", "address_ids":[4,8]}

This is what I'm getting in the Rails server log:

Started PUT "/api/users/10" for 127.0.0.1 at 2013-10-03 16:30:43 +0200

Processing by Api::UsersController#update as HTML

Parameters: {"id"=>"10", "name"=>"John Smith", "address_ids"=>[4, 8], "user"=>{"id"=>"10", "name"=>"John Smith"}}

The thing to notice above is the address_ids array is not making it into the user hash according to the log.

In the controller i'm using strong parameters and updating the User like so:

attributes = params.require(:user).permit(:id, :name, {:address_ids => []}) 
@user.update_attributes(attributes)

The problem is the attributes don't contain the address_ids at the point of update so the associated records are not getting updated.

Temporary Solution

I've worked around the issue manually assigning the address_ids key to the attributes after they come back from the strong parameters check like so:

attributes = params.require(:user).permit(:id, :name, {:address_ids => []})
if params.has_key?(:address_ids)   
  attributes[:address_ids] = params[:address_ids] 
end
@user.update_attributes(attributes)

This works fine but doesn't seem to me this is how it is supposed to work? Why are the adderss_ids not getting auto assigned? How can this be implemented in a clear way?


Solution

  • If you want the addresses saved with the User you need to ensure your client side code sends the address_ids parameters as follows:

    Parameters: {"user"=>{"id"=>"10", "name"=>"John Smith", "address_ids"=>["4", "8"]}}
    

    The input field name attribute will be something like:

    <input name="user[address_ids][]">
    

    I also noticed you seem to have your user attributes repeated in your parameters so you may want to carefully review how your client code is generating the request.