Rails magic form helper – create field based on type
2009 March 21
The following is a helper that adds onto the regular form_for helper within rails. The script below adds methods onto the default form_for to generate fields automatically based on the type of the field. If you have a really basic model you can also generate the entire form based on the data type of each column.
# put this in lib/magic_form.rb class MagicForm < ActionView::Helpers::FormBuilder def input_fields(opts = {}) object = @object.class columns = object.columns.delete_if {|key,value| opts[:exclude] && opts[:exclude].include?(key.name) || key.name == "id" } columns.collect {|o| input_for(o.name)} end def input_for(field, opts = {}) field = field.to_s field_label = self.label(field, opts[:label]) type = @object.class.columns_hash[field].type.to_s if field.include?("_id") field = self.collection_select field, field.gsub("_id","").camelize.constantize.all, opts[:option_id] ? opts[:options_id] : :id, opts[:option_label] ? opts[:option_label] : :name else field = case type when "string", "integer", "float" self.text_field field, opts when "boolean" self.check_box field, opts when "datetime" self.datetime_select field, opts when "date" self.date_select field, opts when "time" self.time_select field, opts when "text" self.text_area field, opts when "binary" self.file_field field, opts eles self.text_field field, opts end end if type == "boolean" "<p>\n\t#{field}\n\t#{field_label}\n</p>\n" else "<p>\n\t#{field_label}\n\t<br />\n\t#{field}\n</p>\n" end end end # Example usage # app/admin/views/listings/new.html.haml %h2 New listing = render :partial => "form", :locals => {:listing => @listing} # app/models/listing.rb class Listing < ActiveRecord::Base has_one :status end # app/models/status.rb class Status < ActiveRecord::Base validates_presence_of :name belongs_to :listing end # app/admin/views/llistings/_form.html.haml # single field usage # f.input_for :price prints out the label along with the proper field. integer, string, float is a # text field, text is a text area, boolean is a checkbox, date field is a date selector, datetime # is date time selector, etc. # f.input_for :status_id makes a label with a select field and populates the select input # with all of the options from the status table. The way that the helper determines the # associated model's data could probably be improved upon, I'm sure there's a better way. - form_for ([:admin, @listing]), :builder => MagicForm do |f| = f.input_for :price = f.input_for :status_id = submit_tag "Create new listing" # app/admin/views/listings/_form.html.haml # complete form maker # f.input_fields will make the entire form for you from Model.columns (excluding id, didn't # want to use content_columns since that strips out all fields that have _id). This probably # won't be used much but it's here for really basic models where nothing too complicated is going on. - form_for ([:admin, @listing]), :builder => MagicForm do |f| = f.input_fields, :exclude => ['created_at'] = submit_tag "Create new listing" # the helper doesn't support has_many associations just has_one associations. # This is meant to be used as a replacement for most of the simple cases for # administering content, not for complex forms or associations.
This form builder was inspired by Merb’s control_for method which I can no longer find documentation on. Hopefully something similar will make it into Rails 3.
Let me know if you have tips on how to add on or improve the script or if you find it useful.
4 Responses
leave one →

I was thinking about doing something similar but a little bit more complex. Now I have decided to change my strategy and keeping it much more simple and go your way. I have also non-model fields that I want to integrate so I guess I have to make some changes
You should lookup Formtastic. It does this and a whole lot more
Nice to know how it works though. I might need it
@PhilT I just needed a simple solution, I’ve seen that plugin it’s pretty slick.
Eventually I’ll get around to packaging this one up as a plugin.