Render Rails Templates Anywhere (even in a model)

Monday, July 20th, 2009

I can only dream of actually having the time to properly update this blog, but for the moment I’m simply posting a snippet that has been very useful to me.

Even though I love Rails, I hate the way it locks you into only working within its paradigm, making it virtually impossible to break out of the MVC box even when it makes far more sense to do so. One particularly bothersome case is when you need (for whatever reason) to render an ActionView template outside of a controller.

For instance, in an application I’m working on I allow users to customize automatically sent emails. These emails are templated using a custom class that allows the user to insert predefined tags into the message that are automatically replaced with information such as the recipients name, address, etc. One such tag is replaced by a summary of all the users registration information, and this summary is simply an ActionView template. This leads to the sticky part. The template class is prepared by a class method of my model, which needs to provide a block to the template class capable of rendering this summary page.

Enter the render_anywhere method!

def render_anywhere(partial, assigns)
  view = ActionView::Base.new(Rails::Configuration.new.view_path, assigns)
  ActionView::Base.helper_modules.each { |helper| view.extend helper }
  view.extend ApplicationHelper
  view.render(:partial => partial)
end

Simply place this method in a file in your lib directory, or even in environment.rb, it really doesn’t matter. Then you can just call it (from literally anywhere) as shown below:

render_anywhere('/students/summary', { :student => student })

You can also add controller specific helpers if necessary, by simply adding more view.extend lines as above.

(thanks to Compulsivo for much of this code)

Better Redirects in Rails

Saturday, March 22nd, 2008

Its been a very long time since I posted to this blog, but I thought I might share some tricks I’ve developed for handling a few special types of redirects a bit more gracefully in Ruby on Rails.

Note: all of the code in this post, except for one view helper method, should be placed in your ApplicationController (app/controllers/application.rb) from which all other controllers inherit.

Most people who have read any book on Rails will probably have run into the redirect_to_index method, which goes something like this:

def redirect_to_index(msg = nil)
  flash[:notice] = msg if msg
  redirect_to :action => 'index'
end

This method is mainly useful when you the user has just edited an object, and you now want to display a message in the flash like “User updated successfully”, and then redirect them back to the index action. But what about if you don’t want to redirect the user back to the index action, or if you want to send them to another controller? Say hello to the flash_redirect method:

def flash_redirect(msg, *params)
  flash[:notice] = msg
  redirect_to(*params)
end

flash_redirect accepts both a message to be put in the flash, along with the params for redirect_to, so that you can flash a message and then send the user anywhere you please.

These two methods by themselves are pretty useful, but what about the common situation where a user attempts to go somewhere they don’t have permission to, or that they need to login before accessing? In the Rails book, this is handled by storing the original url in the session, and then redirecting to the other action, which then has to do special session processing when it returns the user to the original action. Encapsulating all this code into some easily reusable methods would look like this:

# redirect somewhere that will eventually return back to here
def redirect_away(*params)
  session[:original_uri] = request.request_uri
  redirect_to(*params)
end

# returns the person to either the original url from a redirect_away or to a default url
def redirect_back(*params)
  uri = session[:original_uri]
  session[:original_uri] = nil
  if uri
    redirect_to uri
  else
    redirect_to(*params)
  end
end

redirect_away handles sending the user away to another action, and redirect_back will send them back to either the action they were redirected away from, or to a default action. One possible use for these could be to require authorization before accessing an action:

class AdminController < ApplicationController
  before_filter :require_admin, :except => 'login'

  def index 
    # unauthorized people shouldn't be able to access this
  end

  def login
    # handle login
    if User.authorize(params[:username], params[:password])
      session[:admin] = true
      redirect_back(:action => 'index')
    end
  end

  private

  def require_admin
    unless session[:admin]
      flash[:notice] = "You must be logged in"
      redirect_away(:action => 'login')
      return false
    end
  end
end

So now we can redirect a user away from an action, and then send them back to it later on. But what if we want to let a user click a link to go somewhere, and then send them back where they came from later? With a simple helper method and a before filter, we can accomplish just that:

# app/helpers/application_helper.rb
def link_away(name, options = {}, html_options = nil)
  link_to(name, { :return_uri => url_for(:only_path => true) }.update(options.symbolize_keys), html_options)
