2014-11-10 4 views
0

질문 목록이 있습니다. 모든 질문에는 즉 4 개의 답변이 있고 모든 답변은 답변이없는 "끝"까지 다음 질문과 연결된 4 개의 답변이있는 다음 질문에 연결됩니다.Ruby (레일 위) 트리가 원형이 아닌지 확인하십시오.

이것은 나무와 같은 구조이며, 나는 그 방식으로 머물러 있기를 원합니다. 답변이 없으면 이미 묻은 질문에 연결됩니다.

이 작업을 수행하는 유일한 방법은 재귀 함수를 사용하는 것이라고 가정합니다. 이 같은

내가 생각 뭔가 :

MQ = [question.id] Q = question.id

def not_circular(q, mq) 
    mother_questions = mq 
    sister_questions = [] 
    question = Question.find(q) 
    question.answers.each do |a| 
    if mother_questions.include?(a.next_question) 
     return a.content 
    else 
     if !a.endlevel 
     sister_questions << a.next_question 
     end   
    end 
    end 
    mother_questions = mother_questions + sister_questions 

    question.answers.each do |a| 
     if !a.endlevel 
     return not_circular(a.next_question, mother_questions) 
     end 
    end 
    return false 
    end 

하지만 몇 가지 문제를 참조 - 나는의 배열을 생각하고 있었는데 "parent-Questions"와 "next_question"이이 배열에 있는지 확인합니다 (함수를 중지하고 "circular"next_question을 반환합니다). 그러나 예제 코드에서는 "자매 - 다음 질문 "(같은 질문에 대한 대답이 같은 질문을 가리킬 때)이 같을 수 있고 같아야합니다.

누구나 올바른 방향으로 나를 가리킬 수 있습니까?

편집 :

질문에 많은 답변이 있습니다. 대답은 질문에 속합니다. Answer에는 다음 질문을 가리키는 next_question 변수가 있습니다.

EDIT 2 : 트리의 적어도 하나의 분기를 올바르게 테스트하는 기능이 있습니다 (위의 새 코드 참조). 이제는 모든 지점을 테스트하는 방법을 알아 냈습니다.

+0

게시물에 질문 및 답변 연결을 추가 할 수 있습니까? –

답변

0

의견을 보내 주셔서 감사합니다.

나는 실제로 그것을 나의 방식으로 해결했다. (또는 적어도 나의 테스트는 그것을 해결하는데 성공한 것처럼 보인다.)

여기 내 코드입니다 :

mq = [Question.id] 
q = Question.id 

def not_circular(q, mq) 
    if mq.empty? 
    mother_questions = [q] 
    else 
    mother_questions = mq + [q] 
    end 
    question = Question.find(q) 
    question.answers.each do |a| 
    if mother_questions.include?(a.next_question) 
     return a.content 
    else 
     if a.next_question != 0 && !a.last_question 
     if not_circular(a.next_question, mother_questions) 
     return not_circular(a.next_question, mother_questions) 
     end 
     end   
    end 
    end  
    return false 
end 

지금 (따라서 동그라미를 만드는) 이전의 질문에 링크 대답은 관리자에 반환하고 그는 그것을 변경할 수 있습니다.

0

이 테스트의 책임 (즉 타당성)은 질문이 아니라 답변에 있어야한다고 생각합니다. 누군가가 이미 묻은 질문에 대한 대답을 링크하면 그 대답은 잘못되었습니다. 즉 부당한 것이지, 선택된 질문이 아닙니다.

그래서이 테스트를 답안 클래스로 옮길 것입니다.이 작업을하려면 다음 질문으로 그 질문을 가진 답을 가리키는 Question에 새로운 연관이 필요합니다. 나는 이것을 테스트하지 않았지만 그것이 효과가 있다고 생각합니다. 메서드를 시도하기 전에 previous_answers 연결이 작동하는지 테스트하십시오.

#in Question 
has_many :answers 
has_many :previous_answers, :class_name => "Answer", :source => :next_question 

#in Answer 
belongs_to :question 
belongs_to :next_question 

validate :does_not_link_to_previously_asked_question 

def does_not_link_to_previously_asked_question 
    if self.previous_questions.include?(self.next_question) 
    self.errors.add(:next_question_id, "This question has already been asked") 
    end 
end 

def previous_questions 
    current = [self.question] 
    questions = [] 
    while current.size > 0 
    current = current.collect(&:previous_answers).flatten.collect(&:question).reject(&:blank?) 
    questions += current 
    end 
    questions.uniq 
end 
+0

