2013-01-13 11 views
9

Jestem w trakcie pisania uwagi dotyczącej importu dla mojego projektu szyn. Ta troska zapewni mi ogólny sposób importowania pliku csv do dowolnego modelu, który zawiera Importable.Jak dodać opcję konfiguracji specyficznej dla modelu do koncernu rails?

muszę zrobić miejsce dla każdego modelu, aby określić, które pola kod import powinien użyć, aby znaleźć istniejące rekordy. Czy są jakieś zalecane sposoby dodawania tego typu konfiguracji do problemu?

Odpowiedz

9

Zamiast tym zaniepokojenie w każdym modelu, którą proponujemy stworzenie ActiveRecord submodule i przedłużyć ActiveRecord::Base z nim, a następnie dodać metodę w tym modułem (słownie include_importable), który robi to w tym. Następnie można podać nazwę pola jako argument tej metody, a także w sposobie definiowania zmiennej instancji i akcesor (powiedzmy na przykład importable_field), aby zapisać nazwę pola dla odniesienia w swoim Importable klasy i metody instancji.

Więc coś takiego:

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 

Będziesz wtedy trzeba przedłużyć ActiveRecord z tego modułu, powiedzmy, umieszczając tę ​​linię do inicjowania (config/initializers/active_record.rb):

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

(Jeśli problem dotyczy Twojego config.autoload_paths, więc nie powinieneś tego wymagać, patrz komentarze poniżej.)

Następnie w swoich modelach, yo U obejmowałyby Importable takiego:

class MyModel 
    include_importable 'some_field' 
end 

a czytelnik imported_field zwróci nazwę pola:

MyModel.imported_field 
#=> 'some_field' 

W swojej InstanceMethods można następnie ustawić wartość pola importowanego w instancji metody przekazując nazwę pola do write_attribute i uzyskać wartość używając 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" 

Nadzieję, że pomaga. To tylko moje osobiste zdanie na ten temat, istnieją jednak inne sposoby, aby to zrobić (i byłbym zainteresowany, aby o nich usłyszeć).

+0

Wielkiej odpowiedź, dziękuję. To wszystko ma sens. Spróbuję tego, co zasugerowałeś jutro i nagrodzisz rozwiązanie po tym. – Col

+0

Wszystko działa, ale mam mały problem. Otrzymuję następujący błąd, chyba że specjalnie wymagam "dotyczy/importable" na górze każdego pliku modelu. NameError: niezdefiniowana zmienna lokalna lub metoda 'include_importable” dla # Dodałem katalog obawy do autoload_path tak: config.autoload_paths + = Dir [ "# {config.root}/app/models/**/"] To nie jest duży problem, ale wolałbym nie wymagać go wszędzie. Jakieś sugestie? – Col

+2

Problemem jest linia 'ActiveRecord :: Base.extend (Importable :: ActiveRecord)', która musi zostać wywołana * przed * twoje modele są ładowane, aby ActiveRecord miał metodę 'includes_importable'. Automatyczne ładowanie nie działa, ponieważ rzeczywista nazwa modułu "Importable" nie jest wymieniona w kodzie modelu. Istnieje kilka sposobów na rozwiązanie tego problemu. Najłatwiej jest utworzyć inicjator w 'config/initializers/active_record.rb' i przenieść tam linię' extend' z 'require 'concern/importable'' at szczyt. Wtedy nie będziesz musiał tego wymagać w swoich modelach. –

9

Nieco bardziej "waniliowe" rozwiązanie, robimy to (przypadkowo, dokładnie w przypadku niektórych problemów z importowaniem csv), aby uniknąć konieczności przekazywania argumentów do Koncernu. Jestem pewny, że są pewne plusy i minusy dla metody abstrakcyjnego podnoszenia błędów, ale zachowuje ona cały kod w folderze aplikacji i modelach, w których spodziewasz się go znaleźć.

W module "zainteresowania", tylko podstawy:

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 

A w modelu mającego dotyczyć:

class Exemption < ActiveRecord::Base 
    include CsvImportable 

    # ... 

private 
    def some_method_that_differs_by_target_class 
    # real implementation here 
    end 
end 
+0

Ten wariant lepiej mi się podoba, zwłaszcza jeśli obawy dotyczą konkretnej aplikacji (nie w klejnocie) i nie są zawarte w wielu innych modelach. – srecnig

Powiązane problemy