オプションがわからないのでソースみた(datetime_select編)

datetime_select使うとき、オプションがわからなかったんで調べた方法と結果を晒しまふ。
datetime_selectって、年月日時分まで表示してくれるんですが、英語で月を表示してるのと今回の要件だと
年月日しか要らなかったので、表示を変えたいなーと思ってソース調べました。*1


てか、基本的なヘルパがわからないあたり、こいつコード弄ってねえじゃん(プ
みたいな・・・・。


ralisのソースにgrep をかける。
grep -R datetime_select vendor/rails | grep def

そしたら、actionpack/lib/action_view/helpers/date_helper.rbに書いてあったので、これを開く。

      def datetime_select(object_name, method, options = {})
        InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datetime_select_tag(options)
      end

というわけで、InstanceTagを探す。
date_helper.rb内部にありました。

    class InstanceTag #:nodoc:
      include DateHelper
       …(略)…

んー、InstanceTagクラスを作成してその内部メソッドのto_datetime_select_tagを呼び出してるっぽいですね。
っていうわけで、to_datetime_select_tagを探します。

      def to_datetime_select_tag(options = {})
        date_or_time_select options
      end

もろ呼び出してるだけなので、date_or_time_selectを探しに行きます。

        def date_or_time_select(options)
          defaults = { :discard_type => true }
          options  = defaults.merge(options)
          datetime = value(object)
          datetime ||= Time.now unless options[:include_blank]

          position = { :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6 }

          order = (options[:order] ||= [:year, :month, :day])

          # Discard explicit and implicit by not being included in the :order
          discard = {}
          discard[:year]   = true if options[:discard_year] or !order.include?(:year)
          discard[:month]  = true if options[:discard_month] or !order.include?(:month)
          discard[:day]    = true if options[:discard_day] or discard[:month] or !order.include?(:day)
          discard[:hour]   = true if options[:discard_hour]
          discard[:minute] = true if options[:discard_minute] or discard[:hour]
          discard[:second] = true unless options[:include_seconds] && !discard[:minute]

          # Maintain valid dates by including hidden fields for discarded elements
          [:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
          # Ensure proper ordering of :hour, :minute and :second
          [:hour, :minute, :second].each { |o| order.delete(o); order.push(o) }

          date_or_time_select = ''
          order.reverse.each do |param|
            # Send hidden fields for discarded elements once output has started
            # This ensures AR can reconstruct valid dates using ParseDate
            next if discard[param] && date_or_time_select.empty?

            date_or_time_select.insert(0, self.send("select_#{param}", datetime, options_with_prefix(position[param], options.merge(:use_hidden => discard[param]))))
            date_or_time_select.insert(0,
              case param
                when :hour then (discard[:year] && discard[:day] ? "" : " — ")
                when :minute then " : "
                when :second then options[:include_seconds] ? " : " : ""
                else ""
              end)

          end

          date_or_time_select
        end

これでやってますねー。ってことで、:discard_hourオプションを与えてあげれば時、分って無くなるってわかったんですが、月が英語の理由がわかんねーっす。
途中で date_or_time_select.insert(0, self.send("select_#{param}", datetime, options_with_prefix(position[param], options.merge(:use_hidden => discard[param]))))って一行がありますが、ここでselect_yearとかselect_monthとか呼び出してそれぞれの値出してるみたいなので、monthの部分を見ます。

      def select_month(date, options = {})
        val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
        if options[:use_hidden]
          hidden_html(options[:field_name] || 'month', val, options)
        else
          month_options = []
          month_names = options[:use_month_names] || (options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES)
          month_names.unshift(nil) if month_names.size < 13
          1.upto(12) do |month_number|
            month_name = if options[:use_month_numbers]
              month_number
            elsif options[:add_month_numbers]
              month_number.to_s + ' - ' + month_names[month_number]
            else
              month_names[month_number]
            end

            month_options << ((val == month_number) ?
              %(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
              %(<option value="#{month_number}">#{month_name}</option>\n)
            )
          end
          select_html(options[:field_name] || 'month', month_options, options)
        end
      end

なんかuse_month_numbersがあれば、数字をそのまま返してるみたいなので、use_month_number使えばOKとわかりました。


実はコメントにきちんと書いてあってそれ読めば良いんですが、英語が苦手なので英語のコメントよりソースの方先に読んだりする……。
俺のバーカ。

*1:date_selectで良いじゃん。と言うオチ。この日記書く為に調べてたらそのヘルパの存在を思い出したorz