2010-08-29 4 views
6

Ich habe dieses Wochenende mit der Liquid-Template-Engine herumgespielt, und ich frage mich, ob das Folgende möglich ist.Übergeben von Variablen zum Modellieren von Instanzmethoden in Liquid-Vorlagen

Angenommen, ich habe eine latest_posts Methode in einem Blog Modell, das ich eine Ganzzahl übergeben kann, um die neuesten N Beiträge zu erhalten. Ist es möglich, diese Methode in einer flüssigen Vorlage zu verwenden?

Zum Beispiel:

class Blog 

    has_many :posts 

    def latest_posts(n) 
    posts.latest(n) # using a named scope 
    end 

    def to_liquid(*args) 
    { 
     'all_posts' => posts.all, # allows me to use {% for posts in blog.all_posts %} 
     'last_post' => post.last, # allows me to use {% assign recent = blog.last_post %} 
     'latest_posts' => posts.latest_posts(args[0]) # how do I pass variables to this? 
    } 
    end 

end 

In dem vereinfachten Beispiel oben, in meinen flüssigen Vorlagen kann ich blog.all_posts und blog.last_post, habe aber keine Ahnung, wie ich so etwas wie blog.latest_posts: 10 tun würde.

Kann mir jemand in die richtige Richtung zeigen?

Eine Idee, an die ich gedacht habe, war, einen Liquid-Filter zu erstellen und sowohl das Blog-Objekt als auch eine ganze Zahl zu übergeben. Etwas wie:

{% for post in blog | latest_posts(10) %} 
  • aber nicht versucht haben, dass noch als Gefühl, wie ich bin Messerstecherei im Dunkeln ein wenig. Ich würde etwas Hilfe von erfahreneren Liquid-Benutzern zu schätzen wissen.

Antwort

9

hier meine eigene Frage zu beantworten, fand ich eine Lösung in den Liquid groups pages dokumentiert.

Im Wesentlichen musste ich einen Tropfen für die neuesten Beiträge erstellen - a LatestPostsDrop - und Art des Hacks eine Variable an sie mit der before_method Methode übergeben.Dies ist die komplette Lösung:

class Blog 

    has_many :posts 

    def latest_posts 
    LatestPostsDrop.new(posts) 
    end 

    def to_liquid 
    { 
     'all_posts' => posts.all, 
     'last_post' => post.last, 
     'latest_posts' => latest_posts 
    } 
    end 

end 

class LatestPostsDrop < Liquid::Drop 

    def initialize(posts) 
    @posts = posts 
    end 

    def before_method(num) 
    @posts.latest(num) # Post.latest is a named scope 
    end 

end 

die oben tun, können Sie durch eine beliebige Anzahl von neuesten Beiträge wie mit etwas iterieren:

{% for post in blog.latest_posts.10 %} # the last attribute can be any integer 
    <p>{{ post.title }}</p> 
{% endfor %} 

Es scheint ein wenig hacky, aber es funktioniert :)

+1

Danke für die Infos zum before_method. Ich stimme zu, dass es ein wenig hacky ist, aber denken Sie daran, dass der Fokus für Liquid die Vorlage ist, nicht die Maschinerie hinter der Vorlage. Die Absicht besteht darin, anderen Gruppen von Personen zu ermöglichen, nur die Vorlagensprache zu verwenden, um nützliche/anspruchsvolle Ansichten von Daten auf eine sichere Weise zu machen. Ich denke, es ist sehr gut dafür - sowohl meine Kunden als auch ihre Vertragspartner verwenden Liquid-Templates mit meinen SAAS-Daten. –

5

Ich denke, dass Flüssigkeit ein fantastisches Schablonensystem ist. Herzlichen Glückwunsch zu untersuchen/zu verwenden.

Standardmäßig ist keine der Methoden des Modells für die flüssige Vorlage verfügbar. Das ist eine gute Sache. Sie geben dann an, welche Methoden verfügbar sein sollen. (Eine weiße Liste.)

