如何处理XOR条件,Rails,外键和SQLite数据库?

6
我想要的是使用Rails 3.1构建以下内容: UML 如果A已为b_id设置了id,则不应该为c_id设置id。反过来也一样。我希望能够在迁移时从数据库级别进行操作(检查约束?)。这是否可能?还是用模型和验证更经济实惠?
我的环境: Ruby 1.9.3 Rails 3.1.3 SQLite 3.7.3
2个回答

2
通过多态关联,您可以实现这一点,尽管模式看起来不完全像您所拥有的那样,但您可以实现相同的目标,使项目 A 属于 BC 中的一个,而不是两者都属于。
您可以在此处阅读更多信息:http://guides.rubyonrails.org/association_basics.html#polymorphic-associations 在上面链接提供的示例中,A 是他们的 Picture,而 EmployeeProduct 则是您的 BC
class Picture < ActiveRecord::Base
  belongs_to :imageable, :polymorphic => true
end

class Employee < ActiveRecord::Base
  has_many :pictures, :as => :imageable
end

class Product < ActiveRecord::Base
  has_many :pictures, :as => :imageable
end

谢谢您的回答!结合@Frederick的答案,我将得到完整的解决方案来回答我的问题。 - Robin
1
我更倾向于@mynameiscoffey的答案。在表A中只有一个外键列,因此我们在表A中有'imageable_id'和'imageable_type'。 - Thong Kuah

0

我肯定会为此编写验证 - 从验证中向用户提供良好的错误消息更容易。我还想用数据库约束来支持它。看起来检查约束确实可以胜任这项工作。

Rails没有找到支持此功能的方法,因此您需要使用原始SQL创建表格。您还需要将模式转储器更改为:sql,因为Rails无法生成描述此内容的schema.rb

我编写了这个迁移。

class CreateFoos < ActiveRecord::Migration
  def change

    execute <<SQL
      CREATE TABLE foos (
        id INTEGER  PRIMARY KEY,
        x_id INTEGER,
        y_id INTEGER,
        constraint xorit check( (x_id OR y_id) AND NOT(x_id AND y_id))
      )
SQL
  end
end

然后在 Rails 控制台中

Foo.create(:x_id => 1, :y_id => 1) #=> SQLite3::ConstraintException

目前的情况是,你可以创建一行没有设置 x_id 或 y_id 的数据。你可以通过更改约束条件来改变这种情况。

(x_id IS NOT NULL OR y_id IS NOT NULL ) AND (x_id IS NULL OR y_id IS NULL)

对我来说似乎有效


谢谢您的回答!结合@mynameiscoffey的回答,我将得到完整的解决方案来回答我的问题。 - Robin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接