Rails nested form does not save nested attributes

I have the following user controller:

class UsersController < ApplicationController def index @users = User.all end def new @user = User.new end def create @user = User.new(user_params) @customer = Customer.new if @user.save flash.notice = "User '#{@user.email}' was succefully created." redirect_to user_path(@user) else render 'new' end end def show @user = User.find(params[:id]) end private def user_params params.require(:user).permit(:email, :password, :password_confirmation, customer_attributes: [:id, :company]) end end 

And I have the following user model:

 class User < ActiveRecord::Base has_one :customer accepts_nested_attributes_for :customer, :allow_destroy => true end 

And the following customer model:

 class Customer < ActiveRecord::Base belongs_to :user end 

Finally, here is the form:

 <%= form_for [@user] do |f| %> <% if @user.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2> <ul> <% @user.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= f.label :email %><br> <%= f.text_field :email %> </div> <div class="field"> <%= f.label :password %><br> <%= f.password_field :password %> </div> <div class="field"> <%= f.label :password_confirmation %><br> <%= f.password_field :password_confirmation %> </div> <%= f.fields_for :customers do |company| %> <div class="field"> <%= company.label :company %><br> <%= company.text_field :company %> </div> <% end %> <div class="actions"> <%= f.submit %> </div> <% end %> 

When I submit the form, I see: “Unlisted parameters: clients” in the log, but it seems that I really allow it.

In addition, I want to show the company name for each user in the show and index view. I am not sure how to do this.

I remember using the build method in the past to get something similar to work, but this time I cannot figure it out.

+5
source share
2 answers

Change the code as follows:

 def new @user = User.new @user.build_customer end 

Your form:

 <%= form_for @user do |f| %> // user fields <%= f.fields_for :customer do |customer| %> // customer fields <% end %> <% end %> 

Also, your creation method does not require @customer = Customer.new.

+4
source

In response to @Mandeep answer, give me more information:

  • You need to “create” related objects for your form.
  • You need to handle this according to your model.
  • You need to save the attributes according to the specified association

The way to do this is relatively simple (indicated by Mandeep ). However, the reason may be slightly less obvious:


Build

First you need to create an association. This is vital, primarily because Rails (thanks to building on Ruby) is an object - oriented structure.

Orientation of objects, without going into details, means that everything you do with Rails will be based on objects. In the case of our favorite Rails, this means that each Model is an object .

By virtue of this fact, a nested model paradigm must be built in Rails whenever you want to create such a form. To do this, you need to use the build methods that tell ActiveRecord (Rails < a relational mapmaker object ) that you have another related model / object that you want to fill:

 #app/controllers/users_controller.rb class UsersController < ApplicationController def new @user = User.new #-> initializes "User" object @user.build_customer #-> "builds" the associated object end end 

This gives Rails a set of related data that it can fill with your form (given that you are calling the correct methods)

-

Association

Secondly, you need to consider your relationship. This is important because singular and multiple associations are handled differently during the “build” process.

You are using the has_one , which means you need to use the association names singular (although you can invoke associations no matter what you want):

enter image description here

If you used the has_many association, you will need to use multiple association methods:

enter image description here

This explains the need to use the build_customer method; but it should also give you the right to use the name of the singular association for all the methods necessary for this, namely fields_for and params :

 #app/views/users/new.html.erb <%= form_for @user do |f| %> ... <%= f.fields_for :customer do |c| %> ... <% end %> <%= f.submit %> <% end %> #app/controllers/users_controller.rb class UsersController < ApplicationController def create @user = User.new user_params @user.save end private def user_params params.permit(:user).permit(:user, :params, customer_attributes: [:x. :y]) end end 

-

Save

The above controller code will save the attributes you need.

You should understand that passing nested attributes means that the model you are sending associative data to should be subordinate to your "main" model. This happens with ActiveRecord associations in your models, as discussed at the beginning.

Hope this gives you even more clarity.

+6
source

Source: https://habr.com/ru/post/1201985/


All Articles