1

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

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

规则表由 3 个外键组成:

  • 2 列/对 question_ids 的引用-> 名为“assumption_question_id”和“consequent_question_id”的外键
  • 1 列/对 option_id 的引用 -> 名为 option_id 或 condition_id 的外键

规则关联:问题 has_many 规则;和选项 has_one 规则

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

我有这个用于我的选项迁移,但我不确定“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

感谢您的帮助!

4

3 回答 3

2

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

Rails为管理外键的迁移提供本地支持。此类功能包含在诸如foreigner之类的 gem 中。阅读 gem 的文档以了解它的使用方式。

至于关联,只需将您在问题中提到的列添加到每个表中(您提供的迁移看起来不错;也许它缺少一个: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 表中的列question_id存储optionsid中记录的值questions。Rails 猜测列的名称是question_id基于:question符号的。options您可以通过指定一个选项来指示 rails 查看表中的不同列,例如foreign_key: :question_reference_identifier该列的名称。(请注意Rule,我上面代码中的类以foreign_key这种方式使用该选项)

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

于 2012-07-12T18:55:04.427 回答
2

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

如果您有 RailsAdmin,您可能会注意到,只要两个问题字段(assumption_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 上的第一个答案,这种方法在其他任何地方都找不到。

谢谢阅读。

于 2016-11-04T15:58:27.633 回答
0

您可以像这样在模型中设置外键:

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

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

于 2013-01-10T21:32:27.960 回答