0

Project에 속하는 ProjectsPeople이 있다고 가정 해 봅니다. Person은 리더가 될 수도 있고 그렇지 않을 수도 있으며 이에 대한 범위가 있습니다. Project에는 최소 한 명의 리더가 있어야하며, 그렇지 않으면 무효입니다. 그래서 나는이 시도 :rails 새로운 레코드 유효 범위

class Project < ActiveRecord::Base 
    has_many :people 

    validate :has_a_leader 

    def has_a_leader 
    unless self.people.lead.size > 0 
     puts 'Must have at least one leader' 
     errors.add(:people, 'Must have at least one leader') 
    end 
    end 
end 

class Person < ActiveRecord::Base 
    belongs_to :project 
    scope :lead, -> { where(:is_lead => true) } 
end 

불행하게도 검증 범위가 새 레코드에 항상 비어 있기 때문에 만 저장 레코드와 작동합니다

p = Project.new 
p.people.lead.build 
=> #<Person ..., is_lead: true> 
p.people.lead 
=> #<ActiveRecord::AssociationRelation []> 
p.people 
=> #<ActiveRecord::AssociationRelation []> # <-- first syntax at least got something here 
p.valid? 
'Must have at least one leader' 
=> false 
: 또 다른 구문을 시도

p = Project.new 
p.people.build(:is_lead => true) 
=> #<Person ..., is_lead: true> 
p.people 
=> #<ActiveRecord::AssociationRelation [#<Person ..., is_lead: true>]> 
p.people.lead 
=> #<ActiveRecord::AssociationRelation []> 
p.valid? 
'Must have at least one leader' 
=> false 

그래서이 유효성 검사를 다시 작성하고 새 프로젝트를 만들 때 첫 번째 구문을 사용해야합니다.

def has_a_leader 
    unless self.people.find_all(&:is_lead).size > 0 
     puts 'Must have at least one leader' 
     errors.add(:people, 'Must have at least one leader') 
    end 
    end 

하지만 이제는 리더가되는 사람을 정의한 위치가 두 곳 있습니다. 유효성 검사 방법과 범위 람다입니다. 나는 나 자신을 반복한다. 작동하지만 Rails 방식은 아닙니다.

더 좋은 방법이 있나요?

답변

2

: 당신은 아주 쉽게 리드를 설정할 수 Project을 만들 때

class Project < ActiveRecord::Base 
    has_one :leader, -> { where(is_lead: true) }, class_name: 'Person' 
    validates :leader, presence: true 
end 

을 :

def create 
    project = Project.new(params[:project]) 
    project.leader.new(name: 'Corey') #=> uses the scope to set `is_lead` to `true` 
end 

을 당신은 여전히에도 나타 lead 범위가 당신의 Person 모델이지만 이미 정의되었으므로 사용 해보자.

class Project < ActiveRecord::Base 
    has_one :leader, Person.method(:lead), class_name: 'Person' 
end 

이것은 프로젝트의 리더를 움켜 쥐기가 훨씬 쉽다는 단점이 있습니다.

+0

답변 해 주셔서 감사합니다. 이렇게하면 리더는 사람으로 나타나지 않습니다 ('project.people'에서). 그러나 이것은 아마도 아무것도 아닌 것보다 낫습니다. 어쩌면이 명료하게하기 위해'Person'의 STI로 새로운'Leader' 클래스를 만들면 될까요? – Markus

+0

두 연관에 모두 'Person'을 추가하려고합니다. 또한'leader ='를 override하여'people <<'을 호출 한 다음'super '로 호출을 전달할 수 있습니다. 나는 "리더"가'사람 '과 다른 행동을하는 것이 아니라면 STI에서 이것을 복잡하게하지 않을 것이다. – coreyward

+0

'project_leader = Person.new (name : 'Corey')'에서'is_lead' 속성이'true'로 설정되어 있지 않습니다. 프로젝트를 저장 한 후에는 리더가 사라집니다. – Markus

0

프로젝트 테이블에 leader_id 또는 main_leader_id를 추가하셨습니까? 귀하의 프로젝트가 하나 이상의 리더를 가질 수는 있지만 귀하의 구현에있어 잠재적 인 문제점은 다음과 같습니다. 프로젝트를 만들고 한 사람이 누가 리더가 될지를 결정했다고 가정합니다. 나중에 그 사람이 프로젝트에서 벗겨집니다 (Person의 project_id 속성을 변경하여). Person에 콜백을 넣지 않는 한, 프로젝트는 더 이상 리더가 없다는 것을 알지 못할 것이며 잘못된 상태가 될 것입니다. Project가 유효하고 적어도 하나의 리더 (예 : my_project.leaders.first.do_something)가 있다고 가정하는 다른 코드를 사용하면 문제가 발생할 수 있습니다. main_leader_id와 같은 것이 있으면 프로젝트 모델에서 유효성 검사 (presence : true) 만하면되며 모든 리더를 얻으려면 has_many 관계를 사용할 수 있습니다.

당신은 다른 연결 추가하여 문제를 해결할 수