Automatically include all paramaters into render locals

May 4 2010 by Tye Shavik

We use helpers to refactor our render statements and we end up with a lot of helpers like this:

def comment_fields(f,course,discussion,comment)
  render :partial => 'comments/fields',
    :locals => { 
      :f => f,
      :course => course,
      :discussion => discussion,
      :comment => comment }
end

In these helpers you’re typing out each variable name 3 times, once in the function definition and twice in the locals hash. Wouldn’t it be great if you only had to type the name of the variables in the definition and have the local hash generated automatically? Well we’ve created a nifty helper called locals that will do just that. It works like this:

def comment_fields(f,course,discussion,comment)
  render :partial => 'comments/fields',
    :locals => locals(binding)
end

The binding object is built-in to Ruby and allows you to access a list of variable names in the local scope. The locals helper will use this object to generate a hash of variables that you can pass to the render function.

You will need to put this function in your application_helper.rb:

def locals(helper_binding,*locals)
  options = locals.extract_options!
  result = {}
  vars = eval("local_variables",helper_binding)
  for var in vars
    result[var.to_sym] = eval("#{var}",helper_binding)
  end
  result.merge(options)
end

locals(binding) will grab all the local variables that exist at the time it’s evaluated (not just the variables that are in the function definition). You can pass a hash to locals to specify additional variables to pass.

So for example this code:

def comment_fields(f,course,discussion,comment)
  user = comment.user
  render :partial => 'comments/fields',
    :locals => locals(binding,
      :comment_count => discussion.comments.length)
end

Is the same as:

def comment_fields(f,course,discussion,comment)
  render :partial => 'comments/fields',
    :locals => { 
      :user => comment.user,
      :f => f,
      :course => course,
      :discussion => discussion,
      :comment => comment,
      :comment_count => discussion.comments.length }
end

Write a Comment to “Automatically include all paramaters into render locals”