Подтвердить что ты не робот

Как я могу сделать Rails 3 локализовать мои форматы дат?

Я работаю над проектом Rails 3, где есть место для ввода даты в форме. В текстовом поле с датой используется средство выбора даты, поэтому нет никакой озабоченности по поводу даты, введенной в неправильном формате, однако дата отображается в формате: db (например, 2010-01-21).

(Примечание: это особенно относится к полям формы - например, <%= f.text_field :publish_date %>, которые должны автоматически использовать: формат по умолчанию и не обязательно должны иметь значение)

Я попытался добавить в пользовательскую локаль, которая имеет следующую конфигурацию даты:

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"), однако это, похоже, не принимает и становится довольно неприятным.

В конечном итоге приложение поддерживает несколько локалей, поэтому настройка инициализатора для переопределения форматов даты при запуске приложения не подходит, и я знаю, что это должно работать - я предполагаю, что я что-то пропустил.

Файл локали: config/locales/en-AU.yml и в моем приложении .rb Я включаю:

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

в моем файле application.rb.

4b9b3361

Ответ 3

Что я нашел лучшим решением, так это:

  • Я локализую форматы даты в моем файле локали, как вы.
  • В моих формах я локализую дату, установив значение непосредственно

<%= f.text_field :publish_date, :value => (@model.publish_date.nil? ? nil : l(@model.publish_date)) %>

Это не совсем печально, но по крайней мере таким образом я могу использовать свою форму как для новых, так и для существующих записей. Также приложение будет совместимо с несколькими локалями по сравнению с изменением формата по умолчанию с инициализаторами. Если вы полностью хотите выполнить DRY, вы всегда можете написать пользовательский помощник.

Ответ 4

@damien-mathieu имеет солидный ответ для отображения локализованных дат с I18n.localize, и его комментарий вызывает важную оговорку: это прерывает форму ввода текста. С тех пор рельсы дают нам хорошее решение.

Как и у Rails 5, вы можете использовать API атрибутов Rails, чтобы настроить, как пользовательский ввод преобразуется в значение модели или базы данных. Фактически, это был доступный в Rails 4.2, только не полностью документированный.

Через значительные усилия Шона Гриффина, все типы моделей теперь определяются как объекты ActiveRecord::Type. Это определяет единственный источник истины для того, как обрабатывается атрибут. Тип определяет, как сериализуется атрибут (от типа ruby ​​к типу базы данных), десериализован (от типа базы данных до типа ruby) и отбрасывается (от ввода пользователя до типа ruby). Это большое дело, потому что возиться с этим раньше было минным полем особых случаев, которые разработчики должны избегать.

Сначала снимите attribute docs, чтобы понять, как переопределить тип атрибута. Вероятно, вам нужно прочитать документы, чтобы понять этот ответ.

Как Rails преобразует атрибуты

Здесь вы найдете краткую экскурсию по API атрибутов Rails. Вы можете пропустить этот раздел, но тогда вы не будете знать, как это работает. Что это за забава?

Понимание того, как Rails обрабатывает ввод пользователя для вашего атрибута, позволит нам переопределить только один метод вместо создания более полного настраиваемого типа. Это также поможет вам лучше писать код, так как код rails довольно хорош.

Поскольку вы не упомянули модель, , я предполагаю, что у вас есть Post с атрибутом :publish_date (некоторые предпочли бы имя :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:: Тип:: Дата, который расширяет ActiveModel:: Тип:: Значение. Я связался с рельсами 5.1.3, но вы захотите прочитать источник своей версии.

Как пользовательский ввод преобразуется ActiveRecord:: Type:: Date?

Итак, когда вы устанавливаете :publish_date, значение передается cast, которое вызывает cast_value. Поскольку вход формы является строкой, он попытается выполнить fast_string_to_date, затем fallback_string_to_date, который использует Date._parse.

Если вы заблудились, не волнуйтесь. Вам не нужно понимать код рельсов для настройки атрибута.

Определение пользовательского типа

Теперь, когда мы понимаем, как Rails использует 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

Посмотрите, как я просто скопировал код рельсов и сделал небольшую настройку. Легко. Вы можете улучшить это с помощью вызова 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 %>

Ответ 5

Вы можете переопределить получатели для атрибута :publish_date.

то есть. в вашей модели:

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

и, на ваш взгляд, вы можете сделать

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

или

@income.date

Это заставит strftime использовать переданную строку формата, если она не была равна нулю, и в этом случае она вернется к вашей стандартной строке.

Примечание. Я использовал оператор splat для добавления поддержки для получения даты без аргумента. Может быть более чистый способ сделать это.