2009-09-23 81 views
16

我相信datetime_select是黑魔法。我真的想弄清楚的是整個1i,2i,3i,4i ......多個參數的東西。具體來說,它是如何處理後端(activerecord,別的?)。訂單號後面的「我」是什麼?它是一個類型說明符?如果是的話,還有其他什麼類型可用?我讀過date_helper.rb的源代碼,它非常不透明。軌道上的紅寶石多參數屬性*真的*工作(datetime_select)

這裏是我的動力:

我已經在我的模型有一個:datetime列,我想在通過兩個text_field S上觀看輸入:一個日期和一個時間。他們需要驗證,合併在一起,然後存儲到日期時間列中。最終,我將使用javascript日曆將日期輸入日期字段。

那麼有人做到這一點?我嘗試使用虛擬屬性(令人難以置信的是除了基本的railscast以外沒有記錄),問題是當一個新的activerecord對象被創建並且具有nil屬性時,虛擬屬性失敗(對於nil類未定義方法strftime,這是合理的)。

任何人有任何建議或最佳做法?謝謝!

+0

in activerecord/base.rb [assign_multiparameter_attributes]爲需要多個構造函數參數的所有屬性類實例化對象。這通過使用這些參數在列或聚合類型對象上調用new來工作。即:written_on(1)=「2004」,written_on(2)=「6」,written_on(3)=「24」,將實例化具有Date.new(「2004」,「6」,「 「24」)。您還可以在括號中指定一個類型轉換字符,以在參數在構造函數中使用之前對其進行類型化。 Fixnum使用i,Float使用f,String使用i,數組使用a。 – 2009-09-23 19:22:16

+1

嗨,Dean,如果你找到了自己的答案,通常的做法是「回答我自己的問題」,以便人們可以看到問題已經解決。 – nfm 2009-09-23 23:53:02

回答

18

我有同樣的問題。這裏是我的發現......

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

assign_multiparameter_attributes(對) 私人

實例化對象的所有屬性 類需要一個以上的 構造函數的參數。這是通過 在列類型上調用新的或 聚合類型(通過composed_of) 具有這些參數的對象來完成的。因此 的書寫子(date)類型爲 ,其中的書寫子(date)類型爲 Date.new(「1」)= 「2004」,written_on(2)=「6」, written_on 2004「,」6「,」24「)。您可以在 構造函數中使用 時指定一個類型轉換字符 括號將其參數 進行了類型化。使用i作爲Fixnum,f代表 Float,s代表字符串,a代表數組。 如果給定的 屬性的所有值都爲空,則屬性 將設置爲零。

所以這些數字是針對該列的數據類型的參數。 「我」是將其轉換爲整數。其他類型支持像浮點「f」等。

您可以在execute_callstack_for_multiparameter_attributes中看到它檢測到目標類型並實例化它傳遞的值。

因此,要直接回答提出的問題,我不認爲你可以用它來重寫DateTime的創建方式,因爲它使用不支持你想要傳遞的格式的構造函數。我的工作最後是將DateTime列分成一個日期和一個時間列。然後用戶界面可以按我想要的方式工作。

我想知道是否可以在類上創建屬性訪問器來分別代表日期和時間,但保留單個DateTime列。然後表單可以引用這些單獨的訪問器。這可能是可行的。另一個選項可能是使用composed_of來進一步定製類型。

希望能幫助別人。 :)

+0

是的。我正在使用虛擬屬性。 – Ricky 2012-02-19 00:28:42

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

查看日期驗證的validates_timeliness,更容易。另請參閱Date :: DATE_FORMATS AND Time :: DATE_FORMATS,以獲得更多可用於創建更多格式的更好方法。例如,我添加了一個格式,如Date :: DATE_FORMATS [:in_words] =「%b%e,%Y」,然後你可以在初始化程序中說Date.today.to_s(:in_words)。 – brad 2010-01-19 17:27:31

+0

當你剛剛閱讀一個屬性時,最好使用「if(datetime)」... – Scholle 2011-07-02 15:53:49

+0

@Sololle我不同意,當與其他開發人員一起工作時,我想知道某個屬性是屬性還是屬性私人方法。這是我如何發信號... – OneChillDude 2014-03-02 17:31:03