text_field tag select_tag rails number form_with form for fields ruby-on-rails

ruby on rails - tag - Formato de fecha de carriles en un text_field



rails select_tag (13)

Tengo un formulario de rieles que muestra una fecha en un text_field:

<%= form.text_field :check_in_date %>

La fecha se representa como yyyy-mm-dd

Estoy intentando descubrir cómo mostrarlo como mm-dd-yyyy

Intenté agregar esta configuración, pero no funcionó.

ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!( :default => ''%m/%d/%Y'' )


config / initializers / date_format.rb

ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS[:default] = ''%m/%d/%Y''

ver

<%= form.text_field :check_in_date, value: model.check_in_date.to_s %>


Entonces hice algo como esto en el modelo.

def start_date super.strftime "%Y/%m/%d %H:%M" end

Supongamos que tiene una columna llamada start_date en el modelo y desea mostrar otro formato en el formulario, simplemente sobrescriba su valor en el modelo.

Y nada necesita ser cambiado en la forma.

<%= f.text_field :start_date, class: ''form-control'' %>


Esta ubicación de un solo uso, en tu forma:

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

En ubicaciones en.yml (o es.yml)

en: date: formats: default: "%d/%m/%Y"


Expandiendo la respuesta de Kamil un poco: agregue el siguiente método a application_helper.rb:

def date_mdY(date) if date.nil? "" else date.strftime("%m-%d-%Y") end end

Entonces puedes modificar la respuesta de Kamil levemente:

<%= f.text_field :some_date, :value => date_mdY(@model_instance.some_date) %>

Entonces puedes usar este método de ayuda en cualquier otra vista.

Estoy usando jQuery datepicker y la fecha necesaria para estar en un formato particular para que la fecha predeterminada se establezca correctamente. Gracias por la respuesta Kamil!


Hay dos partes para hacer que esto funcione, y una tercera parte para que todo funcione bien. Si solo quiere copiar pegar, continúe y avance hasta el final.

Parte 1: Cómo obtener la Date para formatearla como desee

Hay un montón de extensiones principales para Fecha en ActiveSupport , pero ninguna de ellas crea una nueva clase de fecha. Si está trabajando con Date , que es lo que Rails devuelve cuando tiene una columna de date en su base de datos, el método para convertir esa fecha en una cadena es Date#to_formatted_s . Las extensiones de ActiveSupport agregan este método y alias el método to_s , por lo que cuando llama a Date#to_s (probablemente implícitamente), obtiene Date.to_formatted_s .

Hay dos formas de cambiar el formato utilizado por to_formatted_s :

  1. Pase el nombre del formato que desea utilizar (esta arg se usará para buscar el formato en Date::DATE_FORMATS ).
  2. Cambie el formato al que se asigna :default mapa :default . Como to_formatted_s establece un valor predeterminado de :default , cuando llama a Date#to_s sin pasar un argumento, obtiene el formato especificado por Date::DATE_FORMATS[:default] . Puede anular el valor predeterminado para toda la aplicación de esta manera:

    Date::DATE_FORMATS[:default] = "%m/%d/%Y"

Tengo este conjunto en un inicializador como config/initializers/date_formats.rb . Es tosco y no admite cambios con sus localizaciones, pero obtiene la Date#to_s para devolver el formato deseado sin ningún parche mono o convirtiendo explícitamente sus fechas a cadenas y pasando un argumento.

Parte 2: Obtener las fechas ingresadas por el usuario convertidas en objetos Date

Por defecto, su instancia de ActiveRecord lanzará columnas de fecha usando el viejo ISO 8601 que se ve así: yyyy-mm-dd .

Si no coincide exactamente con ese formato (por ejemplo, está delimitado por Date._parse ), se recurre al uso de Ruby''s Date._parse , que es un poco más indulgente, pero aún espera ver días, meses y años: dd/mm/yyyy

Para que Rails analice las fechas en el formato que las está recopilando, solo necesita reemplazar el método cast_value por uno propio. Puede parchear mono ActiveRecord::Types::Date , pero no es mucho más difícil lanzar su propio tipo heredando de él.

Me gusta usar Chronic para analizar las cadenas de fecha de la entrada del usuario porque aguanta más mierda, como "Mañana" o "Jan 1 99", o incluso comentarios como "5 / 6-99" (6 de mayo de 1999). Como Chronic devuelve una instancia de Time y estamos anulando el método cast_value suministrado, necesitamos llamar a to_date en él.

