如何为rails问题添加特定于模型的配置选项?

Col*_*Col 9 ruby-on-rails

我正在为我的rails项目编写一个可导入的问题.这个问题将为我提供一种将csv文件导入包含Importable的任何模型的通用方法.

我需要一种方法让每个模型指定导入代码应该使用哪个字段来查找现有记录.是否有任何建议的方法可以为关注点添加此类配置?

Tom*_*son 11

一个稍微"看起来像香草"的解决方案,我们这样做(巧合的是,对于正好一些csv导入问题),以避免需要将参数传递给Concern.我确信错误提升抽象方法有利有弊,但它会将所有代码保存在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
Run Code Online (Sandbox Code Playgroud)

在有关注的模型中:

class Exemption < ActiveRecord::Base
  include CsvImportable

  # ...

private
  def some_method_that_differs_by_target_class
    # real implementation here
  end
end
Run Code Online (Sandbox Code Playgroud)


Chr*_*erg 9

我建议创建一个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
Run Code Online (Sandbox Code Playgroud)

然后,您需要ActiveRecord使用此模块进行扩展,例如将此行放在初始化器(config/initializers/active_record.rb)中:

ActiveRecord::Base.extend(Importable::ActiveRecord)
Run Code Online (Sandbox Code Playgroud)

(如果问题出在您的config.autoload_paths身上,那么您不需要在此处提出要求,请参阅下面的评论.)

然后在你的模型中,你会包括Importable这样的:

class MyModel
  include_importable 'some_field'
end
Run Code Online (Sandbox Code Playgroud)

imported_field读者将返回字段的名称:

MyModel.imported_field
#=> 'some_field'
Run Code Online (Sandbox Code Playgroud)

在您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"
Run Code Online (Sandbox Code Playgroud)

希望有所帮助.这只是我对此的个人看法,但还有其他方法可以做到(我也有兴趣了解它们).

  • 问题是`ActiveRecord :: Base.extend(Importable :: ActiveRecord)`行,在加载模型之前必须调用*,以便ActiveRecord具有`includes_importable`方法.自动加载不起作用,因为模型代码中未提及实际的`可导入`模块名称.有几种方法可以解决这个问题,我想最简单的方法是在`config/initializers/active_record.rb`中创建一个初始化器,并在那里移动`extend`行,并在`require'instions/importable'`处于顶端.然后,您不必在模型中要求它. (2认同)