end

# app/controllers/application.rb
before_filter :link_return

private

# handles storing return links in the session
def link_return
  if params[:return_uri]
    session[:original_uri] = params[:return_uri]
  end
end

Now in the view, you can write:

<%= link_away "Edit post", :controller => '/admin/posts', :action => 'edit', :id => post %>

And as long as the controller uses redirect_back, the user can click the link, and when they’re done editing, they will come right back to where they clicked the link. This trick is probably the most useful from a usability standpoint, given that nothing annoys a user more than having to manually navigate back to where they were after each change.

I hope you find these techniques useful for writing more user friendly and concise code!

Updated Ruby Tutorial

Friday, August 17th, 2007

I’ve just updated my Ruby tutorial with a ton of new content. Some of the added sections include:

  • A regular expression (regex) reference
  • An explanation of the rather confusing rules behind block scope
  • An example on the use of the Ruby case statement (similar to the C switch statement)
  • How to write your own attr_accessor method (and understand class_eval in the process)
  • Several new core functions and methods

I don’t know if anyone else is finding my reference helpful, but it has definitely aided me in understanding the intricacies of Ruby.

Fixing div.fieldWithErrors in Ruby on Rails

Saturday, May 5th, 2007

Rails’ form helpers are incredibly handy in quickly writing form code, however their error handling code leaves something to be desired. By default, when a field has errors associated with it, the input is wrapped in a div of class “fieldWithErrors”. Unfortunately, this behavior requires you to explicitly change the div to display inline so it doesn’t make the input appear on the next line after the name of the field. I have also had some trouble getting this setting to work in Safari, although that may just be my problem and not Safari’s.

Fortunately, fixing this annoying little gotcha is as easy as adding a single line to the end of your environment.rb file: (I’ve split it into two lines so it will fit on the page, just remove the line break)

ActionView::Base.field_error_proc = Proc.new { |html_tag, instance|
"<span class=\"fieldWithErrors\">#{html_tag}</span>" }

I know many people have already written about this problem, but I wanted to have my own record of it for easy reference 😉

The Dangers of Direct Assignment in Rails with User.new(params[:user])

Monday, April 30th, 2007

Although it is used in the vast majority of Ruby on Rails tutorials, putting data from a form directly into an object using a statement such as User.new(params[:user]) can actually be an extreme security risk.

To understand why, it is necessary to first explain how this statement works. Forms generated by Rails’ default form helpers look something like this:

Username: <input type="text" name="user[username]" />
Password: <input type="password" name="user[password]" />

The user[name] format is automatically converted by rails into a hash in the params variable, which would contain the following if this form were submitted:

params[:user] = {
    :username => "Bob"
    :password => "Secret"
}

Since User.new accepts a hash of key/value pairs that will become the initial values of all the attributes of the returned object, User.new(params[:user]) is simply taking the hash of values passed in from the HTML form for the user, and directly setting them in the new object. The simplicity of this operation is also its downfall. For instance, a user could modify your registration form (either using a browser plugin our by downloading it to their computer) to the following:

Username: <input type="text" name="user[username]" />
Password: <input type="password" name="user[password]" />
<input type="hidden" name="user[admin]" value="1" />

If your user model used a boolean attribute called admin to specify whether a user had admin privileges, when the form is submitted your code would unwittingly grant the user admin access. Because params[:user][:admin] was set to 1 in the hash passed in from the form, it is automatically set to 1 in the user object and saved to the database.

The Solution

Fortunately, this security hole is easy to fix using either of two simple statements provided by ActiveRecord in your model code. The first is attr_protected, which can be used thus:

class User < ActiveRecord::Base
    attr_protected :admin
end

This simple statement, which can accept multiple parameters, sets up a blacklist of attributes that cannot be set from the hash passed to User.new, effectively filtering the input and patching the security hole.

The second alternative, attr_accessible, uses a white-listing approach instead. Only those attributes explicitly given to attr_accessible can be set from the hash passed to User.new, any others will be ignored.

class User < ActiveRecord::Base
    attr_accessible :username, :password
end

Which approach you use depends entirely on preference, whether you think you are more likely to forget to protect sensitive attributes or to allow access to non-sensitive ones. Whichever method you choose, protected attributes can always be set by calling their accessor method, such as user.admin = 1.

