如何处理xor条件,rails,外键和sqlite数据库?

时间:2011-12-28 14:14:09

标签: ruby-on-rails sqlite database-design xor

我想要的是,使用Rails 3.1以某种方式构建它: UML

如果Ab_id设置了ID,则无法为c_id设置ID。而且反过来也是如此。

我希望我能从数据库级别进行迁移(检查约束?)。这有点可能吗? 或者在带有验证的模型中更实惠?

我的环境:

  • Ruby 1.9.3
  • Rails 3.1.3
  • SQLite 3.7.3

2 个答案:

答案 0 :(得分:2)

你可以通过多态关联实现这一点,虽然架构看起来不像你拥有的那样,你可以实现相同的目标,让A项属于B或者C但永远不会两者兼得。

您可以在此处阅读更多内容:http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

在该链接上提供的示例中,A是他们的Picture,而EmployeeProudct是您的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

答案 1 :(得分:0)

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

Rails不支持我可以找到的,所以你需要用raw 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)

似乎对我有用