class EasyDate < ActiveRecord::Type::Date def cast_value(value) default = super parsed = Chronic.parse(value)&.to_date if value.is_a?(String) parsed || default end end

Ahora solo tenemos que decirle a ActiveRecord que use EasyDate lugar de ActiveRecord::Type::Date :

class Pony < ApplicationRecord attribute :birth_date, EasyDate.new end

Eso funciona, pero si eres como yo, quieres tomar un montón más de trabajo en este momento para que puedas ahorrar 3 segundos en el futuro. ¿Qué sucede si podemos decirle a ActiveRecord que siempre use EasyDate para las columnas que son solo fechas? Podemos.

Parte 3: Haz que los Rails manejen esto automáticamente

ActiveRecord le brinda todo tipo de información sobre su modelo que utiliza para manejar toda la "magia" detrás de las escenas. Uno de los métodos nos da attribute_types . Si lo ejecuta en su consola, recupera el vómito; es un poco aterrador, y simplemente dice "oh, no sé". Si cavas en ese vómito como una especie de bicho raro, es solo un hash que se ve así:

{ column_name: instance_of_a_type_object, ... }

No es algo que da miedo, pero como estamos comenzando a pinchar en las partes internas, la salida inspeccionada de estos instance_of_a_type_object puede terminar siendo obtusa y "cerrada". Me gusta esto:

#<ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Money:0x007ff974d62688

Afortunadamente, realmente solo nos importa uno: ActiveRecord::Types::Date , por lo que podemos restringirlo:

date_attributes = attribute_types.select { |_, type| ActiveRecord::Type::Date === type }

Eso nos da una lista de los atributos que queremos reciclar para usar EasyDate . Ahora solo tenemos que decirle a ActiveRecord que use EasyDate en esos atributos como hicimos anteriormente:

date_attributes.each do |attr_name, _type| attribute attr_name, EasyDate.new end

Y eso básicamente lo hace, pero tenemos que unirlo todo. Si está utilizando ApplicationRecord , puede colocarlo en este y dirigirse a las carreras:

def inherited(klass) super klass.attribute_types.select { |_, type| ActiveRecord::Type::Date === type }.each do |name, _type| klass.attribute name, EasyDate.new end end

Si no quiere "contaminar" ApplicationRecord , puede hacer lo que hice y crear un módulo y extender ApplicationRecord con él. Si no está utilizando ApplicationRecord , deberá crear el módulo y extender ActiveRecord::Base .

module FixDateFormatting # the above `inherited` method here end # Either this... class ApplicationRecord < ActiveRecord::Base extend FixDateFormatting end # ...or this: ActiveRecord::Base.extend(FixDateFormatting)

TL; DR - Qué copiar pegar

Si no le preocupa el cómo y solo quiere que esto funcione, puede:

  1. Agrega gem "chronic" a tu Gemfile y bundle install
  2. Asegúrese de que sus modelos hereden de ApplicationRecord
  3. Copie el código debajo de un archivo en config/initializers/date_formatting.rb
  4. Reiniciar
  5. Todo debería ahora Just Work ™

Aquí está el código para copiar:

Date::DATE_FORMATS[:default] = "%m/%d/%Y" module FixDateFormatting class EasyDate < ActiveRecord::Type::Date def cast_value(value) default = super parsed = Chronic.parse(value)&.to_date if value.is_a?(String) parsed || default end end def inherited(subclass) super date_attributes = subclass.attribute_types.select { |_, type| ActiveRecord::Type::Date === type } date_attributes.each do |name, _type| subclass.attribute name, EasyDate.new end end end Rails.application.config.to_prepare do ApplicationRecord.extend(FixDateFormatting) end


La solución simple de una sola vez es usar :value opción de :value dentro de la llamada text_field lugar de agregar algo a ActiveRecord::Base o CoreExtensions .

Por ejemplo:

<%= f.text_field :some_date, value: @model_instance.some_date.strftime("%d-%m-%Y") %>


Los agregué a mis initializers/time_formats.rb y funciona muy bien:

# Default format for displaying dates and times Date::DATE_FORMATS[:default] = "%m/%d/%Y" Time::DATE_FORMATS[:default] = "%m/%d/%Y"

