Monday, May 16, 2011

Rails form_for_hash

Ruby on Rails has some nice form building helpers if you are building an HTML form for populating an ActiveRecord model. But what if you want your front end forms to not exactly map to your back end models? Maybe you are presenting a logical view that corresponds to parts of different models. Well, Rails still provides helpers that let you roll your own form. However, now you have to manually handle reading and writing values to the form. It would be nice if you could get the form_for functionality with just a simple Hash.

Well, it turns out that with a little bit of work, you can. Based on an idea I found at, I created a simple Object which wraps a Hash and behaves like an ActiveRecord. This class looks like:
class HashObject
  def initialize(hash={})     @hash = hash   end   def method_missing(sym, *args, &block)     @hash[sym]   end end
Then to make it easy to use, I put a helper function in helper/application_helper.rb
def form_for_hash(hash, name, url, html_options={}, &proc)
  object =   form_for object, :as=>name, :url=>url, :html=>html_options, &proc end
Now I can use it in the view as such:  (e.g. new.html.haml)
= form_for_hash @person, :person, special_people_path do

  = f.label :first_name, 'First Name'
  = f.text_field :first_name

  = f.label :last_name, 'Last Name'
  = f.text_field :last_name
  = f.label :phone_number, 'Phone Number'
  = f.text_field :phone_number
  -# etc etc etc
Then in your SpecialPeopleController you would have methods like
def new
  @person = {:first_name=>'Jenny', :phone_number=>'867-5309'} end def create   @person = params[:person]   # logic for populating/updating models based on hash goes here end
And that is all you need to do to be able to use a Hash to populate your forms.


Anonymous said...

Does the madking take requests for topics? Can we have a thread on say parallel programming? Has the madking ever done parallel programming? What was the most difficult part? What software did the madking use? java+jppf?

andrew said...

Is there a reason you'd do this rather than just using an OpenStruct?