Forum: Rails-ES self[:field]

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Tomás A. (Guest)
on 2008-11-12 14:03
Hola,
tenía una duda a ver si me pueden, me apoyo en este ejemplo:

  def full_name
    [first_name, last_name].join(" ").titleize
  end

  def full_name=(name)
    split = name.split(' ', 2)
    self.first_name = split[0]
    self.last_name = split[1]
  end

De igual forma, imaginemos que tengo un campo distance (que si existe en
la db), el usuario me da la distancia en kilómetros y yo la guardo en
metros:

  def distance=(value)
    write_attribute(:distance, value.to_f * 1000))
  end

Ahora quiero que cuando el usuario edite, no mostrarle el valor en
metros sino en kilómetros. He probado con:

  def distance
    self[:distance] / 1000
  end

Pero no me funciona. Como si no existiera esta función.

¿Alguna idea?
Jose Antonio P. (Guest)
on 2008-11-12 14:56
 Hola,

  no se si habrá sido un error al escribirlo aquí, pero el
write_attribute lo cierras con dos parentesis.



>   def distance=(value)
>     write_attribute(:distance, value.to_f * 1000))
>   end
>
Tomás A. (Guest)
on 2008-11-12 15:02
Sí, es una errata al escribirlo a mano.

Gracias.
Juan M. (Guest)
on 2008-11-12 15:19
(Received via mailing list)
Hola
   Por qué no hacés una especie de atributo virtual, tal vez
*distance_in_kilometers:

*
def distance_in_kilometers=(value)
  self.distance = value.to_f * 1000
end*
*

def distance_in_kilometers
  self.distance / 1000
end*
*
2008/11/12 Tomás Arcos <removed_email_address@domain.invalid>
Tomás A. (Guest)
on 2008-11-12 15:48
Porque quiero que cuando el usuario edite, el campo distance tiene la
distancia tal y como la introdujo, en kilómetros, y no en metros.
Vicent G. (Guest)
on 2008-11-12 15:59
Se podría utilizar un before_find; aunque tu código debería de
funcionar.

Un saludo.
Juan M. (Guest)
on 2008-11-12 16:05
(Received via mailing list)
Está bién, pero vos en el form:

en lugar de usar:

<% form_for @foo do |f| %>
    <%= f.text_field *:distance* %><br />
<% end %>

podrías usar:

<% form_for @foo do |f| %>
    <%= f.text_field *:distance_in_kilometers *%><br />
<% end %>




2008/11/12 Tomás Arcos <removed_email_address@domain.invalid>
Daniel R. Troitiño (Guest)
on 2008-11-12 16:26
(Received via mailing list)
Y ya que usas write_attribute ¿no te sirve read_attribute?
Tomás A. (Guest)
on 2008-11-12 16:50
Creo que he averiguado algo:

  def distance=(value)
    write_attribute(:distance, value.to_f * 1000))
  end

  def distance
    read_attribute(:distance) / 1000
  end

Por consola, funciona perfectamente, es decir, que si meto 1 kilómetro,
en la base de datos se guarda 1000 y cuando hago:

t.distance
=> 1

Correcto. El problema está cuando el usuario hace el edit por
formulario, le sale 1000 en vez de 1 en el campo de texto. Ahora si que
no enciendo nada de nada.
Daniel R. Troitiño (Guest)
on 2008-11-13 10:28
(Received via mailing list)
2008/11/12 Tomás Arcos <removed_email_address@domain.invalid>:
> Por consola, funciona perfectamente, es decir, que si meto 1 kilómetro,
> en la base de datos se guarda 1000 y cuando hago:
>
> t.distance
> => 1
>
> Correcto. El problema está cuando el usuario hace el edit por
> formulario, le sale 1000 en vez de 1 en el campo de texto. Ahora si que
> no enciendo nada de nada.

Es curioso, Rails utiliza "value_before_type_cast" como valor del
campo de texto, por eso ves el 1000 en vez del 1. La forma de
arreglarlo sería la siguiente:

<%= f.text_field :distance, :value => @modelo.distance %>

Es un poco pesadez, pero eso parece que lo arregla. Ahora tendriamos
que descubrir porqué los desarrolladores de Rails utilizan justo en
ese punto value_before_type_cast.

Suerte.
Daniel R. Troitiño (Guest)
on 2008-11-13 11:20
(Received via mailing list)
2008/11/13 Daniel R. Troitiño <removed_email_address@domain.invalid>:
>
> Es un poco pesadez, pero eso parece que lo arregla. Ahora tendriamos
> que descubrir porqué los desarrolladores de Rails utilizan justo en
> ese punto value_before_type_cast.

Y aquí está: <http://dev.rubyonrails.org/ticket/6908>

Parece ser que en tu caso, si alguien introduce letras en el campo de
texto puedes obtener un valor de 0 u otro, sin aviso para el usuario
(incluso teniendo un validates_numericality_of).

Este código parece que funciona correctamente:

---
  validates_numericality_of :distance

  def distance=(value)
    value_f = Float(value)
  rescue ArgumentError => e
    self[:distance] = value
  else
    self[:distance] = value_f * 1000
  end

  def distance
    value = distance_before_type_cast
    value_f = Integer(value)
  rescue ArgumentError => e
    value
  else
    value_f / 1000
  end
---

Si el usuario introduce alguna letra en el campo se le devolverá a la
pantalla de edición con la letra donde la escribió. En otro caso el
valor se guarda multiplicado por mil, y cuando se devuelve se devuelve
dividido entre mil (por supuesto tienes que utilizar también la opción
:value cuando dibujes el text_field).

Incluye un par de pruebas, un par de comentarios advirtiendo porque
haces esas cosas tan "raras" y listo.

Suerte.
This topic is locked and can not be replied to.