For more information on this topic, see the Ruby on Rails manual.

A Further Warning on Associations

According to this article, the mass assignment security hole also affects collections and associations, such as a User having many Articles. By specially crafting a form submission, a user could claim any article as their own, simply using something similar to:

<input type="hidden" name="user[article_ids][]" value="5" />

This is because rails automatically creates attribute accessors like article_ids for has_many associations, which accept an array of ids to associate the object with. The form snippet above would add a new id to that array, and give the user ownership/authorship of that article. The author of the above article makes the case that, because of this hole (and other possibly others opened up by associations and other rails magic), it is a better idea to explicitly white-list attributes using attr_accessible, rather than attr_protected. This way, something like article_ids, which most developers don’t know about (myself included), won’t open up your application to exploitation. Ignorance is not always bliss.

Although this methodology is somewhat more in the spirit of Python than Rails, it is undoubtedly the safest. Explicitly defining which variables can be passed in through a form is also the method taken by Formencode, a widely used validation library for Python.

Ruby – A Lightning Tutorial

Saturday, March 31st, 2007

Whenever I’m learning a new programming language, I find it helpful to keep notes on what I learn. Ruby is no exception, except this is the first time I have tried compiling these notes into more of a tutorial.

You can see the first draft of it (or the Alpha version), over here.

Its style is based on the assumption that you can always find out about the practical usage of the language, its classes, functions, and methods, later. Lightning Tutorials (yes, I intend to write more) attempt to teach only the absolute essential parts of the language, its syntax, idioms, features, and gotchas. Because they do not explain anything but the most fundamental parts of the language, they can be very concise. However, you must already be a relatively competent programmer to understand them. I don’t explain what terms such as “instance variables” or “classes” mean, as they are not intended to be an introduction to programming, but rather a quickstart guide for experienced programmers who wish to get up and running on a new language quickly. After all, you can always read the language docs later.

Mac Graphing Calculator Story

Saturday, March 17th, 2007

This story is hilarious! It gives the history of the graphing calculator built into mac since version 8.0. Apparently, the project had been canceled, but two developers stayed on for free at apple for over six months to finish developing it. They would sneak into the building by tailgating other employees through the entrance, and hijack empty offices. Each of the two developers said he was reporting to the other one, so they were entirely autonomous.

All sorts of different employees helped them accomplish the task. In fact, the story says they probably received more aid than they would have had they been on the payroll. Eventually, their project was discovered, but by that time it was advanced enough that apple decided to include it on new macs.

Its a fascinating read! The Graphing Calculator Story

Ruby on Rails, Here I Come!

Thursday, January 4th, 2007

I just got my Agile Web Development with Rails book! Now I can learn rails and start writing killer software 10 times faster than I could with PHP!

end hype

Seriously, now I can actually see how easy it is to develop “real” software with rails, rather than the ten minute basically worthless blog software that doesn’t even have authentication. I think building Flowpad v2 with it (the next version of the tournament registration software) will be the ultimate test of its abilities.

Hopefully Rails will be up to the task.

Python Easter Eggs

Friday, December 1st, 2006

These are pretty funny, and the first one is an excellent definition of what “pythonic” means.

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!


>>> from __future__ import braces
  File "<stdin>", line 1
SyntaxError: not a chance

Python Full Text Search Script

Wednesday, August 9th, 2006

Many times in the past when I have been attempting to figure out how someone else’s code worked (or wasn’t working as was more often the case), I have wanted a way to perform full text searches of all the documents in a directory and its subdirectories. Unfortunately, Windows (being utterly lacking in all things helpful) fails to provide such a search mechanism.

Python to the Rescue!

So I wrote up this small little Python script which will recursively search all the text documents in a directory tree. By text documents I mean anything that isn’t binary, so it will search just about any kind of source code.

The syntax is very simplistic, with only two arguments, one of which is optional.

search.py [directory] searchstring

The search string should be in quotes if it contains anything but alphanumeric characters, and you should, of course, escape quotes in the string.

Example Usage

search.py "Hello World"
search.py include "$unknownvariable"
search.py "<table colspan=\"2\">"