我对Ruby还是很陌生,想知道如果我每次创建新用户(注册时)都想怎么做,它会自动创建一个Contractor实例,以便新User = Contractor。
我很迷茫,提供一些帮助和解释真的很高兴。
用户控制器
each_pair { |name, val| }class UsersController < ApplicationController
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :update_resource_params, if: :devise_controller?
def new
@user = User.new
end
def create
@user = User.new(user.params)
@contractor = Contractor.create(user: @user)
if @user.save
UserMailer.user_alert(@user).deliver_now
redirect_to @user, notice: 'User was successfully created.'
else
render :new
end
end
承包商模型
class Contractor < ApplicationRecord
belongs_to :user
has_many :construction_projects, dependent: :destroy
has_many :clients, dependent: :destroy
has_many :documents, through: :construction_projects
has_many :resources
mount_uploader :logo, LogoUploader
# Model validations
validates :user, presence: true
validates_associated :construction_projects
validates_associated :clients
validates_associated :documents
validates_associated :resources
用户模型
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_one :contractor
has_many :clients, through: :contractor
has_many :construction_projects, through: :contractor
# Model validations
validates_associated :clients
validates_associated :construction_projects
validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
def option_projects
projects = self.contractor.construction_projects.map{ |cp| [cp.name, cp.id] }
projects << ["Add a new project", "Add a new project"]
projects
end
end
答案 0 :(得分:1)
您已定义一个用户has_one
承包商,这意味着该承包商具有外键(user_id
)。您正在这样创建承包商:
@user = User.new(user.params)
@contractor = Contractor.create(user: @user)
Rails需要使用指向新用户的user_id
创建承包商行,该行尚未保存。 Rails继续尝试保存新用户(以便获得ID),然后创建承包商。
您不在此处检查任何验证错误,因此有可能创建承包商而不是用户。
看起来,当您第一次创建承包商(用户除外)时,您不需要传递任何属性。所以我将您的代码更改为此:
@user = User.new(user.params) # should that be user_params?
if @user.save
# now we have a saved user, so create its associated Contractor
@user.create_contractor!
...
在声明create_contractor!
关联时会自动为您定义has_one
方法。如果创建承包商时出现错误,则该方法的!
版本将引发异常。如果您在这里没有任何处理此类错误的方法(在正常情况下不要指望),那似乎是合理的。
答案 1 :(得分:0)
您需要首先建立从用户到承包商的关联:
class User < ApplicationRecord
# ...
has_one :contractor
# or
has_many :contractors
end
然后您可以通过从关联建立一个记录来一次插入两个记录:
irb(main):001:0> @user = User.new
=> #<User id: nil, created_at: nil, updated_at: nil>
irb(main):002:0> @user.build_contractor
=> #<Contractor id: nil, user_id: nil, created_at: nil, updated_at: nil>
irb(main):003:0> @user.save
(0.3ms) BEGIN
User Create (0.8ms) INSERT INTO "users" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2018-11-19 17:43:37.730785"], ["updated_at", "2018-11-19 17:43:37.730785"]]
Contractor Create (1.9ms) INSERT INTO "contractors" ("user_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["user_id", 2], ["created_at", "2018-11-19 17:43:37.734395"], ["updated_at", "2018-11-19 17:43:37.734395"]]
(1.2ms) COMMIT
ActiveRecord非常聪明,可以按正确的顺序插入记录,以便将返回的ID用于contractors.user_id
。
如果关联为has_many
,则可以通过在关联上调用.new
来执行相同的操作:
@user.contractors.new
请参阅: