2009-09-23 7 views
16

Credo che datetime_select sia una magia nera. Quello che sto cercando di capire è l'intero 1i, 2i, 3i, 4i ... più parametri. In particolare come viene gestito nel back-end (activerecord, qualcos'altro?). Cosa c'è nella "i" dopo il numero d'ordine? È un identificatore di tipo? Se sì, quali sono gli altri tipi disponibili? Ho letto l'origine di date_helper.rb ed è piuttosto opaco.Come funzionano gli attributi multieffetto ruby ​​on rails * really * work (datetime_select)

Ecco la mia motivazione:

Ho una colonna di :datetime nel mio modello e voglio di ingresso nella visualizzazione tramite due text_field s: uno per la data e una per volta. Devono essere convalidati, uniti insieme, quindi archiviati nella colonna datetime. In definitiva userò un calendario javascript per inserire le date nel campo della data.

Quindi qualcuno ha fatto questo? Ho provato ad utilizzare attributi virtuali (incredibilmente privi di documenti oltre al rudimentale railscast) e il problema era che quando un nuovo oggetto activerecord viene creato e ha attributi nil, l'attributo virtuale fallisce (metodo non definito strftime per la classe nil, che ha senso).

Qualcuno ha suggerimenti o buone pratiche? Grazie!

+0

in activerecord/base.rb [assign_multiparameter_attributes] crea un'istanza di oggetti per tutte le classi di attributi che richiedono più di un parametro del costruttore. Funziona chiamando la nuova colonna o l'oggetto del tipo di aggregazione con questi parametri. cioè: written_on (1) = "2004", written_on (2) = "6", written_on (3) = "24", crea un'istanza scritta_on (un tipo di data) con Date.new ("2004", "6", "24"). Puoi anche specificare un carattere typecast tra parentesi per fare in modo che i parametri siano tipizzati prima di essere utilizzati nel costruttore. Usa i per Fixnum, f per Float, s per String e a per Array. –

+1

Ciao Dean, se hai trovato la tua risposta, il solito approccio è "Rispondi alla mia domanda" in modo che le persone possano vedere che la domanda è stata risolta. – nfm

risposta

18

Ho avuto la stessa domanda. Ecco cosa ho trovato ...

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

assign_multiparameter_attributes (coppie) privato

un'istanza di oggetti per tutti gli attributi le classi che ha bisogno più di un parametro costruttore. Questo è fatto da chiamando nuovo sul tipo di colonna o tipo di aggregazione (attraverso composed_of) oggetto con questi parametri. Così avente le coppie written_on (1) = "2004", written_on (2) = "6", written_on (3) = "24", sarà istanziare written_on (un tipo di data) con Date.new (" 2004 "," 6 "," 24 "). È possibile inoltre specificare un carattere typecast in tra parentesi per le parentesi con i parametri prima che vengano utilizzati nel costruttore . Utilizzare i per Fixnum, f per Float, s per String e a per Array. Se tutti i valori per un determinato attributo sono vuoti, l'attributo verrà impostato su zero.

Quindi i numeri sono per i parametri del tipo di dati che è la colonna. "I" è convertirlo in un numero intero. Altri tipi sono supportati come "f" per float, ecc.

È possibile vedere qui in execute_callstack_for_multiparameter_attributes che rileva il tipo di obiettivo e lo istanzia passando i valori.

Quindi, per provare a rispondere direttamente alla domanda posta, non penso che tu possa usarlo per sovrascrivere il modo in cui viene creato un DateTime perché usa il costruttore che non supporta il formato che vuoi passare. Il mio lavoro -avrebbe dovuto dividere la colonna DateTime in una colonna Date e una Time. Quindi l'interfaccia utente potrebbe funzionare come volevo.

Mi chiedo se sia possibile creare accessors di attributi sulla classe che rappresentano separatamente la data e l'ora ma mantenere una singola colonna DateTime. Quindi il modulo potrebbe fare riferimento a tali accessorie separati. Potrebbe essere praticabile. Un'altra opzione potrebbe essere quella di utilizzare composed_of per personalizzare ulteriormente il tipo.

Spero che aiuti qualcun altro. :)

+0

Sì. Vado con attributi virtuali. – Ricky

2

Ecco cosa ho trovato. Se qualcuno ha dei commenti, fammi sapere. Mi piacerebbe avere un feedback.

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

Check out validates_timeliness per le convalide della data, molto più semplice. Guarda anche Date :: DATE_FORMATS AND Time :: DATE_FORMATS, per un modo migliore di creare più formati che puoi riutilizzare. Ad esempio, aggiungo un formato come Date :: DATE_FORMATS [: in_words] = "% b% e,% Y" e puoi quindi pronunciare Date.today.to_s (: in_words) in un inizializzatore. – brad

+0

Non c'è bisogno di prefisso self. * Quando leggi un attributo, meglio usare "if (datetime)" ... – Scholle

+0

@Scholle Non sono d'accordo, quando lavoro con altri sviluppatori mi piace sapere se qualcosa è un attributo o un metodo privato. Ecco come faccio a segnalare che ... – OneChillDude