Search code examples
ruby-on-railsruby-on-rails-4devisenested-formsstrong-parameters

Unpermitted params when creating a devise user with nested attributes


I'm currently trying to create a devise user with some nested attributes. Each User has_many :companies and also accepts_nested_attributes_for :companies. When a user is added to the system by an admin, I want to automatically create a corresponding Company and get some of its basic information right in the user registration form. This means that I'm nesting some Company fields in form.

The problem is that, while I'm able to create a user just fine, the nested company is rejected with the error.

Unpermitted parameter: company

Below is my code

application_controller.rb note: companies_params are just in there to see if that was needed (I don't actually know if they're necessary)

before_action :configure_permitted_parameters, if: :devise_controller?

protected

    def configure_permitted_parameters
            devise_parameter_sanitizer.for(:account_update) {|u|
                    u.permit(:password, :password_confirmation, :current_password, companies_attributes: [:id, :name, :street, :city, :state, :zip, :_destroy])}
            devise_parameter_sanitizer.for(:sign_up) {|u|
                    u.permit(:password, :password_confirmation, :current_password, companies_attributes: [:id, :name, :street, :city, :state, :zip, :_destroy])}
    end

users_controller.rb

def new
    @user=User.new
    @[email protected]
end

def create
    @user = User.new(user_params)
    if @user.save
        redirect_to users_admin_path(@user), notice: "User successfuly created!"
    else
        redirect_to welcome_index_path
    end
end

private

def user_params
    params.require(:user).permit(:id, :email, :role, :password, :password_confirmation, companies_attributes: [:id, :name, :street, :city, :state, :zip, :_destroy])
end

_form.html.erb

<%= simple_form_for @user, url: url_for(action: 'create', controller: 'users') do |f| %>
    <fieldset>
        <ol>

            <li class="required">
                <%= f.label :email %>
                <%= f.email_field :email, size: 40 %>
            </li>
            <li class="required">
                <%= f.label :password %>
                <%= f.password_field :password, size: 40 %>
            </li>
            <li class="required">
                <%= f.label :password_confirmation, "Confirm Password" %>
                <%= f.password_field :password_confirmation, size: 40 %>
            </li>

        </ol>
        <%= f.simple_fields_for @company do |company| %>
            <div class="field">
                <%= company.input :name, label: "Name" %>
            </div>
        <% end %>
        <%= f.submit "Create Account" %>
    </fieldset>
<% end %>

Any ideas would be helpful.


Solution

  • Objects

    To give you some context, you have to remember that when you use form_for, it's aim is to build a single object (in this case, @user).

    When you use f.fields_for, you're invoking nested attributes of this object.

    Thus, you have to invoke fields_for as a part of the parent object. Your passing @company will not work as you need; you need to invoke a nested element of the parent object, which is why only the following work:

    <%= f.fields_for :companies ... %>
    <%= f.fields_for @user.companies .... %>
    

    This, of course, has to accompany the build command - to construct the nested object in the controller, which you've done already...

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

    --

    I'll delete this answer if it's too broad - I felt it proper to clarify the situation for anyone who might find this question.