使用嵌套表单创建用户时的Rails回滚 [英] Rails rollback when creating user with nested forms

查看:57
本文介绍了使用嵌套表单创建用户时的Rails回滚的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试将用户添加到数据库时,我得到了回滚,但我不确定为什么.

I'm getting a rollback when trying to add a user to my DB and I'm not sure why.

我有三种型号: company.rb

class Company < ActiveRecord::Base
 acts_as_paranoid

 has_many :locations, dependent: :destroy
 has_many :users, dependent: :destroy
 has_many :tests, through: :locations
 has_many :reports, dependent: :destroy

 accepts_nested_attributes_for :locations, :users

 validates_presence_of :name
end

** user.rb **

** user.rb **

class User < ActiveRecord::Base
 acts_as_paranoid

 devise :database_authenticatable,
      :recoverable,
      :rememberable,
      :trackable,
      :validatable,
      :registerable

 belongs_to :company
 has_and_belongs_to_many :roles
end

** location.rb **

** location.rb **

class Location < ActiveRecord::Base
 acts_as_paranoid

 belongs_to :company
 has_many :network_hosts, dependent: :destroy
 has_many :tests, dependent: :destroy
 has_many :commands, dependent: :destroy

 validates_presence_of :company, :identifier, :name
 validates_uniqueness_of :identifier

 delegate :security_percentage, to: :last_test, allow_nil: true

 after_initialize :generate_identifier, if: -> { self.identifier.blank? }

 def generate_identifier
  self.identifier = SecureRandom.uuid.delete("-")
end

因此,当用户想要注册时,他们需要输入公司,位置和用户信息,这由我的company_controller.rb

So, when a user wants to signup they need to enter company, location, and user information, which is controlled by my company_controller.rb

** company_controller.rb **

** company_controller.rb **

class CompanyController < ApplicationController
 def new
  @company = Company.new
  1.times { @company.locations.build }
  1.times { @company.users.build }
 end

 def create
  @company = Company.new(company_params)
  if @company.save
   redirect_to root_url
  else
   render :new
  end
 end

 private

  def company_params
   params.require(:company).permit(:name, locations_attributes: [:name], users_attributes: [:first_name, :last_name, :full_name, :email, :password, :password_confirmation])
  end
end

该表单使用具有嵌套属性的标准form_for,这样,当用户单击提交"按钮时,我希望可以一​​次完成所有操作

The form is using the standard form_for with nested attributes so that I can hopefully make everything in one shot when the user clicks the submit button

** company/new.html.erb **

** company/new.html.erb **

<%= form_for @company, :url => url_for( :controller => 'company', :action => 'new' ) do |f| %>
  <div class="form-group">
    <%= f.label "Company Name" %>
    <%= f.text_field :name, class: "form-control", placeholder: "ACME Inc."  %>

    <%= f.fields_for :locations do | location_builder | %>
      <%= location_builder.label "Location Name" %>
      <%= location_builder.text_field :name, class: "form-control", placeholder: "Main Building" %>

    <% end %>
  </div>

  <div class="form-group">
    <%= f.fields_for :users do | user_builder | %>
      <%= user_builder.label "First Name" %>
      <%= user_builder.text_field :first_name, class: "form-control", placeholder: "John" %>

      <%= user_builder.label "Last Name" %>
      <%= user_builder.text_field :last_name, class: "form-control", placeholder: "Smith" %>

      <%= user_builder.label "Full Name" %>
      <%= user_builder.text_field :full_name, class: "form-control", placeholder: "John Smith" %>

      <%= user_builder.label "Email" %>
      <%= user_builder.email_field :email, class: "form-control", placeholder: "john@acme.com" %>

      <%= user_builder.label "Password" %>
      <%= user_builder.password_field :password, class: "form-control" %>

      <%= user_builder.label "Confirm Password" %>
      <%= user_builder.password_field :password_confirmation, class: "form-control" %>
    <% end %>
  </div>

  <%= f.submit "Submit", class: "btn btn-large btn-success" %>
<% end %>

但是,我在日志中回滚了这并没有发生,也无法弄清原因.

However, I'm getting a rollback in the logs that this isn't happening and can't figure out why.

