rails(3.2)中的关联和(多个)外键:如何在模型中描述它们,并编写迁移

我有3个模型:问题,选项,规则

问题has_many选项; 选项需要question_id的外键

规则表由3个foreign_keys组成:

  • 2列/对question_ids的引用 – >名为’assume_question_id’和’consequent_question_id’的外键
  • 1列/对option_id的引用 – >名为option_id或condition_id的外键

规则关联:问题有多个规则; 和Option has_one规则

我想了解如何为此编写迁移,以及如何与我在模型中编写的’has_many’/’belongs_to’语句以及我可以包含在模型中的’:foreign_key’选项相关联。

我有这个用于我的Option迁移,但我不确定“add_index”语句如何在外键方面起作用,以及如何将它用于我的规则迁移:(我的问题和选项模型有适当的has_many和belongs_to语句 – 并且工作正常)

class CreateOptions < ActiveRecord::Migration def change create_table :options do |t| t.integer :question_id t.string :name t.integer :order t.timestamps end add_index :options, :question_id end end 

感谢您的帮助!

add_index为指定的列添加索引,仅此而已。

Rails 在迁移管理外键时不提供本机支持 。 这样的function包含在像外国人这样的gem中。 阅读gem的文档,了解它是如何使用的。

至于关联,只需将问题中提到的列添加到每个表中(您提供的迁移看起来很好;也许它缺少a :rule_id ?)

然后在模型中指定关联。 帮助你入门

 class Question < ActiveRecord::Base has_many :options has_many :assumption_rules, class_name: "Rule" has_many :consequent_rules, class_name: "Rule" 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 

注意这只是一个(未经测试的)开始; 选项可能会丢失。

我强烈建议你阅读

编辑:回答评论中的问题

 class Option < ActiveRecord::Base belongs_to :question # ... 

belongs_to告诉rails, options表中的question_id列存储了questions表中记录的id值。 Rails基于:question符号猜测列的名称是question_id 。 您可以通过指定foreign_key: :question_reference_identifier这样的options来指示rails查看options表中的其他列,如果这是列的名称。 (注意上面代码中的Rule类以这种方式使用foreign_key选项)

您的迁移只不过是Rails将根据您的数据库读取和执行命令的指令。 您的模型关联has_manybelongs_to等等)告知Rails您希望Active Record如何处理您的数据,为您提供一种清晰简单的数据交互方式。 模型和迁移从不相互影响; 它们都独立地与您的数据库交互。

注意:我找到了解决问题的方法。来自中国的善意。

如果你有RailsAdmin,你可能会注意到只要一个问题字段的一个字段(assume_question_id,consequent_question_id)等于问题的id,就可以看到一个问题的所有规则。

我已对此进行了详细的测试,发现Rails总是生成条件“question_id = [current_id]”,这使得to_sql输出

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

而以下型号的原因

 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 

使Question.take.rules.to_sql像这样

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

我们还没有得到烦恼的question_id _因此无论我们如何正确地描述或条件,我们的条件都遵循“和”。

然后,我们需要骑它。怎么样?

单击此处,您将了解如何,查找部门8.1 ,您可以看到

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

然后让我们这样做:

 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 

全部完成。

最后

这是我在stackoverflow的第一个答案,这个方法在其他任何地方都找不到。

谢谢阅读。

您可以在模型中设置外键,如下所示:

 class Leaf < ActiveRecord::Base belongs_to :tree, :foreign_key => "leaf_code" end 

您不需要在迁移中指定它,rails将从模型类定义中提取外键。