Rails enforce a DateTime offset with a timezone param and DST - ruby-on-rails

I just had a problem with a DateTime field that was submitted with the wrong timezone offset that I usually observe for people submitting from the same country (how surprising .... coming from an Internet Explorer). I am wondering if this may be linked with DST that will end soon at the end of october, and that some browser might have problems with that (although the affected DateTime was around the 15th of October, before the change).
The frontend form was using bootstrap datetimepicker (whose underlying implementation rely on momentJS). Here's a small extract of the JS that activates the picker and the field, although I'm not sure it's relevant here
<div class="col-xs-4" id="appointment-time-start">
<%= f.hidden_field :from %>
</div>
<script>
$('#appointment-time-start').datetimepicker({
format: 'LT',
defaultDate: "<%= model.from || (Time.now + 2.days) %>",
});
</script>
In order to avoid this issue, I am asking the user to also submit a timezone whose default is set to Paris timezone.
f.time_zone_select(:time_zone)
How should I use this timezone to modify the other dates that are sent as params ? I have a simple appointment form that sends two datetimes, and I need to modify them to ensure their offset matches the time_zone param (AND the Daylight Saving Time extra +1 if it is in effect).
I am also wondering if I should do this in the controller, or directly in the model. My controller is doing the usual thing and my current model looks like (but right now I'm not doing anything with time_zone)
class Appointment
include Mongoid::Document
field :from, type: DateTime
field :to, type: DateTime
field :time_zone, default: 'Paris'

Well I found this answer on a similar question... I'm surprised that there isn't a simpler helper that does that oO
def set_in_timezone(time, zone)
Time.use_zone(zone) { time.to_datetime.change(offset: Time.zone.now.strftime("%z")) }
end
Note that it still doesn't answer my question about whether I should do it in the model/controller.

Related

Getting Globalize and autocomplete to work together

Using globalize gem to manage translations with autocomplete, there is a situation where a number of hooks need to be properly set. Note: this does not use hstore AFAIK. I have not managed to find a way to do so. The most productive set-up to date has
controller:
autocomplete :nation, :name, :full => true
Nation
translates :name
view
<%= autocomplete_field_tag 'nation_name', '', autocomplete_nation_name_itins_path, size: 35, :id_element => 'nation_id' %>
There is no inherent reference to nation_translations database table created by Globalize as of yet. As this image suggests, there is a problem:
Issue 1: The input remains binded to the base table's attribute value (I have not yet cleared them out as the Globalize gem suggests. Otherwise I'd be getting blanks). can is actually ready all values of canin master table... Typing in other locales, like cyrillic say Канада has naturally no effect as that value is not part of the Nation table.
What is interesting is that the drop-down values are being populated by Rails automatically, extracting the translation values of what is input.
Issue 2: I'd rather pass the parameter 'nation_id' which is naturally part of the nation_translations table with the form data. although I can append , :extra_data => [:nation_id] to the controller it is not being submitted (example in cyrillic where the input is given without any autocomplete)
{"utf8"=>"✓", "nation_name"=>"Канада", "commit"=>"..."}
Rails.logger.info :extra_data returns:
extra_data
Now the second issue can be overcome because a query like
Nation::Translation.where('name = ?', "Канада").pluck('nation_id')
returns a proper result. But that point is moot if the autocomplete is not playing ball with the user's input.
How can this be configured to have user input autocomplete with the current local translations?
this does get solved by creating an entirely new class with attributes nation_id, name, locale and can thus be called symbolically.
The query call is not that straightforward however. As the gem suggests, the method need to be tweaked
def autocomplete_nation_name
term = params[:term].downcase
locale = params[:locale]
nationtranslations = Nationtranslation.where('locale = ? AND name LIKE ?', locale, "%#{term}%").order(:name).all
render :json => nationtranslations.map { |nationtranslation| {:id => nationtranslation.id, :label => nationtranslation.name, :value => nationetranslation.name} }
end
intervening on the action method itself provides all the leeway desired...

Rails 4 : wrong time in edit view with string field and TimeZone per request

