web-dev-qa-db-fra.com

Séparez les champs de formulaire de date et heure dans Rails

J'ai un modèle ActiveRecord Eventavec une colonne datetime starts_at. J'aimerais présenter un formulaire dans lequel la date et l'heure pour starts_at sont choisies séparément (par exemple, "23-10-2010" pour la date et "18:00" pour l'heure). Ces champs doivent être sauvegardés par la colonne unique starts_at, et les validations doivent aussi être de préférence contre starts_at.

Je peux bien sûr utiliser des attributs virtuels et des crochets, mais j'aimerais une solution plus élégante. J'ai expérimenté avec composed_of ( rdoc ) et attribut-decorator ( lighthouse discussion , github ) sans succès.

Voici un aperçu de ce que je voudrais ..

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

Toute aide appréciée.

40
pgericson

Était à la recherche aujourd'hui pour un projet Rails, et est tombé sur ce joyau:

https://github.com/shekibobo/time_splitter

Définir DateTimes peut être une tâche difficile ou laide, notamment via un formulaire Web. Il est facile de trouver un bon DatePicker ou TimePicker, mais il peut être difficile de les faire travailler tous les deux. TimeSplitter génère automatiquement des accesseurs pour les attributs date, heure, heure et minute de vos attributs date/heure, ce qui rend simple l'utilisation de différentes entrées de formulaire pour définir différentes parties d'un champ date/heure.

On dirait que ça ferait le travail pour vous

9
asgeo1

Devez-vous avoir un text_field dans la vue?

Autant que je sache, vous pouvez avoir un champ date_time puis simplement utiliser deux champs d’entrée différents pour définir les différentes parties du champ.

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

Étant donné que les assistants de sélection de date et d’heure de Rails définissent cinq paramètres différents (starts_at(1i) pour la partie de l’année, 2i pour la partie du mois, etc.), cela signifie que le date_select ne les définit que pour la partie de la date. Si vous passez :ignore_date => true à time_select, il ne définira que les heures et les minutes.

Si vous devez avoir un text_field, je ne sais pas comment le faire, mais il serait peut-être possible d'utiliser un peu de magie jQuery avant de définir les paramètres datetime avant d'envoyer le formulaire.

39
Frost

Utiliser un date_select et un time_select est une bonne façon de faire.

Cependant, je voulais un text_field pour la date (afin de pouvoir utiliser un sélecteur de date JavaScript).

En utilisant strong_parameters ou Rails 4+:

models/event.rb

# Add a virtual attribute
attr_accessor :start_at_date

views/events/_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

controllers/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
  ...
3
d_rail

Une solution élégante peut fournir date_time_attribute gem :

class MyModel < ActiveRecord::Base
  include DateTimeAttribute

  date_time_attribute :starts_at
end

Cela vous permettra de définir starts_at_date et starts_at_time séparément:

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

Cela vous permettra également de jouer avec les fuseaux horaires, d'utiliser Chronic, etc.

2
Sergei Zinin

Est-ce à cause d'un problème de conception? C'est vraiment beaucoup plus facile si vous enregistrez simplement starts_at en tant que type de données datetime et utilisez quelque chose comme:

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

Il s’agit simplement des champs de date que vous avez pour votre modèle.

0
Chris Barretto