Problem with access to variables in liquid

148 views
Skip to first unread message

meceo

unread,
Jul 2, 2009, 11:06:35 AM7/2/09
to Liquid Templates
Hi there

I included liquid into 2 projects and have issue in one of them.
When I add liquid method in any way I know I still dont have access to
variables:

3 ways

class User
liquid_methods :name
def to_liquid
{:name => name}
end
end

class UserDrop < Liquid::Drop
def name
user = User.last.name
end
end

When I use it by:
@email_template = Liquid::Template.parse "Hi {{ user.name }}"
@user = User.last
@email_template.render({:user => @user})

result: "Hi "

I second project (fresh one) I don't have any problems, do you have
any idea how to debug this problem or resolve it?

Brian Candler

unread,
Jul 2, 2009, 12:06:19 PM7/2/09
to liquid-t...@googlegroups.com

Unfortunately, Rails teaches people to believe that :name and 'name' are the
same thing. They are not :-(

You need to return {'name'=>name} from your to_liquid method, and you need
to pass {'user'=> ...} not {:user=> ...} into render.

$ irb --simple-prompt
>> require 'liquid'
=> true
>> class Foo; def to_liquid; {"name"=>"boing"}; end; end
=> nil
>> tmpl = Liquid::Template.parse "Hi {{ user.name }}"
=> #<Liquid::Template:0xb7bb42a4 @root=#<Liquid::Document:0xb7bb427c
@nodelist=["Hi ", #<Liquid::Variable:0xb7bb3ef8 @filters=[], @markup="
user.name ", @name="user.name">]>>
>> tmpl.render :user=>Foo.new
=> "Hi "
>> tmpl.render 'user'=>Foo.new
=> "Hi boing"
>>

Also, you don't appear to be using your UserDrop class at all, so you can
delete it entirely. A Drop is a shortcut for building an object where, when
liquid calls obj['name'], it invokes the obj.name public instance method
instead. Since you are already returning a Hash, then obj['name'] already
returns the value of interest directly.

HTH,

Brian.

meceo

unread,
Jul 3, 2009, 2:35:16 AM7/3/09
to Liquid Templates
Hi Brian

I know difference between strings and symbols. Indeed I pass hash
keys as symbols but before render I convert them into strings
so that was not a reason in application and it was something what I
forgot (convert symbols) in console
I found bug in other place in application.
Anyway you helped me a lot so thank you again

Now I have to inform template editors which objects and which
methods are accessible for them. I would like to display it in box
next to template creator but how can I do it?
I have to display objects with methods about which I'm sure I will
provide when render template. I can do it by using some prefix for
methods, then inspect_methods on each object
and I will get them, but do you know some better way?

regards
meceo

Brian Candler

unread,
Jul 3, 2009, 3:46:09 AM7/3/09
to liquid-t...@googlegroups.com
On Thu, Jul 02, 2009 at 11:35:16PM -0700, meceo wrote:
> Now I have to inform template editors which objects and which
> methods are accessible for them. I would like to display it in box
> next to template creator but how can I do it?

Which objects are available in the template is simply the set of objects you
pass to the render() call.

Which methods are available on each object is a little more difficult. When
Liquid evaluates an expression of the form foo.bar, it requires only two
methods: 'has_key?' and '[]'

So I'd suggest that you make sure that all your objects respond to a 'keys'
method as well, which lists the available keys. A Hash does this already of
course. If you're subclassing from Liquid::Drop, then

def keys
self.class.public_instance_methods.map { |m| m.to_s }
end

If you look at the source of Liquid::Drop, you'll see that this is the how
it decides whether a method can be directly invoked or not.

However, a Liquid::Drop can actually accept *any* method name. Any unknown
method name is passed to the before_method method.

Brian.

Reply all
Reply to author
Forward
0 new messages