¿Cómo puedo sobrescribir un método getter en un modelo ActiveRecord?

98

Estoy tratando de sobrescribir un método getter para un modelo ActiveRecord. Tengo un atributo llamado nameen el modelo Categoryy me gustaría poder hacer algo como esto:

def name
  name_trans || name
end

Si el name_transatributo no es nulo, devuélvalo; de lo contrario, devuelva el nameatributo. ¿Cómo haría esto?

Esto debería llamarse normalmente así:

@category.name
Oyvindhauge
fuente

Respuestas:

123

La Guía de estilo de rieles recomienda usar self[:attr]over read_attribute(:attr).

Puedes usarlo así:

def name
  name_trans || self[:name]
end
Wonsup Lee
fuente
¿Por qué es mejor? No se limite a vincular a otros sitios, incluya los bits relevantes aquí. Los enlaces pueden volverse inválidos
JamesT
2
Para un poco más de contexto, consulte aquí: github.com/bbatsov/rails-style-guide/issues/155
mimsugara
98

Actualización: el método preferido de acuerdo con la Guía de estilo de Rails es usar en self[:name]lugar de read_attributey write_attribute. Te animo a que omitas mi respuesta y prefieras esta .


Puede hacerlo exactamente así, excepto que debe usarlo read_attributepara recuperar el valor del atributo de nombre y evitar la llamada recursiva al namemétodo:

def name 
  name_trans || read_attribute(:name)
end
meagar
fuente
2
Cualquier idea de por qué Rubocop prefiere self[:name]más read_attribute[:name]?
Zack Xu
18

Me gustaría agregar otra opción para sobrescribir el método getter, que es simplemente: super.

def name
  name_trans || super
end

esto no solo funciona en el método getter de atributos, sino también en los métodos getter de asociaciones, también。

lei liu
fuente
1
Esto es lo que recomiendan actualmente las guías de Rails, para captadores Y definidores
sandre89
5

Anular el getter y usar read_attributeno funciona para asociaciones, pero puede usar alias_method_chainen su lugar.

def name_with_override
  name_trans || name_without_override
end

alias_method_chain :name, :override
Patrick Oscity
fuente
¿Puede dar un ejemplo adecuado ...?
Arup Rakshit
Bien. Acabo de ver el doco . Ahora, si invoco nameel objeto modelo, ¿cuál se llamará name_with_overrideo name_without_override?
Arup Rakshit
1
nameahora llamará name_with_override. Si desea llamar al método original por alguna razón, puede llamar name_without_override.
Patrick Oscity
Ya veo ... Gracias por sus respuestas //
Arup Rakshit
2

Si usa atributos de tienda como este

store :settings, accessors: [:volume_adjustment] 

o usando gemas como hstore_accessor enlace de gemas

Así que terminó usando el storemétodo en el modelo, luego, para anular esos métodos que no puede usar self.read_attribute, debe usar en su lugar superasí:

def partner_percentage
  super.to_i || 10
end
onemanstartup
fuente
0

Si alguien quiere actualizar el valor después del name_transmétodo getter, puede usar self [: name] =.

def name
  self[:name] = name_trans || self[:name]
  # don't do this, it will cause endless loop
  # update(name: name_trans)
end
fangxing
fuente
0

Puede utilizar el método read_attribute de Rails. Documentos de rieles

Rajat Bansal
fuente
Si bien este enlace puede responder la pregunta, las respuestas de solo enlace no están permitidas en SO, agregue algo de contexto a su respuesta de lo que hay detrás de ese enlace. ¡Gracias! :)
AJT82