Ruby on rails 如何实例化两侧都具有多态关联/验证的Rails模型?

Ruby on rails 如何实例化两侧都具有多态关联/验证的Rails模型?,ruby-on-rails,factory-bot,polymorphic-associations,Ruby On Rails,Factory Bot,Polymorphic Associations,在过去的两个小时里,我一直在为这个问题绞尽脑汁。我有两个多态链接的类。医生有医生的东西在他们和用户处理的网络组件电子邮件地址,设计等。医生是一个用户 原因是有不同的用户类别护士、医疗机构,它们都需要自己的字段,但由于它们是用户,所以它们相互关联。所以我在本例中选择了多态关联 问题是我似乎无法同时实例化它们,因为它们都没有被保存。假设一个空数据库,由于它们彼此需要,我如何准确地创建它们?有没有一种方法可以同时保存两者 class User < ActiveRecord::Base rol

在过去的两个小时里,我一直在为这个问题绞尽脑汁。我有两个多态链接的类。医生有医生的东西在他们和用户处理的网络组件电子邮件地址,设计等。医生是一个用户

原因是有不同的用户类别护士、医疗机构,它们都需要自己的字段,但由于它们是用户,所以它们相互关联。所以我在本例中选择了多态关联

问题是我似乎无法同时实例化它们,因为它们都没有被保存。假设一个空数据库,由于它们彼此需要,我如何准确地创建它们?有没有一种方法可以同时保存两者

class User < ActiveRecord::Base
  rolify
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  validates_presence_of :profile

  belongs_to :profile, polymorphic: true
end

class Doctor < ActiveRecord::Base
  has_one :user, as: :profile, dependent: :destroy
  accepts_nested_attributes_for :user

  validates_presence_of :user

  # doctor-specific code here

  delegate :email, :password, to: :user
end

class Nurse < ActiveRecord::Base
  # has_one, accepts... same as doctor. nurse-specific code here
end
如果有人能解决如何在FactoryGirl中使用此工具,我也将不胜感激


旁白:我已经看到了,但它们的两面都没有验证。

您可以跳过第一条记录的验证:

your_record.save(validate: false)
编辑:

实际上,您不需要跳过验证。它不工作的原因可能是因为验证检查的存在,以查看数据库中是否存在关联的对象。因此,对于医生、护士等来说,这样做是可以的,因为这些表没有存储用户id。但是您应该更改用户模型的验证以检查:

validates :profile_id, presence: true
这将确保配置文件_id属性被分配,即使配置文件医生、护士等还不存在。您必须按照正确的顺序创建对象,但:

u = User.new
d = Doctor.new
u.profile = d
u.save # it should be happy at this point because profile_id should be set
d.save

将护士/医生类型存储为用户的资源,并为用户设置控制器

class User
  #resource will be nurse/doctor etc
  belongs_to :resource, polymorphic: true, dependent: :destroy 
  accepts_nested_attributes_for :resource

  #add user specific validations here
end

#user will be either doctor or nurse and not both

class Doctor 
  has_one :user, as :resource 
  #add doctor specific validations
end

class Nurse
  has_one :user, as :resource
  #add nurse specific validations
end
现在,当您创建医生/护士类型的用户时,您可以要求用户选择类型,并根据选择为所选类型呈现嵌套表单。您可以直接在用户表单中呈现这两种类型的嵌套表单,也可以在用户选择类型时使用ajax添加它们

haml中的示例表格如下所示“资源_字段”是一个html id

= form_for @user ...
  = #user specific fields go here
  = #show dropdown to select type and send ajax with type to render type specific form.
  - if @user.resource.nil? #if resource is not set
    #resource_fields
  - else #if resource is present
    = render 'users/doctor_form', f: f if @user.resource.is_a? Doctor
    = render 'users/nurse_form', f: f if @user.resource.is_a? Nurse
响应ajax类型表单的控制器方法

def get_type_form
  @user = User.new
  @user.resource = case params[:selected_type]
                           when "Doctor"
                             Doctor.new
                           when 'Nurse'
                             Nurse.new
                           end
end
在get_form_type.js.haml中

:plain
 - if @user.resource.is_a? Doctor
   $('#resource_fields').replaceWith("#{escape_javascript(render partial: 'users/doctor_form', locals: { f: nil })}");
 - if @user.resource.is_a? Nurse
   $('#resource_fields').replaceWith("#{escape_javascript(render partial: 'users/nurse_form', locals: { f: nil })}");
医生表格的部分内容如下:

 #resource_fields
 - if f.nil?
   = fields_for "user[resource_attributes]", @user.resource do |doctor|
     = render 'users/doctor_fields', :doctor: doctor
 - if f
   = f.fields_for :resource, @user.resource do |doctor|
     = render 'users/doctor_fields', doctor: doctor
 = doctor.text_field :degree
 = doctor.text_field :specialization
而doctor_fields的部分

 #resource_fields
 - if f.nil?
   = fields_for "user[resource_attributes]", @user.resource do |doctor|
     = render 'users/doctor_fields', :doctor: doctor
 - if f
   = f.fields_for :resource, @user.resource do |doctor|
     = render 'users/doctor_fields', doctor: doctor
 = doctor.text_field :degree
 = doctor.text_field :specialization

我有一个类似的功能,我用上面的方法实现。

这里不完全清楚您的设置-尝试询问一些问题以澄清。那么医生就是用户——那么护士或医疗机构在代码方面是否与医生相似?这就是你所说的不同用户类别的意思?@RichardJordan感谢你的回答。是的,它们差不多。它们有自己特定于类的字段。@DaryllSantos,所以基本上每个人都是用户。唯一不同的是他们有不同的个人资料doctor/nurse/etc?@prasad.surase。我就是不能保存,因为用户需要配置文件,反之亦然。我想这对完整性来说是有意义的。我现在不想让随机用户没有配置文件,也不想让配置文件没有电子邮件地址。@DaryllSantos我正在添加答案。我实现的解决方案有点冗长。在下面添加它。谢谢迈克。呃,我如何确保每件事都得到很好的验证?我更新了我的答案,我想这会解决你的问题。由于多态性的原因,它可能有点偏离,但这个想法应该是正确的。太棒了,我会检查一下这个。。。我注意到您删除了委托/验证,并移动了资源的accepts\u nested\u attributes\u。如果你不介意我问,为什么这比旧代码好?这会改变预期的行为。在这个问题中,由于验证,医生或护士不能独立于用户而存在。但这实际上等同于删除这些验证,因为现在医生可以在没有用户的情况下生存。@MikeSlutsky我们可以在医生和护士上添加验证,以检查用户是否始终存在,并在用户上添加验证,以检查资源是否始终存在。@Darylsantos在我的应用程序中,要求用户能够选择类型。因此,父对象是用户对象,而不是医生或护士对象。因此,父对象接受子对象的嵌套属性。@DaryllSantos您可以添加特定于模型的验证和字段。表单将显示验证错误。