我正在爲我的rails項目編寫一個可導入的關注過程。這種擔心將爲我提供一種通用的方式,將csv文件導入到任何包含Importable的模型中。如何將特定模型配置選項添加到導軌問題?
我需要爲每個模型指定導入代碼應該使用哪個字段來查找現有記錄。是否有任何推薦的方式爲關注添加這種類型的配置?
我正在爲我的rails項目編寫一個可導入的關注過程。這種擔心將爲我提供一種通用的方式,將csv文件導入到任何包含Importable的模型中。如何將特定模型配置選項添加到導軌問題?
我需要爲每個模型指定導入代碼應該使用哪個字段來查找現有記錄。是否有任何推薦的方式爲關注添加這種類型的配置?
而不是包括每個模型的關注,我建議建立一個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"
希望有所幫助。這只是我個人對此的看法,不過,還有其他方法可以做到這一點(我也有興趣瞭解它們)。
我們這樣做(巧合的是,對於某些csv導入問題),避免將參數傳遞給Concern需要稍微更「看上去」的解決方案。我確信這個錯誤提升抽象方法有優點和缺點,但它保留了應用程序文件夾中的所有代碼以及您希望找到它的模型。
在 「關注」 模塊,只是基礎知識:
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
我更喜歡這個變體,尤其是如果關注的是應用程序特定的(不是在寶石中),也不包括在很多其他模型中。 – srecnig
大回答,謝謝。這一切都有道理。我會嘗試明天提出的建議,並在此之後頒發解決方案。 – Col
這一切都工作,但我有一個小問題。除非我在每個模型文件的頂部特別要求'疑慮/可導入',否則我會得到以下錯誤。 NameError:未定義局部變量或方法'include_importable」爲#<類別:0x007fc1bdb8dc20> 我已經添加了關注目錄到autoload_path像這樣: config.autoload_paths + = DIR [「#{config.root}/app/models/** /「] 這不是一個大問題,但我不希望在任何地方都需要它。有什麼建議麼? – Col
問題是'ActiveRecord :: Base.extend(Importable :: ActiveRecord)'行,在加載模型之前必須調用*,以便ActiveRecord具有'includes_importable'方法。自動加載不起作用,因爲您的模型代碼中沒有提到實際的'Importable'模塊名稱。有幾種方法可以解決這個問題,我猜最簡單的方法是在'config/initializers/active_record.rb'處創建一個初始化器,然後將'extend'行移到那裏,在'require'/ importable'處頂端。那麼你不必在你的模型中要求它。 –