2012-08-14 4 views
5

Ich habe ein Spielmodell, das has_many: Texte hat. Das Problem ist, dass ich die Texte anders bestellen muss, je nachdem, zu welchem ​​Spiel sie gehören (ja, hässlich, aber es sind alte Daten). Ich habe eine Text.in_game_order_query(game) Methode erstellt, die die entsprechende Reihenfolge zurückgibt.Bezug nehmend auf Instanz in has_many (Schienen)

Meine Lieblingslösung wäre gewesen, einen Standardbereich in das Textmodell zu setzen, aber das würde erfordern, zu wissen, zu welchem ​​Spiel sie gehören. Ich möchte auch keine separaten Klassen für die Texte für jedes Spiel erstellen - es gibt viele Spiele, mit mehr kommen, und alle neueren werden die gleiche Reihenfolge verwenden. So hatte ich eine andere Idee: Texte in der has_many Bestellung, wenn weiß ich, welches Spiel sie sind Teil von:

has_many :texts, :order => Text.in_game_order_query(self) 

jedoch selbst ist die Klasse hier, so das nicht funktioniert.

Gibt es wirklich keine andere Lösung als @game.texts.in_game_order(@game) jedes Mal aufrufen ??

Antwort

-1

Ich denke, wenn Sie Laufzeit wollen Informationen verarbeitet, sollten Sie dies mit getan:

has_many :texts, :order => proc{ {Text.in_game_order_query(self)} } 
+0

Die doppelten geschweiften Klammern geben mir einen Syntaxfehler, und mit nur einer Menge von {} um es heißt "Kann Proc nicht besuchen". – Sprachprofi

+0

Sorry Tippfehler. Nur eine Reihe von Klammern. Aber ich bin mir nicht sicher, ob das klappt: Ordnung überhaupt. Ich benutze es mit: Bedingungen. Vielleicht, wenn proc nicht funktioniert, versuchen Lambda oder Proc. Neu –

0

Hier ist eine Möglichkeit, wo Sie es tun können,

has_many :texts, :order => lambda { Text.in_game_order_query(self) } 

Dies ist ein weiterer Weg ist, die ich in der Regel wird nicht empfohlen (aber funktioniert),

has_many :texts do 
    def game_order(game) 
    find(:all, :order => Text.in_game_order_query(game)) 
    end 
end 

und Sie können sie durch nennen,

game.texts.game_order(game) 
+0

"Kann Proc nicht besuchen" :-( – Sprachprofi

+0

versuchen mit, 'has_many: Texte, Lambda {{: order => Text.in_game_order_query (self)}}' – PradeepKumar

+0

"falsch Anzahl der Argumente (1 für 0) "- Ich fange an zu denken, dass es nicht möglich ist :-(Ich habe auch versucht, diese Funktion in das Game-Modell zu verschieben, so dass ich self.in_game_order_query machen kann, ohne ein Argument übergeben zu müssen kein Glück. – Sprachprofi

0

Ich bin nicht sicher, was Ihr Auftrag/Abfrage sieht aus wie in der in_game_order_query Klassenmethode, aber ich glaube, dass Sie dieses Bild Gerade

has_many :texts, :finder_sql => proc{Text.in_game_order_query(self)} 

tun können, so dass Sie wissen, dass ich das noch nie verwendet haben, aber ich würde schätzen Sie es, wenn Sie mich wissen lassen, ob das für Sie funktioniert oder nicht.

Check out http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many für weitere Dokumentation: finder_sql

1

Würde ein Association extension eine Möglichkeit?

Es scheint, dass Sie diese Arbeit machen könnte:

module Legacy 
    def legacy_game_order 
    order(proxy_association.owner.custom_texts_order) 
    end 
end 

class Game << ActiveRecord::Base 
    includes Legacy 
    has_many :texts, :extend => Legacy 

    def custom_texts_order 
    # your custom query logic goes here 
    end 
end 

So ein Spiel Beispiel gegeben, sollten Sie in der Lage sein Instanz benutzerdefinierte Abfrage zuzugreifen, ohne in Selbst passieren zu müssen:

g = Game.find(123) 
g.texts.legacy_game_order 
3

Follow-up mit PradeepKumar Idee, fand ich die folgende Lösung zu arbeiten

Angenommen, eine Klasse Block, die ein Attribut block_type hat, und eine co ntainer Klasse (sagen Seite), können Sie so etwas wie dieses haben könnte:

class Page 
    ... 

    has_many :blocks do 
    def ordered_by_type 
     # self is the array of blocks 
     self.sort_by(&:block_type) 
    end 
    end 

    ... 
end 

Dann, wenn Sie anrufen

page.blocks.ordered_by_type 

Sie bekommen, was Sie wollen - von einem Proc definiert. Offensichtlich könnte der Proc viel komplexer sein und funktioniert nicht im SQL-Aufruf, aber nachdem dort die Ergebnismenge kompiliert wurde.

UPDATE:
Ich las diesen Beitrag und meine Antwort nach einer Menge Zeit, und ich frage mich, wenn Sie etwas so einfaches wie eine andere Methode tun könnte, die Sie im Grunde selbst in der Post vorgeschlagen.

Was ist, wenn Sie eine Methode, um Gameordered_texts

def ordered_texts 
    texts.in_game_order(self) 
    end 

Does, die das Problem lösen genannt hinzugefügt? Oder muss diese Methode mit anderen Game Beziehungsmethoden verknüpft werden können?

3

Ich hatte vor kurzem ein sehr ähnliches Problem und ich war überzeugt, dass es in Rails nicht möglich war, aber dass ich etwas sehr interessantes gelernt habe.

Sie können einen Parameter für einen Bereich deklarieren und ihn dann nicht übergeben und er wird standardmäßig im übergeordneten Objekt übergeben!

So können Sie gerade tun:

class Game < ActiveRecord 
    has_many :texts, -> (game) { Text.in_game_order_query(game) } 

glauben oder nicht, Sie nicht im Spiel passieren müssen. Schienen werden es magisch für dich tun. Sie können einfach tun:

game.texts 

Es gibt einen Vorbehalt, obwohl. Dies funktioniert derzeit nicht in Rails, wenn Sie das Preloading aktiviert haben. Wenn Sie dies tun, erhalten Sie möglicherweise diese Warnung:

Warnung: Der Assoziationsbereich 'Texte' ist Instanz abhängig (der Umfang Block nimmt ein Argument). Das Vorladen findet statt, bevor die einzelnen Instanzen erstellt werden. Dies bedeutet, dass keine Instanz an den Assoziationsbereich übergeben wird. Dies führt höchstwahrscheinlich zu fehlerhaftem oder falschem Verhalten. Joining, Preloading und das eifrige Laden dieser Verknüpfungen ist veraltet und wird in Zukunft entfernt.

Verwandte Themen