我定义了以下类,这些类具有许多具有细微变化的通用代码。
class ThirdPartyComponent < ActiveRecord::Base
belongs_to :prev_version, :class_name => 'ThirdPartyComponent', :foreign_key => 'prev_version_id'
has_one :next_version, :class_name => 'ThirdPartyComponent', :foreign_key => 'prev_version_id'
attr_accessible :name, :version, :installer, :install_script
mount_uploader :installer, ComponentFileUploader
mount_uploader :install_script, ComponentFileUploader
validates :name, :presence => true
validates :version, :presence => true, :format => { :with => /\A\d{1,3}\.\d{1,2}\z/ }
validates :installer, :presence => true
validates :install_script, :presence => true
validate :increased_version
def increased_version
# Check to ensure that version number is greater than the previous version number for the same component set
unless prev_version.nil?
version > prev_version.version
end
end
def all_previous_versions
prev_versions = all_versions
prev_versions.shift
prev_versions
end
def all_versions
current_version = self
all_versions = [current_version]
while !current_version.prev_version.nil?
all_versions << current_version.prev_version
current_version = current_version.prev_version
end
all_versions
end
end
class RegistryComponent < ActiveRecord::Base
belongs_to :prev_version, :class_name => 'RegistryComponent', :foreign_key => 'prev_version_id'
has_one :next_version, :class_name => 'RegistryComponent', :foreign_key => 'prev_version_id'
attr_accessible :name, :version, :registry_file
mount_uploader :registry_file, ComponentFileUploader
validates :name, :presence => true
validates :version, :presence => true, :format => { :with => /\A\d{1,3}\.\d{1,2}\z/ }
validates :registry_file, :presence => true
validate :increased_version
def increased_version
# Check to ensure that version number is greater than the previous version number for the same component set
unless prev_version.nil?
version > prev_version.version
end
end
def all_previous_versions
prev_versions = all_versions
prev_versions.shift
prev_versions
end
def all_versions
current_version = self
all_versions = [current_version]
while !current_version.prev_version.nil?
all_versions << current_version.prev_version
current_version = current_version.prev_version
end
all_versions
end
end
我还在考虑在未来添加一些其他组件,同样具有非常相似的功能。
我想将这些类中的通用代码提取到一个文件中(包括 ActiveRecord 方法调用,如 validates 等),然后在具体类中引用它们。
到目前为止,我已经尝试过,
- 继承 - 我创建了一个从 ActiveRecord 继承的基类,然后每个类都从基类继承。结果:Rails 抱怨它找不到名称与基类匹配的数据库表。
- 继承 - 我考虑将基类创建为无表模型(参见http://railscasts.com/episodes/219-active-model),但后来我意识到具体类也将缺乏完整的 ActiveRecord 功能
组合 - 我尝试在模块中定义公共代码,然后在具体类中使用包含或扩展来访问它,如下所示。
module ComponentBase belongs_to :prev_version, :class_name => self.class.name, :foreign_key => 'prev_version_id' has_one :next_version, :class_name => self.class.name, :foreign_key => 'prev_version_id' attr_accessible :name, :version validates :name, :presence => true validates :version, :presence => true, :format => { :with => /\A\d{1,3}\.\d{1,2}\z/ } validate :increased_version def increased_version # Check to ensure that version number is greater than the previous version number for the same component set unless prev_version.nil? version > prev_version.version end end def all_previous_versions prev_versions = all_versions prev_versions.shift prev_versions end def all_versions current_version = self all_versions = [current_version] while !current_version.prev_version.nil? all_versions << current_version.prev_version current_version = current_version.prev_version end all_versions end end class RegistryComponent < ActiveRecord::Base include ComponentBase attr_accessible :registry_file mount_uploader :registry_file, ComponentFileUploader validates :registry_file, :presence => true end
这导致了一个
belongs_to
没有为 定义方法的错误ComponentBase
。这看起来是最有希望的解决方案,但是有没有办法在包含它们的类的上下文中执行 ActiveRecord 类方法?或者,我是否有更好的方法来实现相同的目标?