Can't mass-assign protected attributes for creating a has_many nested model with Devise

社会主义新天地 提交于 2019-12-04 03:31:37

first, you have a typo :

attr_accessible :locker_attributes

should be plural :

attr_accessible :lockers_attributes

then, the standard way to use nested_attributes is :

<%= form_for @user do |f| %>
  <%# fields_for will iterate over all user.lockers and 
      build fields for each one of them using the block below,
      with html name attributes like user[lockers_attributes][0][name].
      it will also generate a hidden field user[lockers_attributes][0][id]
      if the locker is already persisted, which allows nested_attributes
      to know if the locker already exists of if it must create a new one
  %>
  <% f.fields_for :lockers do |locker_fields| %>
    <%= locker_fields.label      :name %>
    <%= locker_fields.text_field :name %>
  <% end %>
<% end %>

and in you controller :

def new
  @user = User.new
  @user.lockers.build
end

def create
  # no need to use build here : params[:user] contains a
  # :lockers_attributes key, which has an array of lockers attributes as value ;
  # it gets assigned to the user using user.lockers_attributes=, 
  # a method created by nested_attributes
  @user = User.new( params[:user] )
end

as a side note, you can avoid building a new locker for new users in controller in different ways:

  • create a factory method on User, or override new, or use an after_initialize callback to ensure every new user instantiated gets a locker builded automatically

  • pass a specific object to fields_for :

    <% f.fields_for :lockers, f.object.lockers.new do |new_locker_fields| %>
    

Someone helped me figure out the solution in a more "Rails 4'y" way with strong attributes & how to override Devise's sign_up_params (to catch all the data coming from my signup form).

  def sign_up_params
    params.require(:user).permit(:username, :email, :password, :lockers_attributes)
 end

Gemfile addition: gem 'strong_parameters'

Commenting out the attr_accessible statement in my user.rb file, since apparently strong parameters eliminate the need for attr_accessible declarations.

 # attr_accessible :username, :email, :password, :password_confirmation, :lockers

And the/a correct way of building a Locker before submitting the form: at the beginning of the nested form:

<%= l.input :name, :required => true, label: "Locker name", :placeholder => "Name your first locker" %>

Thanks again for all your help. I know a question like this is difficult to answer without seeing the whole codebase.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!