I develop an application in Ruby on Rails 4 with TimeZone per request.
I want to use a datetime picker (http://xdsoft.net/jqplugins/datetimepicker/) in my application to replace the default Simple_form datetime input (5 combo-boxes...).
For this kind of datetime picker (I search for others, it's the same), in my view, I have to use a "string" field, like this :
<%= f.input :done_at, as: :string, input_html: { :data => { :behaviour => "datetimepicker" } } %>
When I post the form, Rails take care of the timezone and store in the database the time in UTC.
For example, I put "2014-03-14 19:45:07" (local time is Paris, so UTC +0100) in the field, and I have "2014-03-14 18:45:07" in the database, in UTC. It's correct.
But when I want to edit the information, Rails fill in the field with a wrong time. The offset timezone is lost and I have "2014-03-14 18:45:07" in the field (the UTC time), so 1 hour before the correct time.
How can I have the correct time taking care of the user timezone ? (not in UTC)
I tried the solution found on http://jessehouse.com/blog/2013/11/15/working-with-timezones-and-ruby-on-rails/ to override the display of dates, but it doesn't work.
def done_at
super.in_time_zone(time_zone) if super && time_zone
end
If in my view, I put #action.done_at, the time is correct but not in the field.
Thanks,
Fred
Set the value of the input explicitly. You can move #object.done_at.in_time_zone(time_zone) to a helper if you want
<%= f.input :done_at, as: :string, input_html: { :data => { :behaviour => "datetimepicker" }, :value => #object.done_at.in_time_zone(time_zone).strftime('%d-%m-%Y %H:%M') } %>

Rails how to remove UTC offset text ('UTC') from a dateTime leaving only the DateTime?

I have a tool set to store everything in the db as UTC. On a form I have a text field with an attached jQuery Date + Time picker.
In that textfield the dateTime stamp (w/ UTC offset) will just appear like:
<%= f.text_field :report_time, :size => 22 %>
2012-06-05 15:55:50
However I need this form choice to be in EST. So I need to convert it going to the form and then when the form is submitted. This problem is specific only to when an 'EDIT' action is taken (time already exists in field). If I do any addition or subtraction "UTC" gets stuck on the end in the form text field:
#report.report_time = #report.report_time - 5.hours
=>2012-06-05 10:55:50 UTC
At this point a jQuery DateJS dateparse function I'm using will stop working because it doesn't understand the "UTC" text in the text field holding the dateTime.
How can I take a db UTC time and add/subtract hours without "UTC" getting dropped in the form, or how can you remove the UTC offest information leaving only the raw dateTime information?
How do I:
#report.report_time = #report.created_at - 5.hours
=>2012-06-05 10:55:50 UTC
# do something here to strip " UTC" off the dateTime ??
=>2012-06-05 10:55:50
Thank You!
Rails 2.3.5 / Ruby 1.8.7
Use the strftime function to set the value of the field directly, if you don't want the default representation.
<%= f.text_field :report_time, :size => 22, :value =>"...." %>
http://ruby-doc.org/stdlib-1.8.7/libdoc/date/rdoc/DateTime.html#method-i-strftime
You may probably want to check out this link for information on how to use the date/time more naturally with the form builder.
http://guides.rubyonrails.org/form_helpers.html#using-date-and-time-form-helpers

Rails formatting in edit field

Can rails formatting helpers be used on an 'edit' screen? The format helpers (number_to_currency, number_to_percent) are great for index/show, but I don't see how to apply them during edit. I have a custom heler that formats the date:
def my_date_helper(datetime)
datetime.nil? ? "" : datetime.strf('%d-%b-%Y')
end
For example, if I have a starts_at attribute, that the user interacts with using a jQuery datepicker, the value placed in edit.html.erb in <%= f.text_field :starts_at %> by rails will be formatted like:
2011/12/19 00:00:00
I would like the user to be presented with a consistent format,so I want to apply the same format helper I use in show/index so the edit text field shows a format like:
19-Jan-2011
You could do this for your edit form:
<%= f.text_field :starts_at, :value => my_date_helper(#my_model.starts_at) %>
Also, jQuery's Date Picker includes a dateFormat parameter, so you could do something like this in your javascript:
jQuery("#my_model_starts_at").datepicker({
dateFormat: 'd/M/yy'
});
I just had a 'duh' moment. To doesn't seem there's any easy, rails-ey way. But it can be done really easy with unobtrusive JavaScript, like:
$('.datepicker').each(function(i){
var date = new Date($(this).val());
$(this).val($.datepicker.formatDate('dd-M-yy', date));
});
Four lines in application.js and you're done.
jQuery('#datetimepicker3').datetimepicker({
format:'d.m.Y H:i',
inline:true,
lang:'ru'
});
datetimepicker

Validating date formats in rails

My simple date validation regex is not working correctly...
validates_format_of :dob, :with => /\d{2}\/\d{2}\/\d{4}/, :message => "^Date must be in the following format: mm/dd/yyyy"
What am I missing here? I'm trying to validate that a date is in the following format: mm/dd/yyyy - When I enter what should be valid data, I still get the error message.
Thanks for the help so far. Here's a snippet of code from my form that is passing the dob value in:
<tr>
<td>
<%= f.label :dob, "Date of Birth: " %>
</td>
<td>
<%= calendar_date_select_tag "user[dob]", "", :format => :american, :year_range => 50.years.ago..0.years.ago %>
</td>
</tr>
I think it may have something to do with my use of this js calendar plugin. A related problem is that my dob value is not maintained in the field if the post fails validation - the previously entered date value clears out...
Thanks!
Tom
You are probably using a string field to store a date. Consequently, any helpers that expect a DateTime or Time value will not work properly. You will need to investigate multiparameter assignments in Rails to figure out the proper way to do what you want to do (multiparemeter assignments is the magic behind sending 4 fields to Rails and get them converted to a DateTime or Time object).
In other words: if you are using a true DateTime field (as you should for this case) the validates_format_of will not have any effect (or will have adverse effects)
Found an excellent gem / plugin for all your date / time validations.
validates_timeliness
http://github.com/adzap/validates_timeliness
I've not tested your code within a Rails app, but your regular expression looks good to me. Try this test program:
#!/usr/bin/ruby
str = '08/24/2009'
regex = /\d{2}\/\d{2}\/\d{4}/
if str =~ regex
print 'matched', "\n"
else
print 'did not match', "\n"
end
Your regular expression matches. That suggests the problem is elsewhere.
You also might think about trying more general solutions for parsing a date in Ruby, such as the Date.parse method of the Date class. This does a little bit more validation than your regular expression, and it also provides some useful methods for converting dates between different formats.
Ahhh! Forcing date formats on the end-user when Rails implicitly converts them is a bad thing for usability, along with being more work for you (as you've seen).
If you've got a date/time attribute in your model, Rails will do its best to convert via Date.Parse (http://www.ruby-doc.org/core/classes/Date.html#M000644), e.g.
u = Somemodel.find :first
u.created_at
=> Tue Nov 20 15:44:18 -0500 2007
u.created_at = '2008/07/03'
=> "2008/07/03"
u.created_at
=> Thu Jul 03 00:00:00 -0400 2008
u.created_at = '05/10/1980'
=> "05/10/1980"
u.created_at
=> Sat May 10 00:00:00 -0400 1980
The regex looks correct to me. A useful resource is http://www.rubyxp.com/, which will test your regular expression against a given string. Indeed, the regex you have matches a date I typed into rubyxp.
Perhaps there's an issue in getting the entered data -- any chance the field is really called da?
Another item you may find useful: validates_timeliness, a rails plugin to validate dates and times. Why just validate the date format when you can check if it's a real date -- after all, 99/99/9999 will validate against your regex, but you may not really want to accept that.
You can try using current date to convert it into a format something like his:
def validate_date_format(value)
current_date = DateTime.now
begin
DateTime.strptime(current_date, value)
rescue
raise 'Invalid Format'
end
end
You might also want to look into the Chronic Gem (http://chronic.rubyforge.org/) which does natural date parsing. So you can enter in :
Next tuesday at 9pm
And it will interpret it correctly.

Resources