将变量传递给 Liquid 模板中的模型实例方法

发布于 2024-09-16 14:16:17 字数 966 浏览 6 评论 0原文

这个周末我一直在使用 Liquid 模板引擎,我想知道以下是否可行。

假设我在 Blog 模型中有一个 latest_posts 方法,我可以向该方法传递一个整数来获取最新的 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_postsblog.last_post,但不知道我会如何做 >blog.latest_posts:10

有人能指出我正确的方向吗?

我想到的一个想法是创建一个 Liquid 过滤器并将 Blog 对象和一个整数传递给它。类似的东西:

{% for post in blog | latest_posts(10) %}
  • 但还没有尝试过,感觉就像我在黑暗中刺伤一样。希望有经验的 Liquid 用户提供一些帮助。

I've been playing around with the Liquid templating engine this weekend, and I wonder if the following is possible.

Say I have a latest_posts method in a Blog model, which I can pass an integer to to get the latest N posts. Is it possible to use that method in a liquid template?

For example:

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 the simplified example above, in my liquid templates I can use blog.all_posts and blog.last_post, but have no idea how I would do anything like blog.latest_posts: 10.

Can anyone point my in the right direction?

One idea I thought of was to create a Liquid filter and pass both the Blog object and an integer to that. Something like:

{% for post in blog | latest_posts(10) %}
  • but haven't tried that yet as feel like I'm stabbing around in the dark a bit. Would appreciate some help from more experienced Liquid users.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

泪意 2024-09-23 14:16:17

在这里回答我自己的问题,我找到了 液体组页面

本质上,我需要为最新帖子创建一个 drop - 一个 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 %}

这似乎有点 hacky,但它有效:)

Answering my own question here, I found a solution documented in the Liquid groups pages.

Essentially, I needed to create a drop for the latest posts - a LatestPostsDrop - and kind of hack passing a variable to it using the before_method method. Here is the complete solution:

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

Doing the above, allows you to iterate through any number of latest posts using something like:

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

It seems a bit hacky, but it works :)

可可 2024-09-23 14:16:17

我认为液体是一个很棒的模板系统。恭喜您调查/使用它。

默认情况下,没有任何模型方法可用于液体模板。这是一件好事。然后您指定哪些方法可用。 (白名单。)

我使用了在邮件列表上发送的模块扩展。完整的扩展如下。它通过向类和模块添加简单的 #liquid_methods 方法来为您处理 Liquid::Drop 创建。

然后,在您的模型中,只需执行以下操作:

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

我不确定如何/是否可以将参数传递到 drop 中。在 Liquid 邮件列表上询问。我想你可以。

添加:我现在重新阅读您的问题,发现您确实想要将该参数发送到该方法。您可以向 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 类中声明 Liquid 方法。

这是模块扩展。

# 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 

I think liquid is a fantastic template system. Congrats on investigating/using it.

By default, none of the model's methods are available to the liquid template. This is a good thing. You then specify which methods shall be available. (A white list.)

I use an extension to Module which was sent on the mailing list. Complete extension is below. It handles the Liquid::Drop creation for you by adding a simple #liquid_methods method to classes and modules.

Then, in your models, just do:

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

I'm not sure offhand how/if you can pass params into a drop. Ask on the Liquid mailing list. I think you can.

Added: I now re-read your question and see that you really want to send in that param to the method. You can send in more than one argument/parameter to a Liquid filter. So you could have a 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 this example, also remember that you'll need to declare liquid methods in the Post class too.

Here is the module extension.

# 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 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文