2010-11-21 19 views
3

Ich habe eine Situation, wo ich "parametrische" Modelle in Schienen machen möchte; zum Beispiel würde ich gerne PrototypeRecipe definieren, und dann in der Lage sein, mehrere DerivedRecipe's zu machen; vielleicht verwendet ein abgeleitetes Rezept mehr Zucker und ein anderes verwendet weniger Eier oder etwas. Der kritische Punkt ist, dass ich möchte, dass alle 'abgeleiteten' Instanzen Eigenschaften von einem einzigen freigegebenen PrototypeRecipe erben, aber in der Lage sein müssen, lokale Modifikationen vorzunehmen.Schienen Modell Vorlagen (oder Instanz Vererbung) Optionen?

Idealerweise würde ich gerne Methoden für den Prototyp definieren (zB eine Einkaufsliste zusammenstellen) und diese Methoden auf lokale Änderungen in abgeleiteten Instanzen reagieren lassen (also wenn ich 3 Eier anstelle von 2 angegeben habe , könnte ich die make_shopping_list Funktion des Prototyps nennen und es würde das reflektieren).

Gibt es eine existierende Methode, um so etwas zu erreichen? Hier ist das Beste, was ich mit so weit kommen können:

class Ingredient << ActiveRecord::Base 
    belongs_to :recipe, :polymorphic => true 

    # uuid => UUID String (for grouping ingredients which change between prototype and derived instances) 
end 

class PrototypeRecipe << ActiveRecord::Base 
    has_many :ingredients 

    def make_ingredient_list(derived_recipe = nil) 
     self.ingredients.map {|i| derived_recipe.nil? ? i : derived_recipe.ingredients.where(:ingredient_uuid => i.uuid).first } 
    end 
end 

class DerivedRecipe << ActiveRecord::Base 
    belongs_to :prototype_recipe 

    has_many :ingredients 

    def method_missing(sym, *args) 
     self.prototype_recipe.send(sym, *args, self) 
    end 
end 

Ich weiß, dass dieser Code kann viel sauberer gemacht werden, frage ich mich mehr, wenn der allgemeine Ansatz verbessert werden kann auf. Die Grundidee ist, dass Zutaten jeweils eine eindeutige ID haben. Um ein Prototyprezept zu modifizieren, erstellen Sie einfach eine Instanz von DerivedRecipe, verknüpfen diese mit dem Prototyp und fügen dann eine Zutat mit derselben UUID wie eine der Zutaten des Prototyps hinzu.

+0

du meinst '<' ... nicht '<<' – Tilo

Antwort

0

Ich bin nicht 100% auf, was Verhalten Sie suchen, also hier ist meine versuchte Lösung.

Single-Table-Vererbung (STI). Ihre Basisklasse ist PrototypeRecipe und Ihre Kindklasse ist DerivedRecipe. Geben Sie in Ihrer prototype_recipes Tabelle eine type Spalte (Text) ein. Dies signalisiert Rails, dass Sie STI verwenden möchten. Wenn Sie Ihre make_ingredients_list-Methode in die Basisklasse einfügen, können Sie auf Ihre untergeordneten Klassen zugreifen.

# app/models/ingredient.rb 
class Ingredient < ActiveRecord::Base 
    belongs_to :recipe, :class_name => "PrototypeRecipe" 
    ... 
end 

# app/models/prototype_recipe.rb 
class PrototypeRecipe < ActiveRecord::Base 
    has_many :ingredients 
    has_many :derived_recipes 

    def make_ingredient_list 
    ... 
    end 
end 

# app/models/derived_recipe.rb 
class DerivedRecipe < PrototypeRecipe 
    belongs_to :prototype_recipe 
end 

Jetzt können Sie so etwas wie:

@cupcakes = PrototypeRecipe.create 
@cupcakes_with_extra_eggs = @cupcakes.derived_recipes.create 
print @cupcakes_with_extra_eggs.make_ingredient_list 

Ist das, was Sie suchen?