17

datetime_selectそれは黒魔術だと思います。私が本当に理解しようとしているのは、全体、、、、1i...複数のパラメータのものです。具体的には、バックエンドでどのように処理されますか(activerecord、他の何か?)。注文番号の後の「i」は何ですか?タイプ指定子ですか?もしそうなら、利用可能な他のタイプは何ですか?date_helper.rbのソースを読みましたが、かなり不透明です。2i3i4i

これが私の動機です:

モデルに:datetime列があり、2つのsを介してビューに入力したいと思いますtext_field。1つは日付用、もう1つは時間用です。それらは検証され、一緒にマージされてから、日時列に格納される必要があります。最終的には、JavaScriptカレンダーを使用して日付フィールドに日付を入力します。

それで、誰かがこれをしましたか?仮想属性(基本的なrailscast以外に非常に文書化されていない)を使用してみましたが、問題は、新しいactiverecordオブジェクトが作成されてnil属性を持つ場合、仮想属性が失敗することでした(strftimenilクラスの未定義のメソッド。これは理にかなっています)。

誰か提案やベストプラクティスがありますか?ありがとう!

4

2 に答える 2

17

同じ質問がありました。これが私が見つけたものです...

http://apidock.com/rails/ActiveRecord/Base/assign_multiparameter_attributes

Assign_multiparameter_attributes(pairs)private

複数のコンストラクターパラメーターを必要とするすべての属性クラスのオブジェクトをインスタンス化します。これは、これらのパラメーターを使用して、列タイプまたは集計タイプ(composed_ofを介して)オブジェクトでnewを呼び出すことによって行われます。したがって、written_on(1)= "2004"、written_on(2)= "6"、written_on(3)= "24"のペアを使用すると、written_on(日付型)がDate.new( "2004"、 "6 "、" 24 ")。括弧内に型キャスト文字を指定して、コンストラクターで使用される前にパラメーターを型キャストすることもできます。Fixnumにはi、Floatにはf、Stringにはs、Arrayにはaを使用します。特定の属性のすべての値が空の場合、属性はnilに設定されます。

したがって、数値は、列のデータ型のパラメーターに対するものです。「i」はそれを整数に変換することです。フロートの「f」など、他のタイプもサポートされています。

ここでは、execute_callstack_for_multiparameter_attributesで、ターゲットタイプを検出し、値を渡してインスタンス化することがわかります。

したがって、提起された質問に直接答えることを試みるために、渡したいフォーマットをサポートしないコンストラクターを使用するため、DateTimeの作成方法をオーバーライドするためにそれを使用することはできないと思います。私の回避策はDateTime列を1つのDate列と1つのTime列に分割します。そうすれば、UIは私が望むように機能することができます。

日付と時刻を別々に表すが、単一のDateTime列を保持する属性アクセサーをクラスに作成できるのではないかと思います。次に、フォームはそれらの個別のアクセサーを参照できます。それは実行可能かもしれません。別のオプションは、composed_ofを使用てタイプをさらにカスタマイズすることです。

それが他の誰かを助けることを願っています。:)

于 2010-11-23T07:40:25.933 に答える
2

これが私が思いついたものです。誰かコメントがあれば教えてください。フィードバックをお待ちしています。

  validate :datetime_format_and_existence_is_valid  
  before_save :merge_and_set_datetime   

  # virtual attributes for date and time allow strings
  # representing date and time respectively to be sent
  # back to the model where they are merged and parsed
  # into a datetime object in activerecord
  def date
    if (self.datetime) then self.datetime.strftime "%Y-%m-%d"
    else @date ||= (Time.now + 2.days).strftime "%Y-%m-%d" #default
    end
  end
  def date=(date_string)
    @date = date_string.strip
  end
  def time
    if(self.datetime) then self.datetime.strftime "%l:%M %p"
    else @time ||= "7:00 PM" #default
    end
  end
  def time=(time_string)
    @time = time_string.strip
  end

  # if parsing of the merged date and time strings is
  # unsuccessful, add an error to the queue and fail
  # validation with a message
  def datetime_format_and_existence_is_valid    
    errors.add(:date, 'must be in YYYY-MM-DD format') unless
      (@date =~ /\d{4}-\d\d-\d\d/) # check the date's format
    errors.add(:time, 'must be in HH:MM format') unless # check the time's format
      (@time =~ /^((0?[1-9]|1[012])(:[0-5]\d){0,2}(\ [AaPp][Mm]))$|^(([01]\d|2[0-3])(:[0-5]\d){0,2})$/)
    # build the complete date + time string and parse
    @datetime_str = @date + " " + @time
    errors.add(:datetime, "doesn't exist") if 
      ((DateTime.parse(@datetime_str) rescue ArgumentError) == ArgumentError)
  end

  # callback method takes constituent strings for date and 
  # time, joins them and parses them into a datetime, then
  # writes this datetime to the object
  private
  def merge_and_set_datetime
    self.datetime = DateTime.parse(@datetime_str) if errors.empty?
  end
于 2009-10-08T14:12:00.063 に答える