ProblemContributed by: Christian Romney You want to give your application's designers or end users the ability to design robust view templates without risking the security or integrity of your application. SolutionLiquid templates are a popular alternative to the default ERb views with .rhtml templates. Liquid templates can't execute arbitrary code, so you can rest easy knowing your users won't accidentally destroy your database. To install Liquid, you need the plug-in, but first you must tell Rails about its repository. From a console window in the Rails application's root directory type: $ ruby script/plugin source svn://home.leetsoft.com/liquid/trunk $ ruby script/plugin install liquid Once the command has completed, you can begin creating Liquid templates. Like ERb, Liquid templates belong in the controller's folder under app/views. To create an index template for a controller named BlogController, for instance, you create a file named index.liquid in the app/views/blog folder. Now, let's have a look at the Liquid markup syntax. To output some text, simply embed a string between a pair of curly braces: {{ 'Hello, world!' }} You can also pipe text through a filter using a syntax very similar to the Unix command line: {{ 'Hello, world!' | downcase }} All but the most trivial templates will need to include some logic, as well. Liquid includes support for conditional statements: {% if user.last_name == 'Orsini' %} {{ 'Welcome back, Rob.' }} {% endif %} and for loops: {% for line_item in order %} {{ line_item }} {% endfor %} Now for a complete example. Assume you've got an empty Rails application ready, with your database.yml file configured properly, and the Liquid plug-in installed as described above. First, generate a model called Post: $ ruby script/generate model Post Next, edit the migration file: 001_create_posts.rb. For this example, you want to keep things simple: db/migrate/001_create_posts.rb: class CreatePosts < ActiveRecord::Migration def self.up create_table :posts do |t| t.column :title, :string end end def self.down drop_table :posts end end Now, generate the database table by running: $ rake db:migrate With the posts table created, it's time to generate a controller for the application. Do this with: $ ruby script/generate controller Posts Now you're ready to add Liquid support to the application. Start your preferred development server with: $ ruby script/server -d Next, add some general support for rendering liquid templates within the application. Open the ApplicationController class file in your editor, and add the following render_liquid_template method: app/controllers/application.rb: class ApplicationController < ActionController::Base def render_liquid_template(options={}) controller = options[:controller].to_s if options[:controller] controller ||= request.symbolized_path_parameters[:controller] action = options[:action].to_s if options[:action] action ||= request.symbolized_path_parameters[:action] locals = options[:locals] || {} locals.each_pair do |var, obj| assigns[var.to_s] = \ obj.respond_to?(:to_liquid) ? obj.to_liquid : obj end path = "#{RAILS_ROOT}/app/views/#{controller}/#{action}.liquid" contents = File.read(Pathname.new(path).cleanpath) template = Liquid::Template.parse(contents) returning template.render(assigns, :registers => {:controller => controller}) do |result| yield template, result if block_given? end end end This method, which is partly based on code found in the excellent Mephisto publishing tool, finds the correct template to render, parses it in the context of the variables assigned, and is rendered when the application layout yields control to the index.liquid template. To call this method, add the following index action to the PostsController: app/controllers/posts_controller.rb: class PostsController < ApplicationController def index @post = Post.new(:title => 'My First Post') render_liquid_template :locals => {:post => @post} end # ... end For convenience, add a simple to_liquid method to the Post model: app/models/post.rb: class Post < ActiveRecord::Base def to_liquid attributes.stringify_keys end end You're just about finished. Next, you must create an index.liquid file in the app/views/posts directory. This template simply contains: app/views/posts/index.liquid: <h2>{{ post.title | upcase }}</h2> Lastly, a demonstration of how you can even mix and match RHTML templates for your layout with Liquid templates for your views: app/views/layouts/application.rhtml: <html> <head> <title>Liquid Demo</title> </head> <body> <%= yield %> </body> </html> You're finally ready to view your application. Point your browser to /posts; e.g., http://localhost:3000 /posts. DiscussionThe main difference between Liquid and ERb is that Liquid doesn't use Ruby's Kernel#eval method when processing instructions. As a result, Liquid templates can process only data that is explicitly exposed to them, resulting in enhanced security. The Liquid templating language is also smaller than Ruby, arguably making it easier to learn in one sitting. Liquid templates are also highly customizable. You can add your own text filters easily. Here's a simple filter that performs ROT-13 scrambling on a string: module TextFilter def crypt(input) alpha = ('a'..'z').to_a.join alpha += alpha.upcase rot13 = ('n'..'z').to_a.join + ('a'..'m').to_a.join rot13 += rot13.upcase input.tr(alpha, rot13) end end To use this filter in your Liquid templates, create a folder called liquid_filters in the lib directory. In this new directory, add a file called text_filter.rb containing the code listed above. Now open your environment.rb and enter: config/environment.rb: require 'liquid_filters/text_filter' Liquid::Template.register_filter(TextFilter) Your template could now include a line such as this one: {{ post.title | crypt }} Liquid is production-ready code. Tobias Lütke created Liquid to use on Shopify.com, an e-commerce tool for nonprogrammers. It's a very flexible and elegant tool and is usable by designers and end users alike. In practice, you'll probably want to cache your processed templates, possibly in the database. For a great example of Liquid templates in action, download the code for the Mephisto blogging tool from http://mephistoblog.com. See Also
|