Передача переменных в методы экземпляра модели в шаблонах Liquid - PullRequest
6 голосов
/ 29 августа 2010

В эти выходные я играл с шаблонизатором Liquid, и мне интересно, возможно ли следующее.

Скажем, у меня есть метод latest_posts в модели Blog, который я могу передать целым числом, чтобы получить последние N сообщений. Можно ли использовать этот метод в жидком шаблоне?

Например:

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

В приведенном выше упрощенном примере в моих жидких шаблонах я могу использовать blog.all_posts и blog.last_post, но понятия не имею, как бы я делал что-то вроде blog.latest_posts: 10.

Может кто-нибудь направить меня в правильном направлении?

Одна идея, о которой я подумал, состояла в том, чтобы создать фильтр Liquid и передать в него и объект Blog, и целое число. Что-то вроде:

{% for post in blog | latest_posts(10) %}
  • но еще не пробовал, так как чувствую, что я немного покачиваюсь в темноте. Был бы признателен за помощь более опытных пользователей Liquid.

Ответы [ 2 ]

9 голосов
/ 30 августа 2010

Отвечая на мой собственный вопрос здесь, я нашел решение, задокументированное на страницах Liquid groups .

По сути, мне нужно было создать дроп для последних сообщений - LatestPostsDropи что-то вроде хака, передающего переменную с помощью метода before_method.Вот полное решение:

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

Выполнение вышеизложенного позволяет перебирать любое количество последних сообщений, используя что-то вроде:

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

Это кажется немного странным, но этоработает:)

5 голосов
/ 29 августа 2010

Я думаю, что жидкость - это фантастическая система шаблонов.Поздравляю с исследованием / использованием.

По умолчанию ни один из методов модели не доступен для жидкого шаблона.Это хорошая вещь.Затем вы указываете, какие методы должны быть доступны.(Белый список.)

Я использую расширение для модуля, которое было отправлено в списке рассылки.Полное расширение ниже.Он обрабатывает создание Liquid :: Drop для вас, добавляя простой метод #liquid_methods к классам и модулям.

Затем в ваших моделях просто сделайте:

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

Я неконечно, как / если вы можете передать параметры в капле.Спросите в списке рассылки Liquid.Я думаю, что вы можете.

Добавлено: Теперь я перечитал ваш вопрос и вижу, что вы действительно хотите отправить этот параметр в метод.Вы можете отправить более одного аргумента / параметра в жидкостный фильтр.Таким образом, у вас может быть фильтр:

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

В этом примере также помните, что вам также необходимо объявить жидкие методы в классе Post.

Вот расширение модуля.

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