views:

135

answers:

1

I have a Widget model with inheritance (I'm using Single-Table Inheritance, but it's equally valid for Class-per-Table). Some of the subclasses require a particular field; others do not.

class Widget < ActiveRecord
  ALL_WIDGET_TYPES = [FooWidget, BarWidget, BazWidget]
end

class FooWidget < Widget
  validates_presence_of :color
end

class BarWidget < Widget
  # no color field
end

class BazWidget < Widget
  validates_presence_of :color
end

I'm building a "New Widget" form (app/views/widgets/new.html.erb) and would like to dynamically show/hide the color field based on a <select> for widget_type.

<% form_for @widget do |f| %>
  <%= f.select :type, Widget::ALL_WIDGET_TYPES %>
  <div class='hiddenUnlessWidgetTypeIsFooOrBaz'>
    <%= f.label :color %>
    <%= f.text_field :color %>
  </div>
<% end %>

I can easily write some jQuery to watch for onChange events on widget_type, but that would mean putting some sort of WidgetTypesThatRequireColor constant in my Javascript. Easy enough to do manually, but it is likely to get disconnected from the Widget model classes.

I would prefer not to output Javascript directly in my view, though I have considered using content_for(:js) and have a yield :js in my template footer. Any better ideas?

+2  A: 

Here is the html I would generate. You could generate it from the view or helper in various ways.

<select ...>
    <option class="widget colored">FooWidget</option>
    <option class="widget uncolored">BarWidget</option>
    <option class="widget colored">BazWidget</option>
</select>

Then have jQ watch the select and show or hide the div based on the class of the selected option.

jeem
I love it. This works perfectly. (It's a little awkward to render in Rails, but can easily be extracted into a helper and it provides good separation of concerns.)
James A. Rosen