Some rails projects have components that are little more than glorified CRUD interfaces to a database.
In this particular case, I’m working on a backend administration tool, bolting onto some legacy data.
Parts of the app need to be custom, with a nice GUI using in place editing, etc. But other parts are just a dumb listing of the data, with editing ability.
ActiveRecord::Base has a class method ‘columns’ which returns all of the metadata for the class’ database columns.
Here are a few helpers that you can put in a file, e.g. ‘extensions.rb’ in your config/initializers directory (Rails 2.1):
module ColumnHelperExtensions
def field_columns
columns.select {|c| [:string, :integer].include?(c.type) && !c.primary && !c.name.include?('id') }
end
def date_columns
columns.select {|c| :date == c.type }
end
def boolean_columns
columns.select {|c| :boolean == c.type }
end
end
class ActiveRecord::Base
class << self
include ColumnHelperExtensions
end
end
Your controllers will behave just as normal CRUD (e.g. scaffolded-style) rails controllers.
Here is an example edit.html.erb:
<h2>Editing <%= @foo.name %></h2>
<% form_for @foo do |f| %>
<%= error_messages_for 'foo' %>
<table class="standard_form">
<%= render :partial => 'shared/generic_form', :locals => {:f => f, :klass => SparqUser} %>
</table>
<%= submit_tag "Update Foo »" %>
<% end %>
Then in ‘shared/_generic_form.html.erb’ we tie it all together:
<% klass.field_columns.each do |field| %>
<tr>
<td class="first"><%= f.label(field.name) %></td>
<td><%= f.text_field(field.name) %></td>
</tr>
<% end %>
<% klass.date_columns.each do |field| %>
<tr>
<td class="first"><%= f.label(field.name) %></td>
<td><%= f.date_select(field.name) %></td>
</tr>
<% end %>
<% klass.boolean_columns.each do |field| %>
<tr>
<td class="first"><%= f.label(field.name) %></td>
<td><%= f.check_box(field.name) %></td>
</tr>
<% end %>
When facing the task of maintaining views for a table with 20+ columns, I find this approach, at the very least, a good way to bootstrap a CRUD interface without lots of code bloat.
Note: for this to be effective, your columns have to be named at least somewhat sensibly. If you have a column titled ‘event_date’, this gets labeled ‘Event date’. Obviously a column named ‘trlf_widget_gzy’ will not make much sense to end users when humanized.