2010-09-09 5 views
41

Ho un modello ActiveRecord Event con una colonna datetime starts_at. Vorrei presentare un modulo, in cui data e ora per starts_at vengono scelti separatamente (ad esempio "23-10-2010" per la data e "18:00" per il tempo). Questi campi devono essere supportati dalla singola colonna starts_at e le convalide dovrebbero preferibilmente essere contro starts_at.Campi modulo data e ora separati in Rails

Ovviamente posso andare in giro con attributi e ganci virtuali, ma vorrei una soluzione più elegante. Ho sperimentato sia con composed_of (rdoc), sia con attributo-decoratore (lighthouse discussion, github) senza successo.

Qui di seguito è un abbozzo di quello che vorrei ..

class Event < ActiveRecord::Base 
    validates_presence_of :start_date 
end 

# View 
# On submission this should set start_date. 
form_for @event do |f| 
    f.text_field :starts_at_date   # date-part of start_date 
    f.text_field :starts_at_time_of_day # time-of-day-part of start_date 
    f.submit 
end 

Qualsiasi aiuto apprezzato.

+0

Mi sono imbattuto in questo alcune volte ma non ho ancora trovato una soluzione piacevole. La ragione per dividerlo è che posso usare separatamente un datepicker e il time_select. – benvds

risposta

9

stava guardando questo oggi per un progetto Rails, ed è venuto in questo gioiello:

https://github.com/shekibobo/time_splitter

Impostazione DateTimes può essere una cosa difficile o brutto, in particolare attraverso un modulo web. Trovare un buon DatePicker o TimePicker è facile, ma farli lavorare su entrambi può essere difficile. TimeSplitter genera automaticamente accessor per data, ora, ora e min sugli attributi datetime o time, rendendo banale l'uso di input di moduli diversi per impostare parti diverse di un campo datetime.

sembra che sarebbe fare il lavoro per voi

+0

C'è un modo per impostare il fuso orario per questa gemma? Salva sempre in UTC. –

+0

Nel mio test stava usando il fuso orario configurato. Sei sicuro di averlo impostato correttamente? – asgeo1

+0

Ho provato a utilizzare questo gioi e ho subito un problema http://stackoverflow.com/questions/29858627/time-splitter-gem-getting-uninitialized-constant-sheettimesplitter –

0

È a causa di un problema di progettazione? E 'davvero molto più facile se si salva starts_at come un tipo di dati datetime e utilizzare qualcosa come:

http://puna.net.nz/timepicker.htm#

Funziona semplicemente sulla cima di qualsiasi campi data, sarà necessario per il vostro modello.

+1

No, non è un problema di progettazione. I dati dovrebbero essere una singola colonna mentre il generatore di moduli dovrebbe gestire 2 diversi attributi per quella stessa colonna. – benvds

38

Devi avere un text_field nella vista?

Per quanto posso dire, è possibile avere un campo date_time e quindi utilizzare solo due campi di input diversi per impostare le diverse parti del campo.

form_for @event do |f| 
    f.date_select :starts_at 
    f.time_select :starts_at, :ignore_date => true 
    f.submit 
end 

Dal momento che la data e l'ora rotaie selezionare aiutanti impostare cinque diversi parametri (starts_at(1i) per la parte dell'anno, 2i per la parte mese, e così via), ciò significa che il date_select li imposta solo per la parte relativa alla data, mentre se si passa allo time_select, verrà impostata solo la parte delle ore e dei minuti.

Se è necessario un text_field, non sono sicuro di come farlo, ma potrebbe essere possibile utilizzare alcune magie jQuery prima di impostare i parametri datetime prima di inviare il modulo.

+1

Bello, sembra funzionare e abbastanza buono per una soluzione. Ma quello che mi piacerebbe davvero vedere è un modo per dividere e ricostruire gli attributi attorno all'aiutante della forma. Per esempio. before_form_build e before_form_validation. – benvds

+0

Quindi penso che avresti bisogno di fare un po 'di hacking manuale sull'hash params. – Frost

2

soluzione elegante possa fornire date_time_attribute gem:

class MyModel < ActiveRecord::Base 
    include DateTimeAttribute 

    date_time_attribute :starts_at 
end 

Essa vi permetterà di impostare starts_at_date e starts_at_time separatamente:

form_for @event do |f| 
    f.text_field :starts_at_date 
    f.text_field :starts_at_time 
    f.submit 
end 

# this will work too: 
form_for @event do |f| 
    f.date_select :starts_at_date 
    f.time_select :starts_at_time, :ignore_date => true 
    f.text_field :starts_at_time_zone 
    f.submit 
end 

# or 
form_for @event do |f| 
    f.date_select :starts_at_date 
    f.text_field :starts_at_time 
    f.submit 
end 

Ti permetterà anche di giocare con i fusi orari, usare Chronic ecc.

+0

Sei sicuro di poter mischiare 'date_select' e 'text_field'? Non ero in grado di usare un 'text_field' e' time_select' e non c'è documentazione che mostra che puoi. –

+0

Non è necessario includere il modulo DateTimeAttribute, come detto nel README del repository della gemma: https://github.com/einzige/date_time_attribute#rails-users –

3

Utilizzando un date_select e time_select è un buon modo per andare.

Tuttavia, volevo un text_field per la data (quindi posso utilizzare un selettore di date JavaScript).

Utilizzando strong_parameters o Rails 4+:

modelli/event.rb

# Add a virtual attribute 
attr_accessor :start_at_date 

views/eventi/_form.html.haml

- # A text field for the date, and time_select for time 
= f.label :start_at 
= f.text_field :start_at_date, value: (f.object.start_at.present? ? f.object.start_at.to_date : nil) 
= f.time_select :start_at, :ignore_date => true 

controllori/events_controller.rb

# If using a date_select, time_select, datetime_select 
# Rails expects multiparameter attributes 
# Convert the date to the muiltiparameter parts 
def event_params 
    if !!params[:event] && (params[:event]["start_at(4i)"].present? || params[:event]["start_at(5i)"].present?) 

    if params[:event][:start_at_date].present? 
     start_at_date = params[:event][:start_at_date] 
    else 
     start_at_date = Date.today 
    end 
    year = start_at_date.match(/^(\d{4})[\-\/]/)[1] 
    month = start_at_date.match(/[\-\/](\d{2})[\-\/]/)[1] 
    day = start_at_date.match(/[\-\/](\d{2})$/)[1] 
    params[:event]["start_at(1i)"] = year 
    params[:event]["start_at(2i)"] = month 
    params[:event]["start_at(3i)"] = day 
    end 
    ... 
+0

Perché si usa '!!' nel *** se confronto ***? Che cosa significa questo? –

+0

Converte il valore in un valore booleano (http://stackoverflow.com/questions/524658/what-does-mean-in-ruby), probabilmente non richiesto. –

+0

Sì, questo è quello che ho pensato, ma comunque grazie per la risposta. :) –