2010-09-09 7 views
41

Tengo un modelo ActiveRecord Event con una columna de fecha y hora starts_at. Me gustaría presentar un formulario, donde la fecha y la hora para starts_at se eligen por separado (por ejemplo, "23-10-2010" para la fecha y "18:00" para el tiempo). Estos campos deben estar respaldados por la única columna starts_at, y las validaciones deben estar preferiblemente en contra de starts_at, también.Separe los campos de fecha y hora en Rails

Puedo, por supuesto, perder el tiempo con atributos virtuales y ganchos, pero me gustaría una solución más elegante. He experimentado tanto con composed_of (rdoc) como con atributo decorador (lighthouse discussion, github) sin éxito.

A continuación se muestra un esbozo de lo que me gustaría ..

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 

Cualquier ayuda apreciada.

+0

Me he encontrado con esto varias veces pero todavía no he encontrado una buena solución. La razón para dividirlo es para poder usar un datepicker y time_select por separado. – benvds

Respuesta

9

estaba mirando esto hoy para un proyecto de rieles, y encontré esta joya:

https://github.com/shekibobo/time_splitter

DateTime ajuste puede ser una cosa difícil o feo, especialmente a través de un formulario web. Encontrar un buen DatePicker o TimePicker es fácil, pero lograr que trabajen en ambos puede ser difícil. TimeSplitter genera automáticamente descriptores de acceso para fecha, hora, hora y minuto en sus atributos de fecha y hora, por lo que es trivial utilizar entradas de formularios diferentes para establecer diferentes partes de un campo de fecha y hora.

parece que sería hacer el trabajo para usted

+0

¿Hay alguna manera de configurar la zona horaria para esta joya? Siempre se guarda en UTC. –

+0

En mis pruebas estaba usando la zona horaria configurada. ¿Estás seguro de que lo estás configurando correctamente? – asgeo1

+0

Intenté usar esta gema y me encontré con un problema de inmediato http://stackoverflow.com/questions/29858627/time-splitter-gem-getting-uninitialized-constant-sheettimesplitter –

0

¿Esto es debido a un problema de diseño? En realidad es mucho más fácil si sólo guarda starts_at como un tipo de datos de fecha y hora y usar algo como:

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

Simplemente se ejecuta por encima de cualquier campos de fecha que tiene para su modelo.

+1

No, no es un problema de diseño. Los datos deben ser una sola columna, mientras que el generador de formularios debe manejar 2 atributos diferentes para esa misma columna. – benvds

38

¿Tienes que tener un text_field en la vista?

Por lo que puedo decir, puede tener un campo date_time y luego simplemente usar dos campos de entrada diferentes para establecer las diferentes partes del campo.

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

Dado que la fecha y hora rieles seleccione ayudantes establecen cinco parámetros diferentes (starts_at(1i) para la parte del año, 2i para la parte correspondiente al mes, y así sucesivamente), eso significa que el date_select sólo los conjuntos de la parte de fecha, mientras que si pasa al time_select, solo establecerá la parte de la hora y el minuto.

Si debe tener un text_field no estoy seguro de cómo hacerlo, pero podría ser posible utilizar algo de magia jQuery antes de establecer los parámetros de fecha y hora antes de enviar el formulario.

+1

Bueno, parece funcionar y es una buena solución. Pero lo que realmente me gustaría ver es una forma de dividir y reconstruir atributos alrededor del asistente de formularios. P.ej. before_form_build y before_form_validation. – benvds

+0

Entonces creo que tendrías que hacer algo de hackeo manual en hash de params. – Frost

2

solución elegante pueda suministrar date_time_attribute gem:

class MyModel < ActiveRecord::Base 
    include DateTimeAttribute 

    date_time_attribute :starts_at 
end 

Se le permitirá configurar starts_at_date y starts_at_time por separado:

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 

También te permitirá jugar con husos horarios, usar Crónica, etc.

+0

¿Estás seguro de que puedes mezclar 'date_select' y 'text_field'? No pude usar 'text_field' y' time_select' y no hay documentación que pueda mostrar. –

+0

No necesita incluir el módulo DateTimeAttribute, como se dice en el archivo README del repositorio de la gema: https://github.com/einzige/date_time_attribute#rails-users –

3

Usar un date_select y time_select es un buen camino a seguir.

Sin embargo, quería un text_field para la fecha (para que pueda usar un selector de fecha JavaScript).

Usando strong_parameters o rieles de + 4:

modelos/event.rb

# Add a virtual attribute 
attr_accessor :start_at_date 

vistas/eventos/_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 

controladores/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

¿Por qué usa '!!' en el *** si *** comparación? ¿Qué significa eso? –

+0

Convierte el valor en booleano (http://stackoverflow.com/questions/524658/what-does-mean-in-ruby), probablemente no sea necesario. –

+0

Sí, eso es lo que pensé, pero de todos modos gracias por la respuesta. :) –

Cuestiones relacionadas