Changing the timestamp of magic columns (Rails) - ruby-on-rails

I want to change the default timestamp of the magic columns of rails (created_at, modified_at) instead of 2010-09-03 14:52:46 UTC I'd like to change it to September 10, 2010 at 02:52 PM. or at least parse that way.
Now, i know that i can do this right in the view, by manipulating the variable, but isnt there a more "railish way" where i can just do this in the model, and then call it as a method?

class YourModel < ActiveRecord::Base
def my_formated_date_time
created_at.strftime("%B %d, %Y at %I:%M %p")
end
end
Or you can use the localization format. Add this to your config/locale/your_locale.yml. IMHO: This would be the most railish way.
your_locale:
time:
formats:
default: "%B %d, %Y at %I:%M %p"
Then in your view do this
<%=l #your_model.created_at %>
<!-- short for: -->
<%= I18n.localize #your_model.created_at %>

Modifying the created_at date is fine, it will stay as you set it, and you can over-ride it even at the start, but updated_at or modified_at might prove tricky. Every time you save your model this is changed. If you don't want this behavior, convention suggests switching to a different name.
If you want to adjust how dates are displayed, you need to configure the default formatter.

Related

Rails remove time from datetime attribute and group

I have a column DATENEW in my invoices table.
If in my view I use:
<td><%= invoice.DATENEW %></td>
it shows:
2015-02-16 11:38:03 UTC
I need to display only year month and day.
How can I do it?
You can use strftime to show only year, month and date.
<%= invoice.DATENEW.strftime('%Y-%m-%d') %>
And for grouping, first show us what you've tried.
These Time / DateTime methods also may come in handy:
at_beginning_of_month
at_beginning_of_day
at_beginning_of_year
at_beginning_of_week
at_beginning_of_hour
at_beginning_of_minute

Rails Converting from Timestamp to Formatted Time with Timezone

