In Ruby on Rails, people often use the scaffold generator to quickly generate their controller, model, and view code for their resources. This creates a lot of code very quickly that will let you list/edit/create/delete records and objects in no time. Here's an example of the command:

rails generate scaffold device description:string name:string

One file that is generated for your new model is _form.html.erb, as in app/views/devices/_form.html.erb. This contains the form fields(text input, radio buttons, etc.) for your model. Here's what it looks like for our device model:

  
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :description %>
<%= f.text_field :description %>

This is great, but if I add another attribute to the model, I'll have to update the form by hand and add my new attribute, or completely regenerate the scaffold. I'm not interested in extra work and I want my models to automatically add new attributes I may make for them down the line.

My solution? Make a Generic Automatic Form Generator! This will automatically create input fields for my item's attributes, including drop down boxes for any associations that our model might have(if the device belonged to a user through belongs_to :user or something). To create an automatic form generator, just create a partial somewhere, let's make ours app/views/shared/_form_generator.html.erb. Inside it, place the following code:

  <% for column in object.class.columns %>
    <% if column.name != "id" %>
    
<%= f.label "#{column.name}".to_sym %>
<% if column.type == :integer || column.type == :float || column.type == :string %> <% if column.name =~ /_id$/ # is this a id/foreign key field %> <% column_class = column.name.gsub(/_id$/, '').classify.constantize %> <% if column_class %> <%= collection_select(object.class.name.underscore.to_sym, column.name.to_sym, column_class.all, :id, :name, :prompt => true) %> <% else %> <%= f.text_field column.name.to_sym %> <% end %> <% else %> <%= f.text_field column.name.to_sym %> <% end %> <% elsif column.type == :text %> <%= f.text_area column.name.to_sym %> <% elsif column.type == :datetime %> <%= f.datetime_select column.name.to_sym %> <% elsif column.type == :boolean %> <%= f.check_box column.name.to_sym %> <% else %> <% # Unknown Column Type %> <% end %>
<% end %> <% end %>

Then, in your _form.html.erb file for your model, replace this...

  
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :description %>
<%= f.text_field :description %>

...with this...

  <%= render :partial => "shared/form_generator", :locals => {:object => @device, :f => f} %>

And that's it! Now you should be seeing your new form, something that looks like this:

This is Rails 3 friendly, and you can add this to multiple forms if you'd like, since we're using a centralized partial to generate the form. Keep in mind this is a generic generator, not good for any cool custom form stuff. This code can also easily be converted to a helper method, too.


6 Comments

Steve

Mar 01 2011 at 05:37 AM

Hi, Saw this post. Seems interesting. How does it compare with formtastic. I am just new to both, so wanted to get an idea, before committing to an approach.

Thanks.

Dave

Mar 11 2011 at 06:39 PM

This is a super-simple approach to generating form fields, which probably isn't nearly as robust as Formtastic. Instead of being packaged as rails gem, it's just a single file(aka "partial") that's stored in your regular views, so the form generator itself may be easier to customize/edit for your needs. This example is mainly targeted to people interested in writing their own field generator. Formtastic has a similar field generator function(called form.inputs) that'll do something very similar to this example.

If you're not interested in the code behind field generators, and just want a good tool to help you generate forms quickly, I'd probably go with formtastic.

Corey O.

Jun 05 2011 at 10:03 PM

IMO, this is one of the shortcomings of ruby-on-rails. Most of the gurus with whom I have spoke either don't use the scaffold at all, or use it once then never touch it. This is a great little script to use until you get around to putting up proper, custom forms. Thank you.

guest

Jul 09 2011 at 06:28 AM

Looks great but I am not having success with it. Rails 3.0.9 gives:

NoMethodError in Members#edit

Showing C:/.......app/views/shared/formgenerator.html.erb where line #1 raised:

undefined method `columns' for NilClass:Class Extracted source (around line #1):

1: <% for column in object.class.columns %>
2: <% if column.name != "id" %>
3:


4:

Dave

Jul 12 2011 at 08:00 PM

@guest - Hmm, should work on Rails 3.0.9. Did you pass in your object when you rendered your partial?

<%= render :partial => "shared/formgenerator", :locals => {:object => @yourobjectgoeshere, :f => f} %>

DanV

May 09 2012 at 09:26 PM

Great snippet!

I gave this a try and it seems to work pretty well to help me bootstrap my model architecture (I am a noob at rails).

However, the datetime_select field type is not working. I took a quick look at it but its a bit odd. It seems to want the name of the model and the name of the attributes as strings? I am not sure how to derive this information from inside the generator.

Any idea how to get it working?


Add A Comment





Completely Private, used for Gravatar



example: https://www.whatever.com