0

I am trying to use Tempus Dominus Bootstrap 4 in a form on a Ruby on Rails 5.2 app so the user can select a date. Here is the code:

app/views/events/_form.html.erb

<div class='form-group'>
  <%= f.label :starts_at, 'Start Date and Time', class: 'control-label' %>
  <div class="input-group date" id="datetimepicker1" data-target-input="nearest">
    <%= f.text_field(:starts_at, class: "form-control datetimepicker-input", data: {target:"#datetimepicker1"}) %>
    <div class="input-group-append" data-target="#datetimepicker1" data-toggle="datetimepicker">
      <div class="input-group-text"><i class="fas fa-calendar-plus"></i></div>
    </div>
  </div>
</div>

app/assets/javascripts/events.js

$(function () {
  $('#datetimepicker1').datetimepicker();
});

app/controllers/events_controller.rb

  def create
    @event = Event.new(event_params)
    @event.user = current_user
    if @event.save
      redirect_to @event, notice: 'Event was successfully created.' 
    else
      render :new 
    end
  end

I want to submit the format with month first. When I pick a date June 9, 2018 and submit the form, it saves it to the database with the month and day reversed: Sept 6, 2018. When I look at the params after the form is submitted, the format is 06/09/2018 6:00 PM with month first, but Ruby/Rails converts it to a datetime object assuming day first.

How do I tell Ruby that the month is first when converting it to a date object? Can I do something in the controller before saving it?

sawa
  • 165,429
  • 45
  • 277
  • 381
Steve Carey
  • 2,876
  • 23
  • 34
  • Can you control the format that the datetime picker uses? Things tend to go smoother when you use non-ambiguous ISO8601 formats except at the very edges. – mu is too short May 16 '18 at 07:35
  • I would think so but it wasn't in the basic docs. And it's complicated by the fact that two libraries are involved. Moment.js which manipulates date formats and Tempus Dominus Bootstrap 4 which creates the datepicker. – Steve Carey May 16 '18 at 08:05
  • I figured out how to do that and added it as a separate answer. – Steve Carey May 16 '18 at 09:42

2 Answers2

2

You can tell Ruby how to read time string:

DateTime.strptime('06/09/2018', '%m/%d/%Y')

More details you can see in this answer.

Edited:

Also, you can set the default date format as there:

Add this to config/initializers/date_time.rb

Date::DATE_FORMATS[:default] = "%m/%d/%Y" 
Leo
  • 1,673
  • 1
  • 13
  • 15
  • Unfortunately I tried that and for some reason it's not working. It does indeed convert it as such but it still saves it to the database in the wrong format. – Steve Carey May 16 '18 at 07:23
  • Okay I figured it out. I had to remove the field from the whitelisted event_params before converting it using DateTime.strptime function you mentioned. – Steve Carey May 16 '18 at 07:29
  • Thanks, I'll try out the initializer as well. In the controller action, besides removing the field from event_params I had to add to the create and update actions: – Steve Carey May 16 '18 at 07:33
  • @event.starts_at = DateTime.strptime(params['event']['starts_at'],'%m/%d/%Y %H:%M %p') – Steve Carey May 16 '18 at 07:34
  • To the database it was being saved in the standard datetime format as: 2018-09-06 18:00:00 – Steve Carey May 16 '18 at 07:35
  • Yes, it just defines how to read and display the date from anywhere, but not change DateTime object – Leo May 16 '18 at 07:40
1

I found out you can change the date format to one Ruby correctly understands and that is easily readable by users. Change the JavaScript to:

$(document).on('turbolinks:load', function() {
  $('#datetimepicker1').datetimepicker(
    'format', 'MMMM D, YYYY h:mm A'
  );
});

This will display the date to the user as June 9, 2018 6:30 PM. Date format comes from Moment.js http://momentjs.com/docs/#/displaying/format/ but is added to the format option of Tempus Dominus.

As a side note, to get tempus dominus boostrap 4 working in Rails, you have to also load moment.js. Either call the cdn or add the momentjs-rails gem. If the latter then in your application.js file you need to require it, something like this:

# app/assets/javascripts/application.js
...
//= require moment
//= require tempusdominus-bootstrap-4.js
Steve Carey
  • 2,876
  • 23
  • 34