I'm building an application using Rails 4. I'm reading a Unix timestamp from JSON and attempting to display it as a properly formatted time according to my timezone. I'm able to read the display the timestamp, but it is displayed in UTC instead of EST.
This is what I have in my view
<%= Time.at(DateTime.strptime(#weather['sys']['sunrise'].to_s,'%s')).strftime("%l:%M %P") %>
I have four different timestamps where I am doing this same conversion.
Is there something I can tack on to this to display the proper time zone?
You can try this:
<%= Time.at(DateTime.strptime(#weather['sys']['sunrise'].to_s,'%s')).in_time_zone("E‌​astern Time (US & Canada)").strftime("%l:%M %P") %>
Try the following:
<% time_zone = "PDT" %>
<%= Time.at(DateTime.strptime(#weather['sys']['sunrise'].to_s,'%s')).in_time_zone(time_zone).strftime("%l:%M %P") %>
Refer to ActiveSupport::TimeWithZone#in_time_zone for more info.

Rails Date Select Parameters

I'm using a date select in a rails 3 form.
<%=f.date_select :date %>
I would like to restrict the dates so that you can only pick dates that fall on a Sunday. Is there any way of going about doing this?
I'm also trying to stop dates which have already passed from appearing.
Thanks for any help in advance!
Rails date_select field generates three dropdown to select the parts of the date. There is no chanche, that you modify for example the month, and the day will still be sunday.
You must write some js magic to enforce such a role, or find an already existing datepicker and limit it. Or alternatively, you let the user to select a week, and calculate the exact date of sunday from that.
Ok having studied this out a bit further I don't think this is possible due to the format of the date_select field. The closest I can get is
<%=f.date_select :date, start_year: Time.now.year %>
so that at least you can't select dates from previous years. I've implemented the restriction on days and months that have past by setting up the view to automatically delete records that aren't relevant:
<% if(service.date < Date.today) %>
<% service.destroy %>
<% end %>
Not perfect but does the job in my case.

Show a date variable from database - Rails

I have an attribute in my user database of type "Date".
I want to show it in the "show view", in any format.
What shall I write in show.html.erb so that I can see the contents of this field of a user object ?
Thanks :)
You might want to store the date format in a config file and/or a helper so you can easily modify it and use it globally wherever you are printing it in a view.
You can print a date like this:
<%= #user.datecolumn.strftime('%B %d, %Y') %>
See this article where the date formats are listed and there is more information on the subject:
http://www.linux-mag.com/id/4070/
<%= user.created_at.strftime("%B %m") %>
Take a look at the strftime method: http://www.ruby-doc.org/core-1.9.3/Time.html#method-i-strftime

How can I make Rails 3 localize my date formats?

I am working on a Rails 3 project where there is place for date input within a form. The text field with the date uses a date picker so there is no concern about the date being entered in a wrong format, however the date is being displayed in the :db format (e.g. 2010-01-21).
(Note: this is specifically in form fields - e.g. <%= f.text_field :publish_date %>, which should automatically use :default format, and shouldn't need to be provided with a value)
I have tried adding in a customized locale which has the following date configuration:
date:
formats:
# Use the strftime parameters for formats.
# When no format has been given, it uses default.
# You can provide other formats here if you like!
default: "%d/%m/%Y"
short: "%b %d"
long: "%B %d, %Y"
And then setting my locale to this (config.i18n.default_locale = "en-AU") however this doesn't seem to take and its becoming quite frustrating.
The app will eventually support a number of locales, so setting up an initializer to override the date formats at application startup isn't really suitable, and I know that this should work - I'm guessing I've missed something here.
The locale file is: config/locales/en-AU.yml and in my application.rb I am including:
config.i18n.load_path += Dir[Rails.root.join("config", "locales", "*.yml").to_s]
config.i18n.default_locale = "en-AU"
in my application.rb file.
When displaying a date, you can use I18n.l
So you would do :
I18n.l #entry.created_at
And if you want to change it's format :
I18n.l #entry.created_at, :format => :short
The internationalization rails guide is documenting that.
#damien-mathieu has a solid answer for displaying localized dates with I18n.localize, and his comment raises an important caveat: this breaks form text inputs. Since then, rails gives us a nice solution.
As of Rails 5, you can use the
Rails attributes API to customize how user input is transformed into a model or database value. Actually, it was available in Rails 4.2, just not fully documented.
Through Sean Griffin's considerable efforts, all models' types are now defined as ActiveRecord::Type objects. This defines a single source of truth for how an attribute is handled. The type defines how the attribute is serialized (from a ruby type to a database type), deserialized (from a database type to a ruby type) and cast (from user input to a ruby type). This is a big deal, because messing with this used to be a minefield of special cases developers should avoid.
First, skim the attribute docs to understand how to override an attribute's type. You probably need to read the docs to understand this answer.
How Rails Transforms Attributes
Here's a quick tour of the Rails Attributes API. You can skip this section, but then you won't know how this stuff works. What fun is that?
Understanding how Rails handles user input for your attribute will let us override only one method instead of making a more complete custom type. It will also help you write better code, since rails' code is pretty good.
Since you didn't mention a model, I'll assume you have a Post with a :publish_date attribute (some would prefer the name :published_on, but I digress).
What is your type?
Find out what type :publish_date is. We don't care that it is an instance of Date, we need to know what type_for_attribute returns:
This method is the only valid source of information for anything related to the types of a model's attributes.
$ rails c
> post = Post.where.not(publish_date: nil).first
> post.publish_date.class
=> Date
> Post.type_for_attribute('publish_date').type
=> :date
Now we know the :publish_date attribute is a :date type. This is defined by ActiveRecord::Type::Date, which extends ActiveModel::Type::Date, which extends ActiveModel::Type::Value. I've linked to rails 5.1.3, but you'll want to read the source for your version.
How is user input transformed by ActiveRecord::Type::Date?
So, when you set :publish_date, the value is passed to cast, which calls cast_value. Since form input is a String, it will try a fast_string_to_date then fallback_string_to_date which uses Date._parse.
If you're getting lost, don't worry. You don't need to understand rails' code to customize an attribute.
Defining a Custom Type
Now that we understand how Rails uses the attributes API, we can easily make our own. Just create a custom type to override cast_value to expect localized date strings:
class LocalizedDate < ActiveRecord::Type::Date
private
# Convert localized date string to Date object. This takes I18n formatted date strings
# from user input and casts them back to Date objects.
def cast_value(value)
if value.is_a?(::String)
return if value.empty?
format = I18n.translate("date.formats.short")
Date.strptime(value, format) rescue nil
elsif value.respond_to?(:to_date)
value.to_date
else
value
end
end
end
See how I just copied rails' code and made a small tweak. Easy. You might want to improve on this with a call to super and move the :short format to an option or constant.
Register your type so it can be referenced by a symbol:
# config/initializers/types.rb
ActiveRecord::Type.register(:localized_date, LocalizedDate)
Override the :publish_date type with your custom type:
class Post < ApplicationRecord
attribute :publish_date, :localized_date
end
Now you can use localized values in your form inputs:
# app/views/posts/_form.html.erb
<%= form_for(#post) do |f| %>
<%= f.label :publish_date %>
<%= f.text_field :publish_date, value: (I18n.localize(value, format: :short) if value.present?) %>
<% end %>
check out the delocalize gem, it might help you out some.
https://github.com/clemens/delocalize
http://www.railway.at/articles/2009/05/03/new-plugin-delocalize/
What I found to be the best solution is this:
I localize date formats in my locale file like you do
In my forms I localize the date by setting the value directly
<%= f.text_field :publish_date, :value => (#model.publish_date.nil? ? nil : l(#model.publish_date)) %>
It is not perfect sadly, but at least this way I can use my form for both new and existing records. Also the app will stay compatible with multiple locales compared to changing the default format with initializers. If you fully want to comply with DRY you could always write a custom helper.
You could override your getters for the :publish_date attribute.
i.e. in your model:
def date( *format)
self[:publish_date].strftime(format.first || default)
end
and in your view you could do either
#income.date("%d/%m/%Y")
or
#income.date
This would cause strftime to use the passed format string unless it was nil, in which case it would fall back to your default string.
Note: I used the splat operator to add support for getting the date without an argument. There may be a cleaner way to do that.

Resources