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
注意这只是一个(未经测试的)开始; 选项可能会丢失。
我强烈建议你阅读
- http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
- http://guides.rubyonrails.org/association_basics.html
编辑:回答评论中的问题
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_many
, belongs_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将从模型类定义中提取外键。