Ich benutze eine Erweiterung zu Modul, die auf der Mailing-Liste gesendet wurde. Die vollständige Erweiterung ist unten. Es verarbeitet die Liquid :: Drop-Erstellung für Sie, indem es Klassen und Modulen eine einfache # liquid_methods-Methode hinzufügt.

Dann in Ihren Modellen, nur tun:

class Blog 
    # id 
    # name 
    has_many :posts 

    def latest_posts(n) 
    posts.latest(n) # using a named scope 
    end 

    def latest_10_posts;latest_posts(10); end 

    liquid_methods :id, :name, :posts, :latest_10_posts 
end 

Ich bin nicht sicher freihändig wie/ob Sie params in einen Tropfen passieren kann. Fragen Sie auf der Liquid-Mailing-Liste. Ich glaube du kannst.

Hinzugefügt: ich jetzt Ihre Frage neu lesen und sehen, dass Sie wirklich das Verfahren in diesem param senden mögen. Sie können mehr als ein Argument/Parameter an einen Liquid-Filter senden. So könnten Sie einen Filter:

# Define as a Liquid filter 
def latest_posts(blog, n) 
    blog.latest(n) 
end 

# then call the filter in a template: 
{{ blog2 | latest_posts: 10 }} 
# Note that the second param is after the filter name. 

In diesem Beispiel auch daran denken, dass Sie zu flüssig Methoden im Post Klasse zu erklären brauchen.

Hier ist die Modulerweiterung.

# By dd -- http://groups.google.com/group/liquid-templates/browse_thread/thread/bf48cfebee9fafd9 
# This extension is usesd in order to expose the object of the implementing class 
# to liquid as it were a Drop. It also limits the liquid-callable methods of the instance 
# to the allowed method passed with the liquid_methods call 
# Example: 
# 
# class SomeClass 
# liquid_methods :an_allowed_method 
# 
# def an_allowed_method 
#  'this comes from an allowed method' 
# end 
# def unallowed_method 
#  'this will never be an output' 
# end 
# end 
# 
# if you want to extend the drop to other methods you can define more methods 
# in the class <YourClass>::LiquidDropClass 
# 
# class SomeClass::LiquidDropClass 
#  def another_allowed_method 
#  'and this is another allowed method' 
#  end 
# end 
# end 
# 
# usage: 
# @something = SomeClass.new 
# 
# template: 
# {{something.an_allowed_method}}{{something.unallowed_method}}{{something.another_allowed_method}} 
# 
# output: 
# 'this comes from an allowed method and this is another allowed method' 
# 
# You can also chain associations, by adding the liquid_method calls in the 
# association models. 
# 
class Module 

    def liquid_methods(*allowed_methods) 
    drop_class = eval "class #{self.to_s}::LiquidDropClass < Liquid::Drop; self; end" 
    define_method :to_liquid do 
     drop_class.new(self) 
    end 

    drop_class.class_eval do 
     allowed_methods.each do |sym| 
     define_method sym do 
      @object.send sym 
     end 
     end 
     def initialize(object) 
     @object = object 
     end 
    end 

    end 
end 
+0

Hallo Larry, danke für deine Eingabe. Ich habe versucht, mit Ihrem zusätzlichen Vorschlag herumzukommen, konnte aber nicht zufriedenstellend arbeiten. '{{Blog | latest_posts: 10}} würde in der Tat die letzten 10 Beiträge zurückgeben. Ich konnte jedoch nicht herausfinden, wie ich sie durchlaufen könnte: '{% für Beiträge in (blog | latest_posts: 10)%}' (oder Variationen in diesem Thema) hat die Beiträge einfach nicht durchlaufen. Allerdings fand ich eine [Lösung hier] (http://groups.google.com/group/liquid-templates/browse_thread/thread/90ae684e754b6de5/1b080bcff95ed59d?lnk=gst&q=pass+variable+to+drop#1b080bcff95ed59d) Das werde ich in eine Antwort unter ... setzen. – aaronrussell

+0

Ich fand, dass ich die Ergebnisse des Filters in einer Variablen speichern musste und dann konnte ich über die Variable iterieren: '{% assign next_blog_posts = blog | latest_posts: 10%} 'dann' {% for post in latest_blog_posts%} ... ' –