Rails 4:多态,单表继承,范围......?

时间:2015-10-06 16:19:28

标签: ruby-on-rails-4

假设以下内容:

class Customer < ActiveRecord::Base
  has_many :orders
end

class Order < ActiveRecord::Base
  belongs_to :customer
end

客户可以是红色客户和/或蓝色客户,但他们从不只是客户。红色顾客拥有狗,蓝色顾客戴帽子(顾客必须戴帽子或拥有狗)。对于给定的订单,red_customer 从不等于blue_customer。由于我从不使用customer_id,因此我希望将其从架构中删除,并将其替换为red_customer_id和blue_customer_id。每个订单都有一个red_customer_id和blue_customer_id。

...实例

  • @ some_order.customer#不,不好,不想要
  • @ some_order.red_customer#返回用户对象
  • @ some_order.blue_customer#返回用户对象

架构(目前很难看)

  create_table "orders"
    t.string   "name"
    t.integer  "user_id" # I want to get rid of this
    t.integer  "red_customer_id"
    t.integer  "blue_customer_id"
  end

但是如果我删除user_id,那么我的关联会中断。我该如何清理它?

1 个答案:

答案 0 :(得分:0)

假设订单一次只能属于一个用户,我建议您不要在表中包含2个foreign_keys。使用单表继承:

可以获得相同的结果
class Customer < ActiveRecord::Base
  has_many :orders
end

class RedCustomer < Customer
end

class BlueCustomer < Customer
end

class Order < ActiveRecord::Base
  belongs_to :red_customer, foreign_key: 'customer_id'
  belongs_to :blue_customer, foreign_key: 'customer_id'
end

这样,您可以为客户保留一个表,并为订单保留一个foreign_key。

为此,您需要在customer表中使用type字符串列,也可以在订单迁移中将polymorphic: true添加到客户foreign_key声明中,这样列customer_type将会也被创造。

class CreateCustomers < ActiveRecord::Migration
  def change
    create_table :customers do |t|
      t.string     :type
      t.timestamps null: false
    end
  end
end

class CreateOrders < ActiveRecord::Migration
  def change
    create_table :orders do |t|
      t.references :customer, polymorphic: true, index: true

      t.timestamps null: false
    end
  end
end

按预期工作:

order = Order.create
order.red_customer = BlueCustomer.create #=> raises <ActiveRecord::AssociationTypeMismatch>
order.red_customer = RedCustomer.create #=> Ok
order.blue_customer #=> nil
order.red_customer #=> #<RedCustomer id: ...>
order.blue_customer = BlueCustomer.create #=> Ok
order.red_customer #=> nil

希望这会对你有所帮助。