2013-01-13 12 views
9

我正在爲我的rails項目編寫一個可導入的關注過程。這種擔心將爲我提供一種通用的方式,將csv文件導入到任何包含Importable的模型中。如何將特定模型配置選項添加到導軌問題?

我需要爲每個模型指定導入代碼應該使用哪個字段來查找現有記錄。是否有任何推薦的方式爲關注添加這種類型的配置?

回答

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 

然後,您需要使用這個模塊擴展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" 

希望有所幫助。這只是我個人對此的看法,不過,還有其他方法可以做到這一點(我也有興趣瞭解它們)。

+0

大回答,謝謝。這一切都有道理。我會嘗試明天提出的建議,並在此之後頒發解決方案。 – Col

+0

這一切都工作,但我有一個小問題。除非我在每個模型文件的頂部特別要求'疑慮/可導入',否則我會得到以下錯誤。 NameError:未定義局部變量或方法'include_importable」爲#<類別:0x007fc1bdb8dc20> 我已經添加了關注目錄到autoload_path像這樣: config.autoload_paths + = DIR [「#{config.root}/app/models/** /「] 這不是一個大問題,但我不希望在任何地方都需要它。有什麼建議麼? – Col

+2

問題是'ActiveRecord :: Base.extend(Importable :: ActiveRecord)'行,在加載模型之前必須調用*,以便ActiveRecord具有'includes_importable'方法。自動加載不起作用,因爲您的模型代碼中沒有提到實際的'Importable'模塊名稱。有幾種方法可以解決這個問題,我猜最簡單的方法是在'config/initializers/active_record.rb'處創建一個初始化器,然後將'extend'行移到那裏,在'require'/ importable'處頂端。那麼你不必在你的模型中要求它。 –

9

我們這樣做(巧合的是,對於某些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 
+0

我更喜歡這個變體,尤其是如果關注的是應用程序特定的(不是在寶石中),也不包括在很多其他模型中。 – srecnig

相關問題