【问题标题】:Adding a label to rails date_select helper向 rails date_select 助手添加标签
【发布时间】:2012-08-17 09:48:38
【问题描述】:

我目前正在对一个网站进行可访问性大修,遇到了一个我不知道如何在 Rails 中解决的问题。代码如下:

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

产生:

<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>

有谁知道我是否必须为已生成的 3 个选择字段手动编写标签/字段集?或者我应该以不同的方式使用 rails 代码。我对 Rails 有点陌生……更多的是前端。

【问题讨论】:

    标签: html ruby-on-rails ruby forms accessibility


    【解决方案1】:

    有一种方法不包括修补 Rails。不过,它仍然很hacky。这个想法是增加date_select 生成的选择标签。我们将使用 Nokogiri 来执行此操作(在 Gemfile 中需要 gem 'nokogiri')。

    下面的代码将date_select_with_labels 添加到执行此操作的库存表单构建器中:

    class ActionView::Helpers::FormBuilder
      def date_select_with_labels(attribute, options = {})
        generated_selects = @template.date_select(object.model_name.singular, attribute, options)
    
        selects_with_labels = Nokogiri::HTML::Document.parse(generated_selects).css('select').map do |select|
          label(
            attribute,
            date_select_part_type_from_options(select, options[:include_blank]),
            options.reverse_merge(for: select.attr('id'))
          ) +
            select.to_s.html_safe
        end
    
        @template.content_tag(:div) do
          selects_with_labels.join('').html_safe
        end
      end
    
      private
    
      def date_select_part_type_from_options(select, include_blank)
        maybe_one = include_blank ? 1 : 0
    
        case select.css('option').size
        when 12 + maybe_one
          'Month'
        when (28 + maybe_one)..(31 + maybe_one)
          'Day'
        else
          'Year'
        end
      end
    end
    

    【讨论】:

      【解决方案2】:

      我最近在一个项目中遇到了这个问题,我们发现在 Rails 日期选择中每个 select 之前添加标签的唯一方法是对 Rails 进行猴子补丁。我们在 Rails 5.1.4 上。当date_separator 作为参数传递时,这是构建月/日/年选择并在最后两个选择之前放置分隔符的原始方法:

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

      这是我们的猴子补丁,它在每个日期选择之前放置一个图例分隔符,并带有正确的for标签:

      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
      

      【讨论】:

      • 这正是我需要让这些date_selects 可访问。
      • 只是为了补充信息,我将其保存在config/initializers/date_time_selector.rb 覆盖超类。
      【解决方案3】:

      只需将date_select 包裹在divfieldset 中。标签可以指向任何具有 ID 的东西,如果您有多个输入到一个数据类型中(如 rails date_select),那么您可以为容器添加标签,并让选择框成为它的组件。

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

      【讨论】:

        【解决方案4】:

        我认为不可能生成单独的标签。即使您愿意接受一个标签,还有一个附加问题是它不是严格有效的 HTML,因为没有“生日”表单控件。你应该在标签助手中使用 :birthdate_3i 吗?

        【讨论】:

          【解决方案5】:
          date_select("DOB", :birthdate, :prompt => {
          :day => 'Select day', :month => 'Select month', :year => 'Select year',
          :start_year => Time.now.year - 14, :end_year => 1900
          })
          

          更多选项:
          http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-date_select

          【讨论】:

          • 谢谢迈克尔。我现在看到了“提示”选项的作用。但我真正想要的是为生成的选择框添加标签。我不确定它是否可行,所以我想我将它包装在一个带有图例的字段集中。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-01-26
          • 2013-05-18
          • 1970-01-01
          • 2019-11-06
          相关资源
          最近更新 更多