I am having a problem with Rails Forms timezones.
I have a form that is used to setup Schedules. The form itself is quite simple and is given below.
<div class="row">
<div class="col-sm-6">
<h3>Create a new schedule</h3>
<%= bootstrap_form_for(@schedule,label_errors: true, inline_errors: true) do |f| %>
<%= f.text_field :title,required:true %>
<%= f.text_field :description,required:true %>
<%= f.datetime_local_field :start_time,required:true %>
<%= f.datetime_local_field :end_time,required:true %>
<%= f.text_field :cost_cents,required:true %>
<%= f.button :submit %>
<% end %>
</div>
</div>
In my config/application.rb,
I have set the timezone information as follows.
config.active_record.default_timezone = :utc
config.time_zone = 'UTC'
For the user, from the UI, they would be seeing a standard way to pick the date and time.
What is happening is that suppose i pick July 21 2018 04:00 PM as the start time and July 21 2018 05:00 PM as the end time, and since I am in IST time zone (+0530), what I expect is the database to store the data in UTC time by doing the appropriate conversions.
Instead what is happening is that the timezone is completely ignored and the time set on the form is being taken as UTC time and stored.
This is what I see in the Rails console
The incoming request is
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"W1W6naJhEmXhqOJOBBhzQ3O+/HpHrP2WtVNtND+Yoh6mvgsTNr+2GG6T5FxDPRp+DyJAIA+esTpXw8HrDQ60Zw==",
"schedule"=>{"title"=>"Test", "description"=>"Test 2",
"start_time"=>"2018-07-21T16:00",
"end_time"=>"2018-07-21T17:00",
"cost_cents"=>"0"}, "button"=>""}
and the SQL generated is
INSERT INTO "schedules" ("title", "description", "start_time", "end_time",
"user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING "id" [["title", "Test"], ["description", "Test 2"], ["start_time",
"2018-07-21 16:00:00"], ["end_time", "2018-07-21 17:00:00"], ["user_id",
"8f4499ed-fa6f-43b8-be3e-228e3ed57fc6"], ["created_at", "2018-07-21 08:16:38.496829"],
["updated_at", "2018-07-21 08:16:38.496829"]]
My question is,
How do I ensure that the the start_time and end_time values being passed from the browser get converted to UTC before saving?
Is there a way to change the value before being submitted from the browser so that Rails can take care of the appropriate conversion?
As per comments to your answer, try this:
class Schedule < ApplicationRecord
before_save :convert_start_end_times_to_utc
private
def convert_start_end_times_to_utc
start_time = Time.parse(start_time).getutc
end_time = Time.parse(end_time).getutc
end
end
before_save
callback calls the correspondent method ( convert_start_end_times_to_utc
) which manipulates the attributes of the model. In this case start_time
( self.start_time
) and end_time
( self.end_time
). This is done before to save the record to database.
For callbacks see: http://guides.rubyonrails.org/active_record_callbacks.html
See this post for converting to utc: Convert DateTime String to UTC in rails
Ok so I think I have this working. Please let me know if this is on the right track.
What I did was add the momentjs-rails
gem to my project. This gave me access to moment objects on the client side.
Then I modified the form so that the value is converted before the page submission happens and so the UTC time gets sent always.
<div class="row">
<div class="col-sm-6">
<h3>Create a new schedule</h3>
<%= bootstrap_form_for(@schedule,label_errors: true, inline_errors: true) do |f| %>
<%= f.text_field :title,required:true %>
<%= f.text_field :description,required:true %>
<%= f.datetime_local_field :start_time,required:true %>
<%= f.datetime_local_field :end_time,required:true %>
<%= f.text_field :cost_cents,required:true %>
<%= f.button :submit %>
<% end %>
</div>
</div>
<script>
setTimeout(() => {
$('.new_schedule').submit(function() {
var start_time = moment($('#schedule_start_time').val());
if (start_time.isValid()) {
$('#schedule_start_time').val(start_time.clone().utc().format('YYYY-MM-DDTHH:mm'));
}
var end_time = moment($('#schedule_end_time').val());
if (end_time.isValid()) {
$('#schedule_end_time').val(end_time.clone().utc().format('YYYY-MM-DDTHH:mm'));
}
});
},200);
</script>
This article was useful in coming up with this solution.. https://www.codementor.io/yitzofthebits/localize-time-traditional-rails-app-momentjs-twitter-clone-du107wwfg
So when i submit a form with
the database ends up storing the correct time in UTC.
title | description | start_time | end_time
--------+-------------+---------------------+---------------------
Test 2 | Test 2 | 2018-07-21 12:30:00 | 2018-07-21 14:30:00
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.