PullMonkey Blog

19 Dec

Rails date select bug with discard and disable


Code that breaks

1
2
3
4
5
6
7
8

<%= date_select "object", "attr", 
                 :index       => "", 
                 :start_year  => Date.today.year, 
                 :discard_day => true, 
                 :disabled    => true, 
                 :order       => [:month, :year] %>

HTML that is produced

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<input id="object__attr_3i" 
       type="hidden" 
       value="1" 
       name="object[object_attributes][][attr(3i)]"/>
<select id="object_attr_attributes__attr_2i" 
        disabled="disabled" 
        name="object[object_attributes][][attr(2i)]">
...
</select>
<select id="object_attributes__attr_1i" 
        disabled="disabled" 
        name="object[object_attributes][][attr(1i)]">
...
</select>

The Problem

Note that this may be fixed now in version 2.0 of rails. So the problem arises when you use both the options of disabled and discard for the date_select helper. By themselves they work fine and without problems. When you use them together the discard option overrides the disabled option. In the example above, I discard the day and want the entire element to be disabled. The resulting HTML hides the day selector but does not disable it. So, when the form is submitted the date select day is bundled in with the rest of the parameters as a hash of just the day. If it had been hidden and disabled, then we could have ignored it.

The offending Rails Helper code

hidden_html(...) is used anytime discard_<something> is set to true.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

module ActionView
  module Helpers
    ...
    module DateHelper
      ...
      def hidden_html(type, value, options)
        name_and_id_from_options(options, type)
        hidden_html = %(<input type="hidden" id="#{options[:id]}" name="#{options[:name]}" value="#{value}" />\n)
      end
      ...
    end
  end
end

The fix

Note that in the above code there is no reference to the disabled parameter that was set. Using a mixin, you can create a file in RAILS_ROOT/lib named date_select_fix.rb with the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

module ActionView
  module Helpers
    ...
    module DateHelper
      ...
      def hidden_html(type, value, options)
        name_and_id_from_options(options, type)
        hidden_html = %(<input type="hidden" id="#{options[:id]}" name="#{options[:name]}" value="#{value}"#{" disabled=\"disabled\"" if options[:disabled]} />\n)
      end
      ...
    end
  end
end

Works for me. Just for the record, the project that I found this bug in is still using rails 1.2.1 and actionpack 1.13.1.


Filed under: development, Home, rails, ruby

Sorry, comments for this entry are closed at this time.