2013-01-13 15 views
9

Raylarım projem için bir İçe Aktarılabilir endişe yazma aşamasındayım. Bu endişe, bir csv dosyasını İçe Aktarılabilir'i içeren herhangi bir modele aktarmak için genel bir yol sağlayacaktır.Raylara yönelik bir modele nasıl bir modele özgü yapılandırma seçeneği eklerim?

Her model için, içe aktarma kodunun varolan kayıtları bulmak için hangi alanı kullanması gerektiğini belirleme yöntemine ihtiyacım var. Bu tür bir yapılandırmayı endişe için eklemenin herhangi bir yolu var mı?

cevap

9

Aksine her modelde endişe dahil daha, bir ActiveRecord submodule oluşturma öneririm ve onunla ActiveRecord::Base uzatmak ve daha sonra dahil yapar (include_importable diyelim) o alt modülün bir yöntemi ekleyin. Daha sonra, alan adını bu yönteme argüman olarak iletebilirsiniz ve yöntemde, Importable sınıf ve örnek yöntemlerinde başvuru için alan adını kaydetmek için bir örnek değişkeni ve erişimcisi (örneğin, importable_field) tanımlayın.

Yani böyle bir şey: Eğer (

ActiveRecord::Base.extend(Importable::ActiveRecord) 

:

Daha sonra bu modül ile ActiveRecord uzatmak gerekir
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 

, bir başlatıcısı (config/initializers/active_record.rb) bu satırı koyarak söylemek Endişeniz, config.autoload_paths numaranızdadır, daha sonra, burada gereksinim duymanız gerekmemelidir, aşağıdaki yorumları görün.)

Modellerinizde, imported_field okuyucu alanının adını döndürür

class MyModel 
    include_importable 'some_field' 
end 

Ve: u böyle Importable yer alacağını sizin InstanceMethods yılında

MyModel.imported_field 
#=> 'some_field' 

, daha sonra örneğinde ithal alanın değerini ayarlayabilirsiniz write_attribute için alanın adını geçirmeden ve almak tarafından yöntemleri değeri read_attribute kullanarak:

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" 

Umarım yardımcı olur. Bu sadece benim kişisel aldığım budur, ancak bunu yapmanın başka yolları da vardır (ve ben de onlar hakkında duymak isterim).

+0

Büyük cevap, teşekkür ederim. Hepsi mantıklı. Yarın önerdiğin şeyi deneyeceğim ve bundan sonra çözümü vereceğim. – Col

+0

Her şey çalışıyor ama benim küçük bir sorunum var. Her model dosyasının üstünde özellikle 'kaygılar/içe aktarılabilir' gerektirmedikçe aşağıdaki hatayı alıyorum. NameError: tanımsız yerel değişken veya # yöntemi ''include_importable Ben şöyle autoload_path için endişeler dizini ekledik : config.autoload_paths + = Dir [" # {config.root}/app/models/**/"] Bu büyük bir sorun değil ama her yerde buna gereksinim duymamayı tercih ediyorum. Baska öneri? – Col

+2

Sorun, * ActiveRecord :: Base.extend (İçe Aktarılabilir :: ActiveRecord) 'satırı, daha önce çağrılması gereken * * modelleriniz ActiveRecord'un" includes_importable "yöntemine sahip olması için yüklenir. Autoloading çalışmıyor, çünkü '' Importable' modülünün adı model kodunuzda belirtilmemiş. Sorunu çözmenin birkaç yolu var, sanırım en kolayı 'config/initializers/active_record.rb' adresinde bir başlatıcı oluşturmak ve 'extend' satırını oraya taşımak; üst. Daha sonra, modelinizde buna ihtiyacınız olmayacak. –

9

Biraz daha "vanilya görünümlü" çözümü olmamakla birlikte, (tesadüfen, tam bir csv ithalat sorunu için) Endişe argümanlar geçen ihtiyacını önlemek için yapıyoruz. Eminim ki, hata-arttıncı soyut yöntemin artıları ve eksileri vardır, fakat tüm kodu uygulama klasöründe ve bulmayı beklediğiniz modellerde tutar. "Endişe" modülünde

, sadece temelleri:
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 

Ve endişeyi sahip modelde

:

class Exemption < ActiveRecord::Base 
    include CsvImportable 

    # ... 

private 
    def some_method_that_differs_by_target_class 
    # real implementation here 
    end 
end 
+0

Bu çeşidi daha iyi seviyorum, özellikle de endişe uygulamaya özgü (gemide değil) ve diğer birçok modelde yer almıyorsa. – srecnig

İlgili konular