【问题标题】:Passing variables to model instance methods in Liquid templates将变量传递给 Liquid 模板中的模型实例方法
【发布时间】:2011-04-05 11:57:36
【问题描述】:

这个周末我一直在玩 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 用户提供一些帮助。

【问题讨论】:

    标签: ruby template-engine liquid


    【解决方案1】:

    在这里回答我自己的问题时,我在Liquid groups pages 中找到了一个解决方案。

    基本上,我需要为最新帖子创建一个下拉列表 - 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,但它有效:)

    【讨论】:

    • 感谢有关 before_method 的信息。我同意这有点老套,但请记住,Liquid 的重点是模板,而不是模板背后的机制。其目的是使其他人群能够仅使用模板语言以安全的方式制作有用/复杂的数据视图。我认为这非常有用——我的客户和他们的承包商都使用带有我的 SAAS 数据的 Liquid 模板。
    【解决方案2】:

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

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

    我使用了在邮件列表中发送的 Module 扩展。完整的扩展如下。它通过向类和模块添加一个简单的#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 类中声明流动方法。

    这是模块扩展。

    # 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 
    

    【讨论】:

    • 嗨拉里,感谢您的意见。我尝试了您添加的建议,但无法使其令人满意地工作。 {{ blog | latest_posts: 10 }} 确实会返回最新的 10 个帖子。但是,我不知道如何遍历它们:{% for posts in (blog | latest_posts: 10) %}(或该主题的变体)只是没有遍历帖子。但是,我找到了一个solution here,我将在下面给出答案...
    • 我发现我需要将过滤器的结果存储在一个变量中,然后我可以遍历该变量:{% assign latest_blog_posts = blog | latest_posts: 10 %} 然后{% for post in latest_blog_posts %}...
    猜你喜欢
    • 1970-01-01
    • 2014-06-02
    • 1970-01-01
    • 2017-11-10
    • 2019-04-03
    • 2011-05-08
    • 2015-08-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多