1

好的人,Rails 5的细微差别与Rails 4有很大不同。我现在所做的是每次单击submit按钮在其重新加载的格式中出现错误配置文件用户必须存在配置文件用户不能为空。形式加载罚款包括嵌套模型的形式,可不论什么原因,没有试图救孩子模型以下输出到控制台前保存父模型:Rails 5 - 保存回滚,因为嵌套模型父模型没有被保存在子模型之前

Puma starting in single mode... 
* Version 3.7.0 (ruby 2.2.6-p396), codename: Snowy Sagebrush 
* Min threads: 5, max threads: 5 
* Environment: development 
* Listening on tcp://0.0.0.0:3000 
Use Ctrl-C to stop 
Started POST "/users" for 192.168.0.31 at 2017-03-09 18:51:04 -0500 
Cannot render console from 192.168.0.31! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 
    ActiveRecord::SchemaMigration Load (0.2ms) SELECT `schema_migrations`.* FROM `schema_migrations` 
Processing by UsersController#create as HTML 
    Parameters: {"utf8"=>"✓", "authenticity_token"=>"JPKO+ppAYqwWS8tWeXhEtbUWynXREu9jYlF0KIlyPgUaabHSzjPZocSxCvr/WEm1r6wAQyT1CvA6hNkZWfPD3Q==", "user"=>{"username"=>"test", "password"=>"[FILTERED]", "user_type_id"=>"1", "profile_attributes"=>{"first_name"=>"123", "middle_name"=>"123", "last_name"=>"123", "email"=>"[email protected]", "phone_number"=>"1234567890", "cell_number"=>"1234567890"}}, "commit"=>"Create User"} 
    (0.1ms) BEGIN 
    (0.2ms) ROLLBACK 
    Rendering users/new.html.erb within layouts/application 
    Rendered users/_form.html.erb (112.5ms) 
    Rendered users/new.html.erb within layouts/application (118.7ms) 
Completed 200 OK in 834ms (Views: 780.1ms | ActiveRecord: 2.2ms) 

我也有过其他出现这种关系的问题,我在想,也许我需要重建项目。 这里是所有解决此问题的相关代码:

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

############################################################################### 
### Profile Model 
############################################################################### 
    class Profile < ApplicationRecord 
     belongs_to :user, inverse_of: :profile 
     validates_presence_of :user 
    end 
############################################################################### 
### Users Controller 
############################################################################### 
    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 
     @user.build_profile 
     end 

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

     # GET /users/1/edit 
     def edit 
     @user.build_profile 
     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 View 
############################################################################### 
    <%= 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 %> 
      <!--<li><%= debug f %></li>--> 
      </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, :readonly => true, :value => '2' %> 
     <% else %> 
      <%= f.label :user_type_id %> 
      <%= f.text_field :user_type_id, :readonly => true, :value => '1' %> 
     <% end %> 
     </div> 
     <h2>Account Profile</h2> 
     <%= f.fields_for :profile do |profile| %> 
      <%#= profile.inspect %> 
      <div> 
       <%= profile.label :first_name %> 
       <%= profile.text_field :first_name %> 
      </div> 
      <div> 
       <%= profile.label :middle_name %> 
       <%= profile.text_field :middle_name %> 
      </div> 
      <div> 
       <%= profile.label :last_name %> 
       <%= profile.text_field :last_name %> 
      </div> 
      <div> 
       <%= profile.label :email %> 
       <%= profile.text_field :email %> 
      </div> 
      <div> 
       <%= profile.label :phone_number %> 
       <%= profile.telephone_field :phone_number %> 
      </div> 
      <div> 
       <%= profile.label :cell_phone %> 
       <%= profile.telephone_field :cell_number %> 
      </div> 
     <% end %> 
     <div class="actions"> 
     <%= f.submit %> 
     </div> 
     <%= debug params %> 
     <%= debug user %> 
     <%= debug user.profile %> 
    <% end %> 
+0

似乎没有解决方案,因为没有人提供帮助,我会认为它是一个错误。当系统让我的时候,我会为此付出代价。 –

回答

1

好吧我在另一个问题上重新提出了这个问题,我终于找到了答案。所以我从那里粘贴我的回答,以防有人以我在这里问这个问题的同样方式搜索问题。

好吧,我正在回答我自己的问题,因为我知道很多人都在为此付出努力,实际上我已经有了答案,而不是对文档的模糊回应。

首先,我们将在这个例子中使用一对一的关系。当你创建你的关系,你需要确保父模型具有以下

  1. inverse_of:
  2. 自动保存:真
  3. accepts_nested_attributes_for:模型,allow_destroy:真

这里是用户模型然后我会解释,

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

在Rails 5中你需要inverse_of:因为这告诉Rails通过外键存在关系,并且在保存表单数据时需要在嵌套模型上设置它。现在,如果您要离开自动保存:真正的从关系线中关闭,您将保留user_id不保存到配置文件表和其他列,除非您已验证关闭,然后它不会错误它将只保存它,而不需要user_id。这里发生的是autosave:true确保先保存用户记录,以便user_id存储在配置文件模型的嵌套属性中。 简而言之,为什么user_id没有穿过孩子,而是回滚而不是提交。 另外最后一个问题是有一些帖子告诉你在你的控制器中你应该添加编辑路线@ user.build_profile就像我在我的帖子。不这样做,他们是完全错误的,评估

Started GET "https://stackoverflow.com/users/1/edit" for 192.168.0.31 at 2017-03-12 22:38:17 -0400 
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.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 
    Profile Load (0.5ms) SELECT `profiles`.* FROM `profiles` WHERE `profiles`.`user_id` = 1 LIMIT 1 
    (0.1ms) BEGIN 
    SQL (0.5ms) UPDATE `profiles` SET `user_id` = NULL, `updated_at` = '2017-03-13 02:38:17' WHERE `profiles`.`id` = 1 
    (59.5ms) COMMIT 
    Rendering users/edit.html.erb within layouts/application 
    Rendered users/_form.html.erb (44.8ms) 
    Rendered users/edit.html.erb within layouts/application (50.2ms) 
Completed 200 OK in 174ms (Views: 98.6ms | ActiveRecord: 61.1ms) 

控制台输出它的结果后,如果你看它是重建从头开始的形象和重置USER_ID为null,你是当前用户相匹配的记录编辑。所以要非常小心,因为我看到大量的帖子提出这个建议,并且花费我数天的研究来寻找解决方案!

0

我有一个类似的问题(没有嵌套属性保存)。

在控制器中,我将@user.build_profile更改为@user.profile.build(params[:profile])并解决了问题。

+0

我会很快尝试,这是有道理的。如果我可能会问,你怎么解决这个问题?我一直在Google上搜索几天! –

+0

不会导致**未初始化的常量User :: Profile ** –

+0

对不起,有一个typeo。因此,不用'@ user.profile.build(params [:profile])',你可以使用'@ user.profiles.build(params [:profile])''。 从http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html 明白了,我知道这是不一定的'has_one' <==>'belongs_to'关系的情况下有一个'。 profiles'方法,它返回所有用户的配置文件(因为它只是一个has_one),因为它通常是表之间'has_many' <==>'belongs_to'键,但它以某种方式工作。 – bencekiss