Associations and (multiple) foreign keys in rails (3.2) : how to describe them in the model, and write up migrations

前端 未结 3 644
無奈伤痛
無奈伤痛 2020-12-22 03:07

I have 3 models: Question, Option, Rule

Question has_many options; Option needs a foreign key for question_id

Rule table consists of 3 foreign_keys:

3条回答
  •  甜味超标
    2020-12-22 03:22

    Note: I have found this way to solve the problem.Kindness from China.

    If you have RailsAdmin with you,you may notice that you can see all rules of one question as long as one field of both question fields(assumption_question_id,consequent_question_id) equals to id of the question.

    I have done detailed test on this and found out that Rails always generates a condition "question_id = [current_id]" which make to_sql outputs

    SELECT `rules`.* FROM `rules` WHERE `rules`.`question_id` = 170
    

    And the reason that the following model

    class Question < ActiveRecord::Base
      has_many :options
      # Notice ↓
      has_many :rules, ->(question) { where("assumption_question_id = ? OR consequent_question_id = ?", question.id, question.id) }, class_name: 'Rule'
      # Notice ↑
    end
    

    makes Question.take.rules.to_sql be like this

    SELECT `rules`.* FROM `rules` WHERE `rules`.`question_id` = 170 AND (assumption_question_id = 170 OR consequent_question_id = 170)
    

    Is that we have not yet get ride of the annoy question_id so no matter how we describe or condition properly, our condition follows that "AND".

    Then,we need to get ride of it.How?

    Click here and you will know how,Find sector 8.1,and you can see

    Article.where(id: 10, trashed: false).unscope(where: :id)
    # SELECT "articles".* FROM "articles" WHERE trashed = 0
    

    Then lets do it:

    class Question < ActiveRecord::Base
      has_many :options
      # Notice ↓
      has_many :rules, ->(question) { unscope(where: :question_id).where("assumption_question_id = ? OR consequent_question_id = ?", question.id, question.id) }, class_name: 'Rule'
      # Notice ↑
    end
    
    class Rule < ActiveRecord::Base
      belongs_to :option
      belongs_to :assumption_question, class_name: "Question", foreign_key: :assumption_question_id, inverse_of: :assumption_rules
      belongs_to :consequent_question, class_name: "Question", foreign_key: :consequent_question_id, inverse_of: :consequent_rules
    end
    
    class Option < ActiveRecord::Base
      belongs_to :question
      has_one    :rule
    end
    

    All done.

    Finally

    This is my first answer here at stackoverflow,and this method is never found anywhere else.

    Thanks for reading.

提交回复
热议问题