Usando Ruby 1.9.3 y Rails 3.2.x


Mi forma preferida de manejar esto es con atributos virtuales . Hay un RailsCast corto sobre el tema (3m), pero el resultado es que los atributos virtuales le permitirán usar un formato no estándar al mostrar los atributos del modelo en un formulario, o viceversa ( es decir, guardar datos del formulario en un modelo).

Básicamente, en lugar de crear un campo de formulario para el atributo check_in_date , puede definir un "atributo virtual" en el modelo:

class Reservation def check_in_date_string check_in_date.strftime(''%m-%d-%Y'') end def check_in_date_string=(date_string) self.check_in_date = Date.strptime(date_string, ''%m-%d-%Y'') end end

Ahora puede crear campos de formulario que corresponden a check_in_date_string lugar de check_in_date :

<%= f.text_field :check_in_date_string %>

¡Eso es! No es necesario especificar explícitamente una opción de value , y cuando se envía este formulario, el modelo se actualizará adecuadamente.


Para las personas interesadas en formatear en una ubicación específica y no en todo el proyecto, se recomiendan varias respuestas para comprobar si son nulas y quiero agregar que usar try with strftime ayudará a acortarlo .

<%= f.fields_for :assets_depreciations do |asset| %> <tr> <td> <%= asset.text_field :depreciation_date, value: asset.object.depreciation_date.try(:strftime, "%d-%m-%Y") %> </td> </tr> <% end %>


Pasé un tiempo mirando el código, y cambiar el DATE_FORMAT no funcionará porque Rails nunca solicita el formato de fecha. La solución de ajuste de Felix: el valor funciona, pero se siente incómodo: ¿por qué debería tener que establecer manualmente el valor de los campos de texto con fecha específica? Así que este es un código, y yo quería algo mejor.

Esta es mi pequeña solución, pero luego la explicaré un poco porque espero que alguien escriba algo mejor:

MyModel < ActiveRecord::Base # ... self.columns.each do |column| if column.type == :date define_method "#{column.name}_before_type_cast" do self.send(column.name).to_s end end end end

Una explicación algo más larga: cuando un campo de texto está configurando el atributo de valor, primero se verá en el hash de opciones (que es la razón por la solución de Felix), pero si no está allí, llamará a form.object.check_in_date_before_type_cast , que (después de alguna magia method_missing) llamará a form.object.attributes_before_type_cast[''check_in_date''] , que buscará ''check_in_date'' en el hash @attributes dentro de form.object. Supongo que el hash @attributes obtiene la representación de cadena directa de MySQL (que sigue el formato ''aaaa-mm-dd'') antes de que quede envuelto en un objeto Ruby, por lo que simplemente establecer el DATE_FORMAT no funciona por sí mismo . Por lo tanto, la creación de métodos dinámicos anterior crea métodos para todos los objetos de fecha que realmente realizan el encasillado, lo que le permite formatear la fecha usando ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS[:default] .

Esto se siente un poco sucio porque el propósito de ''_forefore_type_cast'' es evitar un encasillamiento, y este es uno de esos monopatches de "ser dragones". Pero aún así, por lo que puedo decir, se siente como lo mejor de lo que hay alrededor. ¿Tal vez alguien más puede hacer un poco más de excavación y encontrar una mejor solución?



Tuve problemas similares con los atributos / campos de tiempo. Entonces uno puede seguir esto:

http://railscasts.com/episodes/32-time-in-text-field

Y funciona bastante bien.

Pero busqué y encontré otra solución interesante. Tipo de monopata feo, pero en algunos casos podría ser más útil que el de Railscasts.

Entonces tengo un modelo con una columna llamada time (ofc tiene un tipo de hora). Aquí está mi solución:

after_initialize :init private def init unless time.nil? @attributes[''time''] = I18n.l(time, format: :short) end end

Como puede ver, formato la variable que va a devolver el método time_before_type_cast . Así que he formateado correctamente el tiempo en mi entrada de texto (representada por FormBuilder ), pero si el usuario pone algo incorrecto como 10;23 todavía tengo esto y en la próxima solicitud será procesado por FormBuilder::text_field . Entonces el usuario tiene la oportunidad de arreglar su miserable error.


Vaya a su archivo environment.rb y agregue lo siguiente:

ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!( :default => ''%m-%d-%Y'' )

Consulte la documentación official si desea leer más :)