belongs_to through associations

前端 未结 7 833
自闭症患者
自闭症患者 2020-11-30 17:19

Given the following associations, I need to reference the Question that a Choice is attached through from the Choice model. I have bee

相关标签:
7条回答
  • 2020-11-30 17:52

    Just use has_one instead of belongs_to in your :through, like this:

    class Choice
      belongs_to :user
      belongs_to :answer
      has_one :question, :through => :answer
    end
    

    Unrelated, but I'd be hesitant to use validates_uniqueness_of instead of using a proper unique constraint in your database. When you do this in ruby you have race conditions.

    0 讨论(0)
  • 2020-11-30 17:52

    My approach was to make a virtual attribute instead of adding database columns.

    class Choice
      belongs_to :user
      belongs_to :answer
    
      # ------- Helpers -------
      def question
        answer.question
      end
    
      # extra sugar
      def question_id
        answer.question_id
      end
    end
    

    This approach is pretty simple, but comes with tradeoffs. It requires Rails to load answer from the db, and then question. This can be optimized later by eager loading the associations you need (i.e. c = Choice.first(include: {answer: :question})), however, if this optimization is necessary, then stephencelis' answer is probably a better performance decision.

    There's a time and place for certain choices, and I think this choice is better when prototyping. I wouldn't use it for production code unless I knew it was for an infrequent use case.

    0 讨论(0)
  • 2020-11-30 17:57

    You can also delegate:

    class Company < ActiveRecord::Base
      has_many :employees
      has_many :dogs, :through => :employees
    end
    
    class Employee < ActiveRescord::Base
      belongs_to :company
      has_many :dogs
    end
    
    class Dog < ActiveRecord::Base
      belongs_to :employee
    
      delegate :company, :to => :employee, :allow_nil => true
    end
    
    0 讨论(0)
  • 2020-11-30 18:03

    A belongs_to association cannot have a :through option. You're better off caching the question_id on Choice and adding a unique index to the table (especially because validates_uniqueness_of is prone to race conditions).

    If you're paranoid, add a custom validation to Choice that confirms that the answer's question_id matches, but it sounds like the end user should never be given the opportunity to submit data that would create this kind of mismatch.

    0 讨论(0)
  • 2020-11-30 18:07

    It sounds like what you want is a User who has many Questions.
    The Question has many Answers, one of which is the User's Choice.

    Is this what you are after?

    I would model something like that along these lines:

    class User
      has_many :questions
    end
    
    class Question
      belongs_to :user
      has_many   :answers
      has_one    :choice, :class_name => "Answer"
    
      validates_inclusion_of :choice, :in => lambda { answers }
    end
    
    class Answer
      belongs_to :question
    end
    
    0 讨论(0)
  • 2020-11-30 18:09

    So you cant have the behavior that you want but you can do something that feels like it. You want to be able to do Choice.first.question

    what I have done in the past is something like this

    class Choice
      belongs_to :user
      belongs_to :answer
      validates_uniqueness_of :answer_id, :scope => [ :question_id, :user_id ]
      ...
      def question
        answer.question
      end
    end
    

    this way the you can now call question on Choice

    0 讨论(0)
提交回复
热议问题