Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a label to rails date_select helper

I'm doing an accessibility overhaul on a site at the moment and have come across a problem I don't know how to solve in Rails. The code reads:

<%= f.label :birthdate %>
<%= f.date_select :birthdate, {:start_year => Time.now.year - 14, :end_year => 1900, :prompt => true, :order => [:day, :month, :year]} %>

Which produces:

<label for="birthdate">Birthdate</label>
<select id="birthdate_3i" name="birthdate(3i)">
    <option value="">Day</option>
    <option value="1">1</option>
        ...
    <option value="31">31</option>
</select>
<select id="birthdate_2i" name="birthdate(2i)">
    <option value="">Month</option>
    <option value="1">January</option>
        ...
    <option value="12">December</option>
</select>
<select id="birthdate_1i" name="birthdate(1i)">
    <option value="">Year</option>
    <option value="1998">1998</option>
        ...
    <option value="1900">1900</option>
</select>

Does anyone know if I have to write labels/fieldsets manually for the 3 select fields that have been produced? Or should I be using the rails code differently. I'm a bit new to rails... more of a frontender.

like image 747
johngeorgewright Avatar asked Nov 04 '22 17:11

johngeorgewright


1 Answers

I recently ran into this on a project and we found that the only way to add labels before each select in a Rails date select was to monkey-patch Rails. We are on Rails 5.1.4. Here is the original method that builds the month/day/year selects and puts a separator before the last 2 selects when date_separator is passed as an argument:

https://github.com/rails/rails/blob/2c97fbf6503c9199f3fe5ed06222e7226dc6fcd9/actionview/lib/action_view/helpers/date_helper.rb#L1091

Here is our monkey-patch that puts a legend separator before every date select with the correct for tag:

module ActionView
  module Helpers
    class DateTimeSelector

      # Given an ordering of datetime components, create the selection HTML
      # and join them with their appropriate separators.
      def build_selects_from_types(order)
        select = ""
        order.reverse_each do |type|
          separator = separator(type)
          select.insert(0, separator.to_s + send("select_#{type}").to_s)
        end
        select.html_safe
      end

      # Returns the separator for a given datetime component.
      def separator(type)
        return "" if @options[:use_hidden]
        field_name = "#{@options[:prefix]}_#{@options[:field_name]}"
        case type
          when :year
            "<label for='#{field_name}_1i'>Year</label>"
          when :month
            "<label for='#{field_name}_2i'>Month</label>"
          when :day
            "<label for='#{field_name}_3i'>Day</label>"
          when :hour
            (@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator]
          when :minute, :second
            @options[:"discard_#{type}"] ? "" : @options[:time_separator]
        end
      end
    end
  end
end
like image 70
Jessie A. Young Avatar answered Nov 11 '22 07:11

Jessie A. Young