[英]In Rails, how to connect a model twice to another model that it polymorphically belongs_to?
我正在尝试确定在Rails 4中设置以下架构和关联的适当方法:
Business
company_name
->1 street_address (Address)
->0..1 mailing_address (Address)
->0..n employees (Employee)
Employee
first_name
last_name
birthday
->0..n addresses (Address)
Address
street
city
state
zip
->1 resource (Business or Employee or potentially something else in the future)
这里的主要目标是:
请注意,一个地址既可以属于一个公司(充当该公司的街道地址或邮寄地址),也可以属于一个雇员(一个雇员可以有多个地址)。 对我而言,这意味着多态关系,而我在Rails中实现此目标的第一步是这样的:
class Business < ActiveRecord::Base
has_one :street_address, class_name: 'Address', as: :resource,
inverse_of: :resource, dependent: :destroy
has_one :mailing_address, class_name: 'Address', as: :resource,
inverse_of: :resource, dependent: :destroy
has_many :business_employees, inverse_of: :business, dependent: :destroy
has_many :employees, through: :business_employees
end
class BusinessEmpoloyee < ActiveRecord::Base
belongs_to :business
belongs_to :employee
end
class Employee < ActiveRecord::Base
has_many :business_employees, inverse_of: :employee, dependent: :destroy
has_many :businesses, through: :business_employees
has_many :addresses, as: :resource, inverse_of: :resource, dependent: :destroy
end
class Address < ActiveRecord::Base
belongs_to :resource, polymorphic: true
end
但是,这没有达到预期的效果。 商家的街道地址和邮寄地址总是返回相同的值。 例如:
2.1.2 :001 > b = Business.create(company_name: 'Test Business')
2.1.2 :002 > b.street_address = Address.create(street: '123 Main St', city: 'San Francisco', state: 'CA')
2.1.2 :003 > b.mailing_address = Address.create(street: 'P.O. Box 123', city: 'New York', state_code: 'NY')
2.1.2 :004 > b2 = Business.find_by_company_name('Test Business')
Business Load (1.2ms) SELECT "businesses".* FROM "businesses" WHERE "businesses"."company_name" = 'Test Business' LIMIT 1
=> #<Business id: 1168, company_name: "Test Business", street_address_id: nil, mailing_address_id: nil, created_at: "2014-09-04 19:57:14", updated_at: "2014-09-04 19:57:14">
2.1.2 :005 > b2.mailing_address
Address Load (0.5ms) SELECT "addresses".* FROM "addresses" WHERE "addresses"."resource_id" = $1 AND "addresses"."resource_type" = $2 LIMIT 1 [["resource_id", 1168], ["resource_type", "Business"]]
=> #<Address id: 1186, resource_id: 1168, resource_type: "Business", street: "P.O. Box 123", city: "New York", state: "NY", zip: nil, created_at: "2014-09-04 19:57:56", updated_at: "2014-09-04 19:57:56">
2.1.2 :006 > b2.street_address
Address Load (0.5ms) SELECT "addresses".* FROM "addresses" WHERE "addresses"."resource_id" = $1 AND "addresses"."resource_type" = $2 LIMIT 1 [["resource_id", 1168], ["resource_type", "Business"]]
=> #<Address id: 1186, resource_id: 1168, resource_type: "Business", street: "P.O. Box 123", city: "New York", state: "NY", zip: nil, created_at: "2014-09-04 19:57:56", updated_at: "2014-09-04 19:57:56">
当然,这确实是有道理的-业务部门应该如何知道将哪个地址用于哪个地址值?
那么,既然如此,我如何能捕捉到这里所描述的关系有什么建议?
经验法则:关系被写入belongs
的模型中。 如果为一个模型指定两个指向同一模型的关联,则它们实际上将是相同的,因为只有一种归属方式:具有某个模型的resource_id
和resource_type
。
您需要在“所属”中添加另一个参数,以便过滤“属于哪种”。 一种相对标准的方法是单表继承(STI)( 我碰巧写过有关如何使用它的方法 ),其工作方式如下:您向Address
添加一个type:string:index
列,并创建一个继承自它的新类Address
,例如MailingAddress
:
class MailingAddress < Address
end
大多数情况下,它应该为空,它继承自Address
甚至存储的所有内容:存储在同一张表中,但可以通过type="MailingAddress"
进行区分,当您从数据库查询此类的实例时,该类型将自动添加。 但是,当您查询Address
es时,根据继承原理,您还将获得MailingAddress
es。
执行此操作的其他方法涉及相似的内容:添加另一列以从所有其他地址中过滤出邮件地址。 即使RDBMS如此之快,字符串也不是最快的比较对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.