我的Rails5应用程序具有组织模型和用户模型(1:n关系)。创建组织的工作流程还应包括组织的第一个用户的创建。我认为这可以通过嵌套模型使用ActiveRecord,但是创建操作失败并显示错误消息"用户组织必须存在"。
class Organization < ApplicationRecord
has_many :users, dependent: :destroy
accepts_nested_attributes_for :users
end
class User < ApplicationRecord
belongs_to :organization
end
class OrganizationsController < ApplicationController
def new
@organization = Organization.new
@organization.users.build
end
def create
@organization = Organization.new(organization_params)
if @organization.save
redirect_to @organization
else
render 'new'
end
end
def organization_params
params.require(:organization).permit(:name, users_attributes: [:name, :email, :password, :password_confirmation])
end
end
在视图中,我使用<%= f.fields_for :users do |user_form| %>
帮助器。
这是我身上的错误,还是ActiveRecord完全不支持?在导轨指南中无法找到任何相关信息。毕竟,这应该(理论上)是可能的:首先对组织进行INSERT,然后对用户进行INSERT(顺序很重要,要知道用户外键的组织ID)。
答案 0 :(得分:1)
如https://github.com/rails/rails/issues/18233中所述,Rails5需要进行完整性检查。因为我不喜欢像禁用完整性检查这样的愚蠢的解决方案,所以我遵循了DHH关于上述问题的建议:
我喜欢通过常规Ruby对象进行聚合。例如,我们有一个Signup模型,它只是一个编排构建过程的Ruby对象。所以,我该放手一搏!
我编写了一个名为注册的ruby类,它封装了组织和用户模型,并提供了类似ActiveRecord模型的保存/创建界面。此外,通过包含 ActiveModel :: Model ,有用的东西可以免费进入类(属性哈希构造函数等,请参阅http://guides.rubyonrails.org/active_model_basics.html#model)。
# The Signup model encapsulates an organization and a user model.
# It's used in the signup process and helps persisting a new organization
# and a referenced user (the owner of the organization).
class Signup
include ActiveModel::Model
attr_accessor :organization_name, :user_name, :user_email, :user_password, :user_password_confirmation
# A save method that acts like ActiveRecord's save method.
def save
@organization = build_organization
return false unless @organization.save
@user = build_user
@user.save
end
# Checks validity of the model.
def valid?
@organization = build_organization
@user = build_user
@organization.valid? and @user.valid?
end
# A create method that acts like ActiveRecord's create method.
# This builds the object from an attributes hash and saves it.
def self.create(attributes = {})
signup = Signup.new(attributes)
signup.save
end
private
# Build an organization object from the attributes.
def build_organization
@organization = Organization.new(name: @organization_name)
end
# Build a user object from the attributes. For integritiy reasons,
# a organization object must already exist.
def build_user
@user = User.new(name: @user_name, email: @user_email, password: @user_password, password_confirmation: @user_password_confirmation, organization: @organization)
end
end
特别感谢@engineersmnky指出了相应的github问题。
答案 1 :(得分:0)
您正在寻找&#34;协会回拨&#34;。将这些参数发送到组织模型后,您可以在该模型中访问它们。如果每次创建组织时都会为其分配一个新用户,您只需在组织模型中执行以下操作:
has_many :users, dependent: :destroy, after_add: :create_orgs_first_user
attr_accessor: :username #create virtual atts for all the user params and then assign them as if they were organizational attributes in the controller. This means changing your `organization_params` method to not nest user attributes inside the array `users_attributes`
def create_orgs_first_user
User.create(name: self.username, organization_id: self.id, etc.) # You can probably do self.users.create(params here) but I didn't try it that way.
end
答案 2 :(得分:0)
&#34;用户组织必须存在&#34;不应该出错。 ActiveRecord是&#34; smart,&#34;因为它应该执行两个.announcement
。首先,它将模型保存在INSERT
侧,以便它具有has_many
,然后它将模型保存在id
侧,填充外键值。问题实际上是由5.1.1之前的Rails 5版本中的belongs_to
中的错误引起的。请参阅https://github.com/rails/rails/issues/25198和Trouble with accepts_nested_attributes_for in Rails 5.0.0.beta3, -api option。
解决方案是使用accepts_nested_attributes_for
选项,或者更好的是升级到Rails 5.1.1。
您可以通过删除inverse_of:
模型中的accepts_nested_attributes_for
并在Rails控制台中创建新的Organization
模型和新的Organization
来证明这是真的。模型,关联它们(例如User
)并尝试myorg.users << myuser
(例如save
)。您会发现它会按预期工作。