2010-08-29 12 views
6

He estado jugando con el motor de plantillas Liquid este fin de semana, y me pregunto si lo siguiente es posible.Pasando variables para modelar métodos de instancia en plantillas de Liquid

Supongo que tengo un método latest_posts en un modelo Blog, que puedo pasar un número entero para obtener las últimas N publicaciones. ¿Es posible usar ese método en una plantilla líquida?

Por ejemplo:

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 

En el ejemplo simplificado anterior, en mis plantillas de líquidos que pueda usar blog.all_posts y blog.last_post, pero no tienen idea de cómo iba a hacer algo así blog.latest_posts: 10.

¿Alguien puede apuntarme en la dirección correcta?

Una idea en la que pensé fue crear un filtro de Liquid y pasar el objeto Blog y un entero a eso. Algo así como:

{% for post in blog | latest_posts(10) %} 
  • pero no han probado todavía cuando la persona sienta que estoy punzante alrededor en el un poco oscuro. Agradecería la ayuda de los usuarios de Liquid más experimentados.

Respuesta

9

responder a mi propia pregunta aquí, he encontrado una solución documentada en el Liquid groups pages.

Esencialmente, necesitaba crear un drop para las últimas publicaciones - un LatestPostsDrop - y un tipo de hack que le pasaba una variable usando el método before_method.Aquí está la solución completa:

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 

hacer lo anterior, le permite iterar a través de cualquier número de todos los mensajes usando algo como:

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

Me parece un poco hacky, pero funciona :)

+1

Gracias por la información del método before_method. Estoy de acuerdo en que es un poco raro, pero recuerde que el foco de Liquid es la plantilla, no la maquinaria detrás de la plantilla. La intención es permitir que otros grupos de personas usen solo el lenguaje de plantilla para hacer vistas de datos útiles/sofisticadas de una manera segura. Creo que es muy bueno para eso, tanto mis clientes como sus contratistas usan plantillas Liquid con mis datos SAAS. –

5

Creo que el líquido es un fantástico sistema de plantillas. Felicidades por su investigación/uso.

De manera predeterminada, ninguno de los métodos del modelo está disponible para la plantilla líquida. Ésto es una cosa buena. A continuación, especifique qué métodos estarán disponibles. (Una lista blanca.)

Utilizo una extensión para el Módulo que se envió en la lista de correo. La extensión completa está abajo. Maneja la creación Liquid :: Drop para usted agregando un método simple #liquid_methods a clases y módulos.

Luego, en sus modelos, sólo hago:

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 

No estoy seguro de improviso cómo/si se puede pasar params en una gota. Pregunte en la lista de correo de Liquid. Yo creo que puedes.

Agregado: ahora volver a leer su pregunta y ver que realmente desea enviar en ese parámetro al método. Puede enviar más de un argumento/parámetro a un filtro Líquido. Por lo que podría tener un filtro:

# 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. 

En este ejemplo, también recordar que tendrá que declarar los métodos de líquidos en el poste de la clase también.

Aquí está la extensión del módulo.

# 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

Hola Larry, gracias por tu aporte. Intenté con tu sugerencia agregada pero no pude lograr que funcionara satisfactoriamente. '{{blog | latest_posts: 10}} 'devolvería las últimas 10 publicaciones. Sin embargo, no pude averiguar cómo iterar a través de ellos: '{% para las publicaciones en (blog | últimas_posiciones: 10)%}' (o variaciones a lo largo de ese tema) simplemente no se repiten a través de las publicaciones. Sin embargo, encontré una [solución aquí] (http://groups.google.com/group/liquid-templates/browse_thread/thread/90ae684e754b6de5/1b080bcff95ed59d?lnk=gst&q=pass+variable+to+drop#1b080bcff95ed59d) que voy a poner en una respuesta a continuación ... – aaronrussell

+0

Descubrí que necesitaba almacenar los resultados del filtro en una variable y luego podía iterar sobre la variable: '{% assign latest_blog_posts = blog | latest_posts: 10%} 'then' {% para publicar en latest_blog_posts%} ... ' –

Cuestiones relacionadas