How do I DRY up business logic between sever-side Ruby and client-side Javascript?
- by James A. Rosen
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?