【问题标题】:Rails 5 Nested Form Attributes not SavingRails 5嵌套表单属性不保存
【发布时间】:2017-03-01 17:18:47
【问题描述】:

好的,伙计们,我有一个与配置文件表相关的用户表,我相信我已经完成了我应该做的所有事情来保存嵌套表单属性,但是它们不会保存到数据库中。我已阅读其他帖子,但似乎没有一个适合或解决方案不起作用。需要明确的是,我在基于 Linux 的系统上使用带有 MySQL 的 Rails 5。 我已经在下面包含了相关文件

用户模型

class User < ApplicationRecord
  has_one :profile, inverse_of: :user
  accepts_nested_attributes_for :profile, allow_destroy: true
end

配置文件模型

   class UsersController < ApplicationController
  before_action :set_user, only: [:show, :edit, :update, :destroy]

  # GET /users
  # GET /users.json
  def index
    @users = User.all
  end

  # GET /users/1
  # GET /users/1.json
  def show
  end

  # GET /users/new
  def new
    @user = User.new
    @user.create_profile
    @user.build_profile
  end

  # GET /users/1/edit
  def edit

  end

  # POST /users
  # POST /users.json
  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        format.html { redirect_to @user, notice: 'User was successfully created.' }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /users/1
  # PATCH/PUT /users/1.json
  def update
    respond_to do |format|
      if @user.update(user_params)
        format.html { redirect_to @user, notice: 'User was successfully updated.' }
        format.json { render :show, status: :ok, location: @user }
      else
        format.html { render :edit }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /users/1
  # DELETE /users/1.json
  def destroy
    @user.destroy
    respond_to do |format|
      format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def user_params
      params.require(:user).permit(:username, :password, :user_type_id, profile_attributes: [:id, :user_id, :first_name, :middle_name, :last_name, :phone_number, :cell_number, :email])
    end
end

用户表单部分

<%= 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 |message| %>
            <li><%= message %></li>
          <% end %>
          </ul>
        </div>
      <% end %>

      <div class="field">
        <%= f.label :username %>
        <%= f.text_field :username %>
      </div>

      <div class="field">
        <%= f.label :password %>
        <%= f.text_field :password %>
      </div>

      <div class="field">
        <% if params[:trainer] == "true" %>
        <%= f.label :user_type_id %>
        <%= f.text_field :user_type_id %>
        <% else %>
        Nota trainer
        <% end %>
      </div>
        <h2>Account Profile</h2>
        <%= f.fields_for :profiles do |client_profile| %>
          <%#= client_profile.inspect %>
            <div>
              <%= client_profile.label :first_name %>
              <%= client_profile.text_field :first_name %>
            </div>
            <div>
              <%= client_profile.label :middle_name %>
              <%= client_profile.text_field :middle_name %>
            </div>
            <div>
              <%= client_profile.label :last_name %>
              <%= client_profile.text_field :last_names %>
            </div>
            <div>
              <%= client_profile.label :email %>
              <%= client_profile.text_field :email %>
            </div>
            <div>
              <%= client_profile.label :phone_number %>
              <%= client_profile.text_field :phone_number %>
            </div>
            <div>
              <%= client_profile.label :cell_phone %>
              <%= client_profile.text_field :phone_number %>
            </div>
        <% end %>
      <div class="actions">
        <%= f.submit %>
      </div>
    <% end %>

新视图

New User

    <%= render 'form', user: @user %>

    <%= link_to 'Back', users_path %>

参数调试输出

{
"utf8"=>"✓",
"_method"=>"patch", 
"authenticity_token"=>"oZwa3K5QJRKlWGf176/fOOmrANd07KUyXUJa8Ig9CtEq+OilF73R9CzWVXwE2+K/crSFfm5p3yaeW+u2KSEF7w==",
 "user"=>{
           "username"=>"vitago", 
           "password"=>"[FILTERED]", 
           "profiles"=>{
                         "first_name"=>"John", 
                         "middle_name"=>"B", 
                         "last_names"=>"Doe",            
                         "email"=>"johnbdoe@gmail.com", 
                         "phone_number"=>"1002223333"
                        }
          },
 "commit"=>"Update User",
 "id"=>"1"}

