Compatible with Rails 5+
Written by Chris Oliver @excid3.
This is a small gem for creating Google Calendar style 12 hour AM/PM time_select fields for Rails. It's based off of simple_time_select by tamoyal.
Just add this into your Gemfile followed by a bundle install:
gem "combined_time_select", "~> 2.0.0"
Here we have a model called Event with the start_time attribute that we will be using with combined_time_select.
Because Rails time_select fields submit separate values, there is some overhead on the controller side when we combine the fields into one. We can't rely on Rails to parse the input into a valid time anymore.
In the view you can do the following:
<%= f.time_select :start_time,
:combined => true,
:default => Time.now.change(:hour => 11, :min => 30),
:minute_interval => 15,
:time_separator => "",
:start_hour => 10,
:start_minute => 30,
:end_hour => 14,
:end_minute => 30
%>
This will create a combined time select starting at 10:30 AM and going till 2:30 PM with 15 minute intervals with a default of 11:30 AM. This will set the value for the start_time attribute on the object this form was created for.
Because combined_time_select
overrides the time_select method to provide you the combined time fields, there is no need to designate a method when using libraries such as Formtastic. You will, however, need to disable the built in hour and minute labels by indicating :labels => false
(though you can still give your individual field a label with :label => "Label Name"
) and to add in the am/pm designation for a 12 hour clock by indicating :ampm => true
.
You can also pass in HTML options as a second hash argument to add attributes like data directly to the html.
<%= form.time_select :time_start, # :time_start here is the datetime object
{
combined: true,
minute_interval: 30,
ampm: true,
time_separator: "",
end_hour: 23,
include_blank: true
}, # options
{
data: { input: "true" }
} # html_options
%>
On the controller side, we need to parse this attribute before we create a new object. combined_time_select provides a nice method for this called parse_time_select!. You can use this in your create action just before you initialize the new model:
def create
params[:event].parse_time_select! :start_time
@event = Event.new params[:event]
end
def update
params[:event].parse_time_select! :start_time
@event = Event.find(params[:event])
if @event.update_attributes params[:event]
...
end
end
And voila! You're all set.
If you would like to include a date with your time_select, you can use date_select
with the same paramter name and the fields will be combined with the time.
<%= form.date_select :event_start %>
<%= form.time_select :event_start, combined: true %>
When the form gets submitted we will recieve a params hash like so:
{"utf8"=>"✓", "event"=>{"start_time(5i)"=>"10:00:00"}, "commit"=>"Save changes"}
A normal time_select wil use start_time(4i) for the hours and start_time(5i) for the minutes. The parse_time_select! will take all the start_time(Xi) fields, parse them into a Time object and set the params[:start_time] attribute to this object. The result after a parse_time_select!(attribute) looks like this:
{"utf8"=>"✓", "event"=>{"start_time"=>Fri, 23 Dec 2011 10:00:00 UTC +00:00}, "commit"=>"Save changes"}
This allows you to also seamlessly use a date_select field in combination with combined_time_select.