我是初学者/中级Rails开发人员,我继承了一个大型的Rails项目。在挖掘代码库时,我发现我们的一个模型具有依赖于硬编码ID的关联定义:
class Account < ActiveRecord::Base
has_many :customer_rels, :class_name => 'EntityAccountRel', :conditions => 'entity_account_rels.entity_type_id=1'
has_many :vendor_rels, :class_name => 'EntityAccountRel', :conditions => 'entity_account_rels.entity_type_id=2'
has_many :customers, :through => :customer_rels, :source => :entity
has_many :vendors, :through => :vendor_rels, :source => :entity
客户和供应商都是实体,与Account(通过EntityAccountRel)有关系。它们通过entity_type_id彼此区分,entity_type_id是指EntityType,这是一个模型,其少数成员足够静态,让我们通过硬编码的id引用它们。我认识到这是一种不好的做法,但我想知道重构的“最佳”方式:
1)重新定义关联定义以使用如下的子查询:
has_many :customer_rels, :class_name => 'EntityAccountRel', :conditions => 'entity_account_rels.entity_type_id=(select id from entity_type where name="Customer")'
这对我来说是最明显的解决方案,但也看起来非常不优雅,也可能效率低下
2)在EntityAccountRel上定义范围,如下所示:
scope :customer, joins(:entity_type).where('entity_type.code="CUST"')
然后以某种方式将其与关联定义联系起来:
has_many :customer_rels, :class_name => 'EntityAccountRel', :scope => :customer
这不起作用,(未知密钥:范围(ArgumentError))但似乎如果我知道如何正确定义关联,可能会支持它
3)在EntityAccountRel上建立一个继承关系,不需要entity_type_id(也可能是EntityType):
class CustomerAccountRel < EntityAccountRel
这将简化我的关联定义,但它似乎是一个具有深远影响的主要重构。另外,我被告知谨慎使用继承,因为它可能使代码难以理解。
这些是我提出的所有选项,但我认为我遗漏了一些明显的东西。
答案 0 :(得分:0)
EntityType#id
似乎被认为是静态的并且与代码行为密切相关,因此您可以将它们命名为常量:
class EntityType
CUSTOMER = 1
VENDOR = 2
end
然后用常数替换幻数。这很快,并为您提供了良好的回报,因为您可以轻松地在代码的其他部分引用它。我会在模型层中保留对这些常量的所有引用。