development.log 中的日志输出

   Started PATCH "/users/1" for 192.168.0.31 at 2017-03-02 01:28:22 -0500
    Cannot render console from 192.168.0.31! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
    Processing by UsersController#update as HTML
      Parameters: {
        "utf8"=>"✓",      
     "authenticity_token"=>"GRKhJuTuytcwr4ycCBi0KiFNkmRCstPAnaP0Z8UucWZFp5JdfmosqOvIQ7WpgYUN8yHvEcmMcmYOPLX1iDUwAA==", 
        "user"=>{
        "username"=>"vitago", 
        "password"=>"[FILTERED]", 
        "profiles"=>{
            "first_name"=>"John", 
            "middle_name"=>"B", 
            "last_names"=>"Doe", 
            "email"=>"johnbdoe@gmail.com", 
            "phone_number"=>"1002223333"
         }
    }, 
    "commit"=>"Update User", 
    "id"=>"1"
}
      User Load (0.5ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
    Unpermitted parameter: profiles
       (0.1ms)  BEGIN
       (0.1ms)  COMMIT
    Redirected to http://192.168.0.51:3000/users/1
    Completed 302 Found in 7ms (ActiveRecord: 0.7ms)


    Started GET "/users/1" for 192.168.0.31 at 2017-03-02 01:28:22 -0500
    Cannot render console from 192.168.0.31! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
    Processing by UsersController#show as HTML
      Parameters: {"id"=>"1"}
      User Load (0.6ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
      Rendering users/show.html.erb within layouts/application
      Rendered users/show.html.erb within layouts/application (1.4ms)
    Completed 200 OK in 43ms (Views: 29.8ms | ActiveRecord: 0.6ms)


    Started GET "/users/1/edit" for 192.168.0.31 at 2017-03-02 01:28:24 -0500
    Cannot render console from 192.168.0.31! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
    Processing by UsersController#edit as HTML
      Parameters: {"id"=>"1"}
      User Load (0.5ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
      Rendering users/edit.html.erb within layouts/application
      Rendered users/_form.html.erb (7.1ms)
      Rendered users/edit.html.erb within layouts/application (12.5ms)
    Completed 200 OK in 43ms (Views: 35.6ms | ActiveRecord: 0.5ms)

【问题讨论】:

  • @user.create_profile这行要去掉,@user.build_profile就够了

标签: ruby-on-rails ruby ruby-on-rails-5


【解决方案1】:

:profile 是您的嵌套模型的名称,因此请在您的 user_params 中尝试 profile_attributes

def user_params
  params.require(:user).permit(:username, :password, :user_type_id, profile_attributes: [:id, :first_name, :middle_name, :last_name, :email, :phone_number, :cell_number])
end

您似乎在嵌套的配置文件参数中忘记了:email

表单中的这一行:

<%= f.fields_for :profiles do |client_profile| %>

应该是:

<%= f.fields_for :profile do |client_profile| %>

Userhas_oneprofile,所以配置文件在嵌套形式中应该是单数。

更新:

新建和编辑操作都需要在其中构建一个空配置文件才能显示嵌套表单:

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

# GET /users/1/edit
def edit
  @user.build_profile
end

【讨论】:

  • 不,仍然没有保存数据。
  • 当我将 :profiles 更改为 :profile 时,我最终没有显示任何嵌套属性。向 profile_attributes 添加电子邮件:无论哪种方式都没有影响。
  • hm,可能是因为您没有在 form_for 助手中使用 @user 实例变量:form_for(@user)。这只是一部分,所以我看不到整个画面。我可能弄错了
  • 在我的帖子中添加了新视图
  • @user.profile.build 在控制器的新操作中应该是 @user.build_profile。它与has_many 的语法不同。如果解决了,我会更新我的答案
【解决方案2】:

您需要做的更改很少,@Ren 的回答中已经给出了一些更改,

1) 新操作,@user.create_profile 不需要。

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

2) &lt;%= form_for(user) do |f| %&gt; 应该是 &lt;%= form_for @user do |f| %&gt;

3) &lt;%= f.fields_for :profiles do |client_profile| %&gt; 应该是 &lt;%= f.fields_for :profile do |client_profile| %&gt;

<%= 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 |message| %>
                    <li><%= message %></li>
                    <% end %>
            </ul>
       </div>
    <% end %>

    <div class="field">
    <%= f.label :username %>
    <%= f.text_field :username %>
    </div>

    <div class="field">
    <%= f.label :password %>
    <%= f.text_field :password %>
    </div>

    <div class="field">
    <% if params[:trainer] == "true" %>
    <%= f.label :user_type_id %>
    <%= f.text_field :user_type_id %>
    <% else %>
    Nota trainer
    <% end %>
    </div>
    <h2>Account Profile</h2>
    <%= f.fields_for :profile do |client_profile| %>
        <%#= client_profile.inspect %>
        <div>
            <%= client_profile.label :first_name %>
            <%= client_profile.text_field :first_name %>
        </div>
        <div>
            <%= client_profile.label :middle_name %>
            <%= client_profile.text_field :middle_name %>
        </div>
        <div>
            <%= client_profile.label :last_name %>
            <%= client_profile.text_field :last_names %>
        </div>
        <div>
            <%= client_profile.label :email %>
            <%= client_profile.text_field :email %>
        </div>
        <div>
            <%= client_profile.label :phone_number %>
            <%= client_profile.text_field :phone_number %>
        </div>
        <div>
            <%= client_profile.label :cell_phone %>
            <%= client_profile.text_field :phone_number %>
        </div>
    <% end %>
    <div class="actions">
    <%= f.submit %>
    </div>
<% end %>

【讨论】:

  • @BetaZed Software Solutions,检查了我的答案吗?
  • 这增加了一些额外的,但是添加到控制器中的编辑方法并没有什么不同。无论 @user.build_profile 是否在编辑方法中,它都有效。我添加它是为了安全,但它似乎没有影响。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多