text_fieldのvalue(datetime)のフォーマット

<% @journal.datetime = Time.now unless @journal.datetime %>
<%= text_field 'journal', "datetime" %></p>

こんなviewを書いて@journal.datetime有り/無しを試してみると。

  • あり
2007-11-01 00:00:00
  • なし
Sat Dec 08 23:43:40 +0900 2007

ちなみに、debugで表示させると

2007-12-08 23:43:40.268200 +09:00

to_sまたはinspectすると

Sat Dec 08 23:43:40 +0900 2007

となる。はて?text_fieldのvalueは何を表示させているのか?

まず、action_view/helpers/form_helper.rbのdef text_fieldをながめてみると、

def text_field(object_name, method, options = {})
  InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("text", options)
end

となっているので、

      def initialize(object_name, method_name, template_object, local_binding = nil, object = nil)
        @object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup
        @template_object, @local_binding = template_object, local_binding
        @object = object
        if @object_name.sub!(/\[\]$/,"")
          if object ||= @template_object.instance_variable_get("@#{Regexp.last_match.pre_match}") and object.respond_to?(
:id_before_type_cast)
            @auto_index = object.id_before_type_cast
          else
            raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to id_bef
ore_type_cast: #{object.inspect}"
          end
        end
      end
        :
      def to_input_field_tag(field_type, options = {})
        options = options.stringify_keys
        options["size"] ||= options["maxlength"] || DEFAULT_FIELD_OPTIONS["size"]
        options = DEFAULT_FIELD_OPTIONS.merge(options)
        if field_type == "hidden"
          options.delete("size")
        end
        options["type"] = field_type
        options["value"] ||= value_before_type_cast(object) unless field_type == "file"
        add_default_name_and_id(options)
        tag("input", options)
      end

を見てみると、どうもoptions["value"]に代入しているvalue_before_type_cast(object)が怪しそうだ。

      def value_before_type_cast(object)
        self.class.value_before_type_cast(object, @method_name)
      end
        :
      class << self
        def value_before_type_cast(object, method_name)
          unless object.nil?
            object.respond_to?(method_name + "_before_type_cast") ?
            object.send(method_name + "_before_type_cast") :
            object.send(method_name)
          end
        end

find . -name '*.rb' | xargs grep _before_type_castとかしてみると、

があやしそうだが… この辺からはARのソースをきちんと追ってく必要がありそうだ。今まで追ってなかったのだ。

と、途方にくれたのもつかの間、こんなソースコメントが。

# == Accessing attributes before they have been typecasted
#
# Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its co
urse first.
# That can be done by using the <attribute>_before_type_cast accessors that all attributes have. For example, if your A
ccount model
# has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast.

よっしゃ〜。

<%= debug @journal.datetime_before_type_cast %>

とすると、

2007-12-09 00:30:42.612479 +09:00

期待通りの結果が得られた。もう風呂に入りたいのでここまで。