2012-11-11 16 views
5

Mam app Rails z kilku modeli o tej samej strukturze:Rozszerzanie klasy Ruby z samodzielny fragment kodu

class Item1 < ActiveRecord::Base 
    WIDTH = 100 
    HEIGHT = 100 
    has_attached_file :image, styles: {original: "#{WIDTH}x#{HEIGHT}"} 
    validates_attachment :image, :presence => true 
end 


class Item2 < ActiveRecord::Base 
    WIDTH = 200 
    HEIGHT = 200 
    has_attached_file :image, styles: {original: "#{WIDTH}x#{HEIGHT}"} 
    validates_attachment :image, :presence => true 
end 

Rzeczywisty kod jest bardziej skomplikowana, ale to wystarczy dla prostoty.

Myślę, że mogę umieścić wspólną część kodu w jednym miejscu, a następnie użyć go we wszystkich modelach.

Oto, co przychodzi mi na myśl:

class Item1 < ActiveRecord::Base 
    WIDTH = 100 
    HEIGHT = 100 
    extend CommonItem 
end 

module CommonItem 
    has_attached_file :image, styles: {original: "#{WIDTH}x#{HEIGHT}"} 
    validates_attachment :image, :presence => true 
end 

Oczywiście to nie działa z dwóch powodów:

  1. CommonItem nie ma pojęcia o metodach klasy modlę.
  2. Styki są wyszukiwane w CommonItem zamiast Item1.

Próbowałem użyć include zamiast extend, niektóre sposoby class_eval i dziedziczenia klas, ale prace none.

Wygląda na to, że brakuje mi czegoś oczywistego. Proszę powiedz mi, co.

+2

http://api.rubyonrails.org/ classes/ActiveSupport/Concern.html jest stworzony dla takich rzeczy. – jdoe

Odpowiedz

3

Oto jak zrobiłbym to:

class Model 
    def self.model_method 
    puts "model_method" 
    end 
end 

module Item 
    def self.included(base) 
    base.class_eval do 
     p base::WIDTH, base::HEIGHT 
     model_method 
    end 
    end 
end 

class Item1 < Model 
    WIDTH = 100 
    HEIGHT = 100 
    include Item 
end 

class Item2 < Model 
    WIDTH = 200 
    HEIGHT = 200 
    include Item 
end 

Sposób included nazywa na module, gdy jest włączone.

Myślę, że udało mi się stworzyć podobną strukturę, która ma twój problem. Moduł wywołuje metodę dziedziczoną przez klasy elementów z klasy Model.

wyjściowa:

100 
100 
model_method 
200 
200 
model_method 
+0

Nice! Korzystanie z haka 'self.included' nie przychodzi mi na myśl. To na pewno rozwiązanie. – Ivan

2

W Ruby konstrukt użyć do ekstrakcji powtarza się kod w jednym urządzeniu jest sposób:

class Model 
    def self.model_method 
    p __method__ 
    end 

    private 

    def self.item 
    p self::WIDTH, self::HEIGHT 
    model_method 
    end 
end 

class Item1 < Model 
    WIDTH = 100 
    HEIGHT = 100 
    item 
end 

class Item2 < Model 
    WIDTH = 200 
    HEIGHT = 200 
    item 
end 
+1

Czy osoba zainteresowana powinna wyjaśnić? Ten kod doskonale rozwiązuje problem OP, ma dokładnie takie samo zachowanie jak kod @ Dogberta, a jednocześnie jest znacznie prostszy i nie wymaga żadnej metaprogramowania, odbicia ani haków. –