我正在为我的 rails 项目编写一个 Importable 关注点。这个问题将为我提供一种通用的方式来将 csv 文件导入到任何包含 Importable 的模型中。
我需要为每个模型指定一种方法来指定导入代码应该使用哪个字段来查找现有记录。有没有推荐的方法来添加这种类型的配置来解决问题?
我正在为我的 rails 项目编写一个 Importable 关注点。这个问题将为我提供一种通用的方式来将 csv 文件导入到任何包含 Importable 的模型中。
我需要为每个模型指定一种方法来指定导入代码应该使用哪个字段来查找现有记录。有没有推荐的方法来添加这种类型的配置来解决问题?
一个稍微“普通”的解决方案,我们这样做(巧合的是,对于某些 csv 导入问题)以避免将参数传递给关注点的需要。我确信引发错误的抽象方法有利有弊,但它将所有代码保留在 app 文件夹和您希望找到它的模型中。
在“关注”模块中,只有基础知识:
module CsvImportable
extend ActiveSupport::Concern
# concern methods, perhaps one that calls
# some_method_that_differs_by_target_class() ...
def some_method_that_differs_by_target_class()
raise 'you must implement this in the target class'
end
end
并且在有问题的模型中:
class Exemption < ActiveRecord::Base
include CsvImportable
# ...
private
def some_method_that_differs_by_target_class
# real implementation here
end
end
我建议不要在每个模型中都包含关注点,而是创建一个ActiveRecord
子模块并使用它进行扩展ActiveRecord::Base
,然后在该子模块中添加一个方法(比如include_importable
)来执行包含。然后,您可以将字段名称作为参数传递给该方法,并在该方法中定义实例变量和访问器(例如importable_field
)以保存字段名称以供您的Importable
类和实例方法中引用。
所以是这样的:
module Importable
extend ActiveSupport::Concern
module ActiveRecord
def include_importable(field_name)
# create a reader on the class to access the field name
class << self; attr_reader :importable_field; end
@importable_field = field_name.to_s
include Importable
# do any other setup
end
end
module ClassMethods
# reference field name as self.importable_field
end
module InstanceMethods
# reference field name as self.class.importable_field
end
end
然后,您需要扩展ActiveRecord
此模块,例如将此行放入初始化程序 ( config/initializers/active_record.rb
):
ActiveRecord::Base.extend(Importable::ActiveRecord)
(如果您担心,config.autoload_paths
那么您不需要在这里要求它,请参阅下面的评论。)
然后在您的模型中,您将包括Importable
以下内容:
class MyModel
include_importable 'some_field'
end
imported_field
阅读器将返回该字段的名称:
MyModel.imported_field
#=> 'some_field'
然后,您InstanceMethods
可以在实例方法中设置导入字段的值,方法是将字段名称传递给write_attribute
,并使用以下方法获取值read_attribute
:
m = MyModel.new
m.write_attribute(m.class.imported_field, "some value")
m.some_field
#=> "some value"
m.read_attribute(m.class.importable_field)
#=> "some value"
希望有帮助。不过,这只是我个人对此的看法,还有其他方法可以做到这一点(我也有兴趣了解它们)。