Je travaille sur un projet Rails 3 où il y a de la place pour la date dans un formulaire. Le champ de texte avec la date utilise un sélecteur de date donc il n'y a pas de souci quant à la date entrée dans un format incorrect, cependant la date est affichée au format: db (par exemple 2010-01-21).
(Remarque: ceci est spécifiquement dans les champs de formulaire - par exemple <%= f.text_field :publish_date %>
, qui devrait utiliser automatiquement: le format par défaut, et ne devrait pas avoir besoin d'être fourni avec une valeur)
J'ai essayé d'ajouter un environnement local personnalisé qui a la configuration de date suivante:
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"
Et puis définir mes paramètres régionaux à ceci (config.i18n.default_locale = "en-AU"
) mais cela ne semble pas prendre et ça devient assez frustrant.
L'application prendra éventuellement en charge un certain nombre de paramètres régionaux, donc la mise en place d'un initialiseur pour remplacer les formats de date au démarrage de l'application n'est pas vraiment appropriée, et je sais que cela devrait fonctionner - je suppose que je ' ai manqué quelque chose ici.
Le fichier de paramètres régionaux est: config/locales/en-AU.yml
et dans mon application.rb j'inclus:
config.i18n.load_path += Dir[Rails.root.join("config", "locales", "*.yml").to_s]
config.i18n.default_locale = "en-AU"
dans mon fichier application.rb.
Lors de l'affichage d'une date, vous pouvez utiliser I18n.l
Vous feriez donc:
I18n.l @entry.created_at
Et si vous voulez changer son format:
I18n.l @entry.created_at, :format => :short
Le internationalisation Rails guide documente cela.
consultez le joyau de délocalisation, cela pourrait vous aider.
https://github.com/clemens/delocalize
http://www.railway.at/articles/2009/05/03/new-plugin-delocalize/
@ damien-mathieu a une réponse solide pour afficher des dates localisées avec I18n.localize
, et son commentaire soulève une mise en garde importante: cela rompt les entrées de texte. Depuis lors, Rails nous donne une belle solution.
À partir de Rails 5 , vous pouvez utiliser Rails attributes API pour personnaliser la façon dont l'entrée utilisateur est transformée en valeur de modèle ou de base de données . En fait, c'était disponible dans Rails 4.2 , mais pas complètement documenté.
Grâce à Sean Griffin's efforts considérables, tous les types de modèles sont désormais définis comme ActiveRecord::Type
objets. Cela définit une seule source de vérité pour la façon dont un attribut est géré. Le type définit la façon dont l'attribut est sérialisé (d'un type Ruby à un type de base de données), désérialisé (d'un type de base de données à un Ruby) et cast (de l'entrée utilisateur à un Ruby). C'est un gros problème, car jouer avec cela était un champ de mines de cas spéciaux que les développeurs devraient éviter.
Commencez par parcourir les documents attribute
pour comprendre comment remplacer le type d'un attribut. Vous aurez probablement besoin de lire la documentation pour comprendre cette réponse.
Voici une présentation rapide de l'API Attributs Rails. Vous pouvez ignorer cette section, mais vous ne saurez pas comment cela fonctionne. Quel plaisir est-ce?
Comprendre comment Rails gère les entrées utilisateur pour votre attribut nous permettra de remplacer une seule méthode au lieu de créer un type personnalisé plus complet. Cela vous aidera également à écrire un meilleur code, car le code de Rails est assez bon .
Puisque vous n'avez pas mentionné de modèle, je suppose que vous avez un Post
avec un :publish_date
attribut (certains préféreraient le nom :published_on
, mais je m'égare).
Découvrez quel type :publish_date
est. Peu importe qu'il s'agisse d'une instance de Date
, nous devons savoir ce que type_for_attribute renvoie:
Cette méthode est la seule source d'informations valide pour tout ce qui concerne les types d'attributs d'un modèle.
$ Rails c
> post = Post.where.not(publish_date: nil).first
> post.publish_date.class
=> Date
> Post.type_for_attribute('publish_date').type
=> :date
Maintenant, nous connaissons le :publish_date
l'attribut est un :date
type. Ceci est défini par ActiveRecord :: Type :: Date , qui étend ActiveModel :: Type :: Date , qui étend ActiveModel :: Type :: Value . J'ai lié à Rails 5.1.3, mais vous voudrez lire la source de votre version.
Ainsi, lorsque vous définissez :publish_date
, la valeur est passée à cast , qui appelle cast_value . Puisque l'entrée de formulaire est une chaîne, elle essaiera fast_string_to_date puis fallback_string_to_date qui utilise Date._parse .
Si vous vous perdez, ne vous inquiétez pas. Vous n'avez pas besoin de comprendre le code de Rails pour personnaliser un attribut.
Maintenant que nous comprenons comment Rails utilise l'API d'attributs, nous pouvons facilement créer le nôtre. Créez simplement un type personnalisé pour remplacer cast_value
pour attendre des chaînes de date localisées:
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
Voyez comment je viens de copier le code de Rails et de faire un petit Tweak. Facile. Vous pourriez vouloir améliorer cela avec un appel à super
et déplacer le :short
formate une option ou une constante.
Enregistrez votre type afin qu'il puisse être référencé par un symbole:
# config/initializers/types.rb
ActiveRecord::Type.register(:localized_date, LocalizedDate)
Remplacez le :publish_date
tapez avec votre type personnalisé:
class Post < ApplicationRecord
attribute :publish_date, :localized_date
end
Vous pouvez maintenant utiliser des valeurs localisées dans vos entrées de formulaire:
# 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 %>
Ce que j'ai trouvé être la meilleure solution est la suivante:
<%= f.text_field :publish_date, :value => (@model.publish_date.nil? ? nil : l(@model.publish_date)) %>
Ce n'est malheureusement pas parfait, mais au moins de cette façon, je peux utiliser mon formulaire pour les enregistrements nouveaux et existants. L'application restera également compatible avec plusieurs paramètres régionaux par rapport à la modification du format par défaut avec les initialiseurs. Si vous voulez vous conformer pleinement à DRY vous pouvez toujours écrire un assistant personnalisé.
Vous pouvez remplacer vos getters pour le :publish_date
attribut.
c'est-à-dire dans votre modèle:
def date( *format)
self[:publish_date].strftime(format.first || default)
end
et à votre avis, vous pouvez faire
@income.date("%d/%m/%Y")
ou
@income.date
Cela obligerait strftime à utiliser la chaîne de format transmise à moins qu'elle ne soit nulle, auquel cas elle reviendrait à votre chaîne par défaut.
Remarque: J'ai utilisé l'opérateur splat pour ajouter un support pour obtenir la date sans argument. Il peut y avoir une façon plus propre de le faire.