2012-11-11 9 views
5

Ho un'applicazione Rails con diversi modelli con la stessa struttura:Estensione di una classe di rubino con un pezzo di codice autonomo

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 

Il codice attuale è più complicato, ma che è abbastanza per semplicità.

Penso di poter inserire la parte comune del codice in un unico punto e quindi utilizzarlo in tutti i modelli.

Ecco quello che mi viene in mente:

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 

Ovviamente non funziona per due motivi:

  1. CommonItem ha alcuna idea su metodi di classe invoco.
  2. WIDTH e HEIGHT le costanti sono ricercate in CommonItem anziché Item1.

ho provato ad usare include invece di extend, alcuni modi di class_eval e ereditarietà di classe, ma nessuna funziona.

Sembra che manchi qualcosa di ovvio. Per favore dimmi cosa.

+2

http://api.rubyonrails.org/ classes/ActiveSupport/Concern.html è fatto per cose come questa. – jdoe

risposta

3

Ecco come lo farei:

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 

Il metodo included viene chiamato su un modulo in cui è incluso.

Penso di essere riuscito a creare una struttura simile a quella del problema. Il modulo sta chiamando il metodo ereditato dalle classi items dalla classe Model.

uscita:

100 
100 
model_method 
200 
200 
model_method 
+0

Bello! L'uso del gancio "self.included" non mi è venuto in mente ... Questa è sicuramente una soluzione. – Ivan

2

In Ruby, il costrutto di estrarre codice ripetuto in una singola unità è un metodo :

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

Il downlocoter spiegherebbe? Questo codice risolve perfettamente il problema dell'OP, ha lo stesso identico comportamento del codice di @ Dogbert pur essendo molto più semplice e non richiede alcuna forma di metaprogrammazione, riflessione o hook. –

Problemi correlati