How can I make Rails 3 localize my date formats?

I am working on a Rails 3 project where there is a place to enter a date on the form. A date picker is used in the date text box, so there is no concern about the date entered in the wrong format, however the date is displayed in the format: db (for example, 2010-01-21).

(Note: this is especially true for form fields - for example, <%= f.text_field :publish_date %> , which should be used automatically: the default format and not necessarily have a value)

I tried adding to a user locale that 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 it does not seem to accept and becomes rather unpleasant.

Ultimately, the application supports multiple locales, so setting up the initializer to override date formats when starting the application does not work, and I know that this should work - I assume that I missed something.

config/locales/en-AU.yml file: config/locales/en-AU.yml and in my .rb application I include:

 config.i18n.load_path += Dir[Rails.root.join("config", "locales", "*.yml").to_s] config.i18n.default_locale = "en-AU" 

in my application.rb file.

+41
ruby-on-rails ruby-on-rails-3 internationalization localization
Oct 07 '10 at 7:52
source share
5 answers

When displaying the date, you can use I18n.l

So you would do:

 I18n.l @entry.created_at 

And if you want to change its format:

 I18n.l @entry.created_at, :format => :short 

The internationalization routing guide documents this.

+85
Oct 07 '10 at 7:55
source share
+7
Dec 06 2018-10-12T00:
source share

What I found the best solution is:

  • I localize date formats in my locale file like you.
  • 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)) %>

This is not entirely sad, but at least in this way I can use my form for both new and existing records. Also, the application will be compatible with several locales compared to changing the default format with initializers. If you want to do DRY completely, you can always write a custom helper.

+4
Jan 21 '13 at 12:55
source share

@ damien-mathieu has a solid answer for displaying localized dates from I18n.localize , and his comment raises an important caveat: this interrupts the text input form. Since then, the rails give us a good solution.

Like Rails 5 , you can use the Rails attribute API to customize how user input is converted to a model or database value. In fact, it was available in Rails 4.2 , but not fully documented.

Through the considerable efforts of Sean Griffin, all model types are now defined as ActiveRecord::Type objects. This defines the only source of truth for how the attribute is processed. The type determines how the attribute is serialized (from the ruby ​​type to the database type), deserialized (from the database type to the ruby ​​type), and discarded (from user input to the ruby ​​type). This is a big deal, because messing with it used to be a minefield of special cases that developers should avoid.

First uncheck attribute docs to understand how to redefine attribute type. You probably need to read the docs to understand this answer.

How Rails Converts Attributes

Here's a quick tour of the Rails Attributes API. You can skip this section, but then you will not know how it works. What kind of fun is this?

Understanding how Rails handles user input for your attribute will allow us to override only one method instead of creating a more complete custom type. It will also help you write code better, as rails code is pretty good.

Since you did not mention the model, I assume that you have a Post with the attribute :publish_date (some would prefer the name :published_on , but I digress).

What is your type?

Find out which type :publish_date . We do not care that this is an instance of Date , we need to know what type_for_attribute returns:

This method is the only reliable source of information for everything related to the types of model 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 that the attribute :publish_date is a type :date . This is determined by ActiveRecord :: Type :: Date , which extends ActiveModel :: Type :: Date , which extends ActiveModel :: Type :: Value . I contacted the rails 5.1.3, but you will want to read the source of your version.

How is user input converted to ActiveRecord :: Type :: Date?

So, when you set :publish_date , the value is passed to cast , which calls cast_value . Since the form input is a string, it will try to execute fast_string_to_date , then fallback_string_to_date , which uses Date._parse .

If you get lost, do not worry. You do not need to understand the rails code to configure the attribute.

Custom Type Definition

Now that we understand how Rails uses the attribute 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 the rails code and made a little tweak. Easily. You can improve this by calling super and move the :short format to a parameter or constant.

Register your type so that it can be referenced by the symbol:

 # config/initializers/types.rb ActiveRecord::Type.register(:localized_date, LocalizedDate) 

Cancel type :publish_date 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 %> 
+3
Aug 17 '17 at 19:48 on
source share

You can override recipients for the attribute :publish_date .

i.e. in your model:

 def date( *format) self[:publish_date].strftime(format.first || default) end 

and, in your opinion, you can do

 @income.date("%d/%m/%Y") 

or

 @income.date 

This will force strftime to use the passed format string if it was not zero, in which case it will revert to your standard string.

Note. I used the splat operator to add support to get a date without an argument. There may be a cleaner way to do this.

+1
Feb 27 '14 at 1:37
source share



All Articles