Started POST "/signup" for 127.0.0.1 at 2015-08-07 13:49:22 -0400
Processing by CompanyController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"2OHwJ9UfEbfkZHjLdm9BfOd7jlRdvoEz0L4NRJCKl64=", "company"=>{"name"=>"ACME Brick", "locations_attributes"=>{"0"=>{"name"=>"Main House"}}, "users_attributes"=>{"0"=>{"first_name"=>"Testin", "last_name"=>"User", "full_name"=>"Test User", "email"=>"test@test.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}}}, "commit"=>"Submit"}
  User Load (0.8ms)  SELECT  "users".* FROM "users"  WHERE "users"."deleted_at" IS NULL AND "users"."id" = 7  ORDER BY "users"."id" ASC LIMIT 1
  Role Load (0.3ms)  SELECT "roles".* FROM "roles" INNER JOIN "roles_users" ON "roles"."id" = "roles_users"."role_id" WHERE "roles"."deleted_at" IS NULL AND "roles_users"."user_id" = $1  [["user_id", 7]]
   (0.1ms)  BEGIN
  Location Exists (0.3ms)  SELECT  1 AS one FROM "locations"  WHERE "locations"."identifier" = '3b7febb35ea740488788d43fcc5e989c' LIMIT 1
  User Exists (0.3ms)  SELECT  1 AS one FROM "users"  WHERE "users"."email" = 'test@test.com' LIMIT 1
   (0.1ms)  ROLLBACK
  Rendered company/new.html.erb within layouts/application (5.0ms)
Completed 200 OK in 108ms (Views: 32.2ms | ActiveRecord: 1.9ms | Solr: 0.0ms)

**公司表格**

class CreateCompanies < ActiveRecord::Migration
  def change
    create_table :companies do |t|
      t.string :name

      t.timestamps
    end
  end
end

**位置表**

class CreateLocations < ActiveRecord::Migration
  def change
    create_table :locations do |t|
      t.belongs_to :company, index: true
      t.string :identifier
      t.string :name

      t.timestamps
    end
  end
end

**用户表**

class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table(:users) do |t|

      t.belongs_to :company, index: true
      
      t.string :username
      t.string :first_name
      t.string :last_name
      t.string :full_name

      t.string :time_zone, :default => "Central Time (US & Canada)"

      t.string :avatar_file_name
      t.string :avatar_content_type
      t.integer :avatar_file_size
      t.datetime :avatar_updated_at

      ## Database authenticatable
      t.string :email,              :null => false, :default => ""
      t.string :phone_number
      t.string :encrypted_password, :null => false, :default => ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, :default => 0
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Token authenticatable
      t.string :authentication_token

      t.timestamps
    end

    add_index :users, :email,                :unique => true
    add_index :users, :reset_password_token, :unique => true

    create_table :roles_users, :id => false do |t|
      t.references :role, :user
    end
  end

  def self.down
    drop_table :users
    drop_table :roles_users
  end
end

**来自日志的错误**

** The error from logs **

Started POST "/signup" for 127.0.0.1 at 2015-08-07 18:12:54 -0400
Processing by CompanyController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"aAc83zKKlV4w1i2GhTqTo3ehtXP+tPvYbBBRq1ccYzA=", "company"=>{"name"=>"Test Co.", "locations_attributes"=>{"0"=>{"name"=>"Main"}}, "users_attributes"=>{"0"=>{"first_name"=>"John", "last_name"=>"Smith", "full_name"=>"John Smith", "email"=>"john@acme.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}}}, "commit"=>"Submit"}
  User Load (0.5ms)  SELECT  "users".* FROM "users"  WHERE "users"."deleted_at" IS NULL AND "users"."id" = 7  ORDER BY "users"."id" ASC LIMIT 1
  Role Load (0.3ms)  SELECT "roles".* FROM "roles" INNER JOIN "roles_users" ON "roles"."id" = "roles_users"."role_id" WHERE "roles"."deleted_at" IS NULL AND "roles_users"."user_id" = $1  [["user_id", 7]]
   (0.1ms)  BEGIN
  Location Exists (0.3ms)  SELECT  1 AS one FROM "locations"  WHERE "locations"."identifier" = '0d759e5405084663a1c110d37f04573a' LIMIT 1
  User Exists (0.2ms)  SELECT  1 AS one FROM "users"  WHERE "users"."email" = 'john@acme.com' LIMIT 1
   (0.1ms)  ROLLBACK
Completed 422 Unprocessable Entity in 75ms
** [Airbrake] Notice was not sent due to configuration:         
  Environment Monitored? false         
  API key set? true

ActiveRecord::RecordInvalid (Validation failed: Locations company can't be blank):
  app/controllers/company_controller.rb:10:in `create'
  app/controllers/application_controller.rb:95:in `set_time_zone'


  Rendered /Users/godzilla/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/actionpack-4.1.7/lib/action_dispatch/middleware/templates/rescues/_source.erb (0.9ms)
  Rendered /Users/godzilla/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/actionpack-4.1.7/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.7ms)
  Rendered /Users/godzilla/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/actionpack-4.1.7/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.2ms)
  Rendered /Users/godzilla/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/actionpack-4.1.7/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (15.6ms)

它引用位置标识符已经存在,但是不存在.这是在尝试创建新的Location时动态进行的操作(请注意location.rb模型中的方法generate_identifier).最重要的是,该用户也不存在.

It references that the location identifier already exists, but it doesn't. This is something that is made on the fly when trying to create a new Location (notice the method generate_identifier in the location.rb model). On top of that, the user doesn't exist either.

有什么办法解决这个问题吗?

Any ideas how to get around this problem?

推荐答案

编写validates_presence_of :company时,这意味着在创建位置时公司记录必须存在,但尚未完全保存.但是,您的位置仍与公司对象相关联,并且无需进行此验证即可正确保存.我认为您可以通过company_id的存在来验证,因为在保存过程中可以使用公司ID.

When you write validates_presence_of :company it means that your company record has to exist at the time of location creation, but it is not fully saved yet. However, your location is still associated with the company object, and it will be saved correctly without this validation. I think you can validate on presence of company_id instead because company id becomes available during saving.

这篇关于使用嵌套表单创建用户时的Rails回滚的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