2014-02-27 2 views
1

지난 2 시간 동안이 문제에 대한 내 머리를 터트렸다. 나는 polymorphically 링크 된이 두 클래스가 있습니다. 의사는 의사에게 물건이 있고 사용자는 웹 구성 요소 (전자 메일 주소, 작성자 등)를 처리합니다. 의사는 사용자입니다.양쪽에 다형 연관/유효성 검사를 사용하여 Rails 모델을 인스턴스화하는 방법은 무엇입니까?

다른 사용자 클래스 (간호사, MedicalInstitutions)가 있기 때문에 모두 자신의 필드가 필요하지만 사용자라는 사실에 의해 함께 연결됩니다. 그래서 저는이 경우 다형성 연관성을 선택했습니다.

문제는 둘 다 저장되지 않기 때문에 두 인스턴스를 인스턴스화 할 수 없다는 것입니다. 빈 데이터베이스를 가정하면 서로를 필요로하기 때문에 두 데이터베이스를 정확히 어떻게 만듭니 까? 동시에 "둘 다를 저장하는"방법이 있습니까?

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에서이 문제를 어떻게 해결할 수 있는지 알려 주시면 감사하겠습니다.

옆 : 나는 this을 본 적이 있지만 양측에 유효성이 없습니다.

+0

여기에 설정을 명확히하지 않고 일부 q를 명확히 해보려고합니다. 그래서 의사는 사용자입니다. 그래서 간호사 나 MedicalInstitution은 의사와 비슷한 코드를 사용합니다. 그것이 다른 사용자 클래스의 의미입니까? –

+0

@RichardJordan이 답변 해 주셔서 감사합니다. 예, 그들은 같은 종류입니다. 그들 자신의 클래스 - 특정 필드가 있습니다. –

+0

@DaryllSantos 그래서 기본적으로 모두가 사용자입니다. 단, 다른 프로필 (의사/간호사/기타)을 가지고 있다는 점이 다릅니다. –

답변

0

당신은 당신의 첫 번째 레코드에 대한 유효성 검사를 건너 뛸 수 있습니다 :

your_record.save(validate: false) 

편집 :

는 사실, 당신은 유효성 검사를 생략 할 필요가 없습니다. 유효하지 않은 이유는 validates_presence_of가 연관된 객체가 데이터베이스에 존재하는지 확인하기 때문일 것입니다. 따라서 Doctor, Nurse 등 (has_many 쪽)에서는 user_id를 저장하지 않기 때문에이 작업을 수행 할 수 있습니다. 하지만 당신은 확인하기 위해 사용자 모델의 검증을 변경해야합니다 : 이것은 PROFILE_ID 속성이 할당되어 있는지 확인합니다

validates :profile_id, presence: true 

, 프로필 (의사, 간호사 등)이 아직 존재하지 않는 경우에도 마찬가지입니다. 당신은 비록 적절한 순서로 개체를 만들어야합니다

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 
+0

감사합니다. 마이크. 어, 어떻게 모든 것이 잘되었는지 확인할 수 있을까요? –

+0

내 대답이 업데이트되었으므로 문제가 해결 될 것입니다. 다형성 때문에 약간 떨어져있을 수 있지만 아이디어는 정확해야합니다. –

0

스토어 사용자를위한 자원으로 유형 (간호사/의사)와

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 

지금 사용자를위한 컨트롤러, u는 사용자가 작성하는이 의사/간호사 유형의 경우, 사용자에게 유형을 선택하도록 요청할 수 있으며 선택 사항에 따라 선택한 유형에 대해 중첩 된 양식을 렌더링합니다. 사용자 양식에서 두 유형의 중첩 된 양식을 렌더링하거나 사용자가 해당 유형을 선택할 때 ajax를 사용하여 중첩 된 양식을 추가 할 수 있습니다.

예제 양식은 haml입니다. 'resource_fields'는 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 

컨트롤러있어서

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에 입력 양식 AJAX에 응답한다.I 유사한 기능을 가지고 내가 상기 방법을 사용하여 구현

= 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 

상기 부분이 될 것이다 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 })}"); 

및 doctor_form위한 부분이 될 것이다.

+0

굉장합니다, 이것에 대해 살펴 보겠습니다 ... 당신이 위임/검증을 제거하고 자원의'accepts_nested_attributes_for'를 옮겼다는 것을 알았습니다. 내가 묻고 싶다면 왜 이전 코드보다 나은가요? –

+0

의도 한 동작이 변경됩니다. 질문에서, 의사 또는 간호사는 유효성 검사 때문에 사용자와 독립적으로 존재할 수 없습니다. 그러나 이것은 의사가 사용자없이 존재할 수 있기 때문에 유효성 검사를 제거하는 것과 동일합니다. –

+0

@MikeSlutsky 의사와 간호사에게 유효성 검증을 추가하여 사용자가 항상 있는지, 그리고 사용자가 자원이 항상 존재하는지 확인하십시오. –