私はRails 3プロジェクトで作業しています。フォーム内で日付を入力する場所があります。日付のテキストフィールドは日付ピッカーを使用するため、日付が入力される心配はありません。間違った形式ですが、日付は:db形式で表示されています(例:2010-01-21)。
(注:これは特にフォームフィールドにあります-<%= f.text_field :publish_date %>
、これは自動的に:default形式を使用する必要があり、値を提供する必要はありません)
次の日付構成を持つカスタマイズされたロケールで追加しようとしました。
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"
そして、ロケールをこれに設定します(config.i18n.default_locale = "en-AU"
)しかし、これには時間がかかりそうになく、かなりイライラします。
アプリは最終的に多くのロケールをサポートするため、アプリケーションの起動時にイニシャライザーを設定して日付形式をオーバーライドすることは実際には適切ではなく、これはshould work-I'm guessing I 'ここで何かを逃しました。
ロケールファイルは次のとおりです。config/locales/en-AU.yml
そして、私のapplication.rbに私は含まれています:
config.i18n.load_path += Dir[Rails.root.join("config", "locales", "*.yml").to_s]
config.i18n.default_locale = "en-AU"
私のapplication.rbファイルに。
日付を表示するときは、I18n.l
だからあなたがするだろう:
I18n.l @entry.created_at
そして、フォーマットを変更したい場合:
I18n.l @entry.created_at, :format => :short
internationalization Rails guide はそれを文書化しています。
delocalize gemをチェックしてください。
https://github.com/clemens/delocalize
http://www.railway.at/articles/2009/05/03/new-plugin-delocalize/
@ damien-mathieuには、ローカライズされた日付をI18n.localize
、および彼のコメントは重要な警告を提起します:これはフォーム入力テキストを壊します。それ以来、Railsは私たちに素敵なソリューションを提供します。
Rails 5の時点で、 Rails属性API を使用して、ユーザー入力をモデルまたはデータベース値に変換する方法をカスタマイズできます。実際には、それは Rails 4.2 で利用可能で、完全に文書化されていません。
Sean Griffin's かなりの努力により、すべてのモデルのタイプはActiveRecord::Type
オブジェクト。これにより、属性の処理方法に関する単一の真実のソースが定義されます。タイプは、属性のシリアル化(Rubyタイプからデータベースタイプへ)、デシリアライズ(データベースタイプからRubyタイプ)およびキャスト)を定義します。 (ユーザー入力からRubyタイプ)へ。これを混乱させることは、開発者が避けるべき特別な場合の地雷原であったためです。
まず、 attribute
ドキュメントをざっと読んで、属性のタイプをオーバーライドする方法を理解します。この答えを理解するには、おそらくドキュメントを読む必要があります。
Rails Attributes API。このセクションはスキップできますが、この機能がどのように機能するかわかりません。何が面白いのでしょうか?
Rails属性のユーザー入力を処理する方法を理解すると、より完全なカスタム型を作成するのではなく、1つのメソッドのみをオーバーライドできます。Railsのコードは非常に優れているため、 。
モデルについては言及しなかったため、Post
と:publish_date
attribute(一部の名前は:published_on
、しかし脱線する)。
タイプ:publish_date
です。 Date
のインスタンスであるかどうかは気にしません。 type_for_attribute が返すものを知る必要があります。
このメソッドは、モデルの属性のタイプに関連する情報の唯一の有効な情報源です。
$ Rails c
> post = Post.where.not(publish_date: nil).first
> post.publish_date.class
=> Date
> Post.type_for_attribute('publish_date').type
=> :date
これで、:publish_date
属性は:date
タイプ。これは ActiveRecord :: Type :: Date で定義され、 ActiveModel :: Type :: Date で拡張されます ActiveModel :: Type :: Value 。 Rails 5.1.3にリンクしましたが、バージョンのソースを読むことをお勧めします。
したがって、:publish_date
、値は cast に渡され、これは cast_value を呼び出します。フォーム入力は文字列であるため、 fast_string_to_date を試行します-- fallback_string_to_dateDate._parse を使用します。
迷子になっても心配しないでください。属性をカスタマイズするためにRailsのコードを理解する必要はありません。
これでRailsが属性APIを使用する方法を理解したので、独自のAPIを簡単に作成できます。cast_value
ローカライズされた日付文字列を期待する場合:
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
Railsのコードをコピーして小さな調整を行ったところをご覧ください。簡単です。 super
を呼び出してこれを改善し、:short
をオプションまたは定数にフォーマットします。
型を登録して、シンボルで参照できるようにします。
# config/initializers/types.rb
ActiveRecord::Type.register(:localized_date, LocalizedDate)
:publish_date
カスタムタイプを入力します。
class Post < ApplicationRecord
attribute :publish_date, :localized_date
end
これで、フォーム入力でローカライズされた値を使用できます。
# 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 %>
私が最善の解決策であることがわかったのはこれです:
<%= f.text_field :publish_date, :value => (@model.publish_date.nil? ? nil : l(@model.publish_date)) %>
残念ながら完全ではありませんが、少なくともこの方法で、新規および既存のレコードの両方にフォームを使用できます。また、アプリは、初期化子を使用してデフォルトの形式を変更する場合と比較して、複数のロケールとの互換性を維持します。 DRYに完全に準拠したい場合は、常にカスタムヘルパーを記述できます。
:publish_date
属性のゲッターをオーバーライドできます。
すなわち、あなたのモデルで:
def date( *format)
self[:publish_date].strftime(format.first || default)
end
あなたの意見では、あなたはどちらかをすることができます
@income.date("%d/%m/%Y")
または
@income.date
これにより、strftimeは、nilでない限り、渡されたフォーマット文字列を使用します。nilでない場合、デフォルト文字列にフォールバックします。
注:スプラット演算子を使用して、引数なしで日付を取得するためのサポートを追加しました。よりクリーンな方法があるかもしれません。