해답을 가져 주셔서 감사합니다. 그러나 저는 모델에서 이것을 수행하고 답을 다시 질문에 연결하고 싶지 않습니다. 이 질문은 일련의 질문 중 퀴즈가 서클없이 가능한지 확인하는 컨트롤러의 방법으로 수행하고 싶습니다. – Damjan

0

가 나는 완전히 통해 생각하지 않은 여기에 몇 가지 이론이 있지만 더 원형 경로가 존재하지 않는 수있는 간단한 보증을 원하는 경우,이를 달성하기위한 가장 간단한 방법은 아무 대답이 연결되지 수 있도록하는 것입니다 그 자체보다 높은 수준의 질문으로 돌아 간다. 그래서 질문은 그들이 나무에 어디에 있는지 알고 답은 질문의 수준보다 높을 수 없습니다. 대답은 여전히 ​​자신의 레벨 아래의 질문에 링크 될 수 있습니다.

그렇지 않으면이 계산을 모델에 너무 많이 매달려는 대신 독립형 Ruby로 생각해야한다고 생각합니다. 간단히 말해서 ID와 부모를 포함하는 매우 간단한 질문 및 답변 트리를 만들 수 있습니다/자식 관계를 사용하여 계층 간 대화를 너무 많이하지 않아도 데이터를 모델링 할 수 있습니다. 그것이 자체 모듈이기 때문에 테스트하고 관리하기가 더 쉽습니다.

현재 답변으로 이어질 수있는 질문을 추가 할 수 없도록하는 방법은 해당 답변의 경로에 응답에서 제공되는 질문이 없는지 확인하는 것입니다.트리 모델에서 각 노드가 부모 일뿐만 아니라 자식이라고 인식하면 현재 답변에서 나무를 걷는 것이 매우 간단합니다. (각 구성원의 배열은 parent입니다.) 모든 질문을 식별합니다. 그 길에. 그런 질문은 현재 답변에 합법적으로 추가 할 수없는 "제외 된"목록을 구성합니다.

+0

답변 해 주셔서 감사합니다. 나는이 일을 할 수 있기를 정말 좋아하지 만, 모든 질문의 모든 부모님을 구제해야합니까? 내가 뭘 하려는지 사용자에게 "동그라미를 만들기 때문에 대답 xy의 next_question 변경"을 사용자 지정 유효성 검사를 만드는 것입니다 – Damjan

+0

그것은이 작업을 수행 _where_에 따라 다릅니다; 당신은 어딘가에 전체 트리의 표현을 가져야합니다. 당신이 어떤 접근 방식을 취해도 상관없이 이것을 검증 할 수있는 방법은 없습니다.하지만 ActiveRecord 모델에서 꺼내는 것이 좋습니다. 그것을 전혀 저장하지 않아야합니다. 내가 ID를 언급 할 때 그것은 단지 guid 또는 유사 할 수 있습니다. 실제로 사용자 옵션을 제한하는 데 관심이 있다면 클라이언트의 JavaScript로 검사를 구현할 수도 있습니다. 그러면 잠재적으로 응답 성이 향상됩니다. – glenatron

1

트리에서이 문제를 다루는 가장 좋아하는 방법은 조인 테이블에 대한 유효성 검사를 사용하는 것입니다. 내가 사용하고있는 구조를 완전히 이해하고 있는지 확신 할 수 없으므로 서로 전제 조건 인 코스 공통 문제를 해결할 것입니다.

class Course < ActiveRecord::Base 
    has_many :course_relationships, dependent: :destroy 
    has_many :prereqs, through: :course_relationships 

    has_many :inverse_course_relationships, class_name: 'CourseRelationship', foreign_key: 'prereq_id', dependent: :destroy 
    has_many :inverse_prereqs, through: :inverse_course_relationships, source: :course 
end 

은 그럼 조인 테이블의 유효성 검사를 배치 :

class CourseRelationship < ActiveRecord::Base 
    belongs_to :course 
    belongs_to :prereq, class_name: 'Course' 

    validate :is_acyclic 

    def is_acyclic 
    if course == prereq 
     errors.add(:base, "A course can't be a prerequisite to itself") 
     return false 
    end 

    check_for_course = Proc.new do |current_course| 
     if course == current_course 
     errors.add(:base, "Catch 22 detected. \"#{course.title}\" is already required before \"#{prereq.title}\".") 
     return false 
     end 

     current_course.prereqs.each do |course_to_check| 
     check_for_course.call course_to_check 
     end 
    end 

    check_for_course.call prereq 
    return true 
    end 
end 

이 모든 시간이 새로운 관계가 생성되는 것을 보장은 물론 그 자체의 전제 조건을 (심지어 간접적 경우)이 될하지 않습니다.

관련 문제