Diferencia entre attr_accessor y attr_accessible

235

En Rails, ¿cuál es la diferencia entre attr_accessory attr_accessible? Según tengo entendido, el uso attr_accessorse usa para crear métodos getter y setter para esa variable, de modo que podamos acceder a la variable como Object.variableo Object.variable = some_value.

Leí que attr_accessiblehace que esa variable específica sea accesible para el mundo exterior. ¿Puede alguien decirme cuál es la diferencia?

felix
fuente
44
Tienes razón en que attr_accessorse utiliza para generar métodos getter y setter. Consulte mi respuesta a una pregunta anterior para obtener una explicación bastante completa de attr_accessible: stackoverflow.com/questions/2652907/… y luego actualice su pregunta si necesita otros detalles específicos después de eso.
mikej
2
attr_accessible ya no se admite en Rails 4 a menos que use la gema protected_attributes, según la respuesta principal a stackoverflow.com/questions/17371334/… (julio de 2014)
esmerilado

Respuestas:

258

attr_accessores un método Ruby que hace un captador y un colocador. attr_accessiblees un método Rails que le permite pasar valores a una asignación en masa: new(attrs)o update_attributes(attrs).

Aquí hay una asignación masiva:

Order.new({ :type => 'Corn', :quantity => 6 })

Puede imaginar que el pedido también podría tener un código de descuento, por ejemplo :price_off. Si no etiqueta :price_offya attr_accessibleque impide que el código malicioso pueda hacer lo siguiente:

Order.new({ :type => 'Corn', :quantity => 6, :price_off => 30 })

Incluso si su formulario no tiene un campo para :price_off, si está en su modelo, está disponible de forma predeterminada. Esto significa que un POST diseñado aún podría configurarlo. El uso de attr_accessiblelistas blancas es aquellas cosas que pueden asignarse en masa.

Paul Rubel
fuente
2
¿Por qué no está attr_accessibleen la documentación de Rails? api.rubyonrails.org
Chloe
19
Parece que Rails4 tiene una nueva forma de hacer las cosas. Vea esta respuesta: stackoverflow.com/questions/17371334/…
Paul Rubel
1
Porque el parámetro fuerte ha reemplazado el uso de attr_accessible edgeguides.rubyonrails.org/…
Imran Ahmad
173

Muchas personas en este hilo y en google explican muy bien que attr_accessibleespecifica una lista blanca de atributos que se pueden actualizar de forma masiva ( todos los atributos de un modelo de objetos juntos al mismo tiempo ) Esto es principalmente (y solo) para proteger su aplicación del exploit pirata "Asignación masiva".

Esto se explica aquí en el documento oficial de Rails: Asignación masiva

attr_accessores un código ruby ​​para (rápidamente) crear métodos setter y getter en una clase. Eso es todo.

Ahora, lo que falta como explicación es que cuando crea de alguna manera un enlace entre un modelo (Rails) con una tabla de base de datos, NUNCA, NUNCA, NUNCA necesita attr_accessoren su modelo crear creadores y captadores para poder modificar su registros de la mesa.

Esto se debe a que su modelo hereda todos los métodos de la ActiveRecord::BaseClase, que ya define los accesos CRUD básicos (Crear, Leer, Actualizar, Eliminar) por usted. Esto se explica en el documento oficial aquí Modelo de rieles y aquí Sobrescribir acceso predeterminado (desplácese hacia abajo hasta el capítulo "Sobrescribir acceso predeterminado")

Digamos por ejemplo que: tenemos una tabla de base de datos llamada "usuarios" que contiene tres columnas "nombre", "apellido" y "rol":

Instrucciones SQL:

CREATE TABLE users (
  firstname string,
  lastname string
  role string
);

Asumí que estableciste la opción config.active_record.whitelist_attributes = trueen tu config / environment / production.rb para proteger tu aplicación del ataque de asignación masiva. Esto se explica aquí: Asignación masiva

Su modelo Rails funcionará perfectamente con el modelo aquí abajo:

class User < ActiveRecord::Base

end

Sin embargo, deberá actualizar cada atributo de usuario por separado en su controlador para que la Vista de su formulario funcione:

def update
    @user = User.find_by_id(params[:id])
    @user.firstname = params[:user][:firstname]
    @user.lastname = params[:user][:lastname]

    if @user.save
        # Use of I18 internationalization t method for the flash message
        flash[:success] = t('activerecord.successful.messages.updated', :model => User.model_name.human)
    end

    respond_with(@user)
end

Ahora para facilitar su vida, no desea hacer un controlador complicado para su modelo de Usuario. Entonces usará el attr_accessiblemétodo especial en su modelo de Clase:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname

end

Para que pueda usar la "autopista" (asignación masiva) para actualizar:

def update
    @user = User.find_by_id(params[:id])

    if @user.update_attributes(params[:user])
        # Use of I18 internationlization t method for the flash message
        flash[:success] = t('activerecord.successful.messages.updated', :model => User.model_name.human)
    end

    respond_with(@user)
end

No agregó los atributos de "rol" a la attr_accessiblelista porque no permite que sus usuarios establezcan su rol por sí mismos (como administrador). Lo haces tú mismo en otra vista especial de administrador.

Aunque su vista de usuario no muestra un campo de "rol", un pirata podría enviar fácilmente una solicitud HTTP POST que incluya "rol" en el hash de parámetros. El atributo "rol" que falta en el attr_accessiblees proteger su aplicación de eso.

Todavía puede modificar su atributo user.role por sí solo como a continuación, pero no con todos los atributos juntos.

@user.role = DEFAULT_ROLE

¿Por qué demonios usarías el attr_accessor?

Bueno, esto sería en el caso de que su formulario de usuario muestre un campo que no existe en su tabla de usuarios como una columna.

Por ejemplo, supongamos que su vista de usuario muestra un campo "por favor, dígale al administrador que estoy aquí". No desea almacenar esta información en su tabla. Solo quiere que Rails le envíe un correo electrónico advirtiéndole que un usuario "loco" ;-) se ha suscrito.

Para poder utilizar esta información, debe almacenarla temporalmente en algún lugar. ¿Qué más fácil que recuperarlo en un user.peekabooatributo?

Entonces agrega este campo a su modelo:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname
  attr_accessor :peekaboo

end

Por lo tanto, podrá hacer un uso educado del user.peekabooatributo en algún lugar de su controlador para enviar un correo electrónico o hacer lo que quiera.

ActiveRecord no guardará el atributo "peekaboo" en su tabla cuando lo haga user.saveporque no ve ninguna columna que coincida con este nombre en su modelo.

Douglas
fuente
48

attr_accessores un método Ruby que le brinda métodos setter y getter a una variable de instancia del mismo nombre. Entonces es equivalente a

class MyModel
  def my_variable
    @my_variable
  end
  def my_variable=(value)
    @my_variable = value
  end
end

attr_accessible es un método Rails que determina qué variables se pueden establecer en una asignación en masa.

Cuando envía un formulario, y tiene algo así, MyModel.new params[:my_model]entonces quiere tener un poco más de control, para que las personas no puedan enviar cosas que usted no desea.

Puede hacerlo attr_accessible :emailpara que cuando alguien actualice su cuenta, pueda cambiar su dirección de correo electrónico. Pero no lo haría attr_accessible :email, :salaryporque entonces una persona podría establecer su salario mediante el envío de un formulario. En otras palabras, podrían hackear su camino a un aumento.

Ese tipo de información debe manejarse explícitamente. Simplemente eliminarlo del formulario no es suficiente. Alguien podría entrar con firebug y agregar el elemento en el formulario para enviar un campo de salario. Podrían usar el rizo incorporado para enviar un nuevo salario al método de actualización del controlador, podrían crear un script que envíe una publicación con esa información.

Entonces, attr_accessorse trata de crear métodos para almacenar variables y attr_accessiblese trata de la seguridad de las asignaciones masivas.

Joshua Cheek
fuente
2
Tienes un error tipográfico, después del bloque de código debería decirattr_accesible
Chubas
Gran redacción, me gusta el ejemplo de la clase. ¡Puntos de bonificación adicionales (falsos) por incluir una explicación de :as!
Ian Vaughan
El modelo es extendido por ActiveRecord :: Base. class User < ActiveRecord::Base
Verde
18

attr_accessores el código ruby ​​y se usa cuando no tiene una columna en su base de datos, pero aún quiere mostrar un campo en sus formularios. La única forma de permitir esto es attr_accessor :fieldnamey puede usar este campo en su Vista o modelo, si lo desea, pero principalmente en su Vista.

Consideremos el siguiente ejemplo

class Address
    attr_reader :street
    attr_writer :street  
    def initialize
        @street = ""
    end
end

Aquí hemos utilizado attr_reader( atributo legible ) y attr_writer( atributo de escritura ) para acceder al propósito. Pero podemos lograr la misma funcionalidad usando attr_accessor. En resumen, attr_accessor proporciona acceso a los métodos getter y setter.

Entonces el código modificado es el siguiente

class Address
    attr_accessor :street  
    def initialize
        @street = ""
    end
end

attr_accessiblele permite enumerar todas las columnas que desea permitir la asignación masiva. Lo opuesto a esto es lo attr_protectedque significa este campo que NO quiero que nadie pueda asignar misas. Es más que probable que sea un campo en su base de datos con el que no quiera que nadie esté jugando. Como un campo de estado o similar.

shrikant1712
fuente
2
Entonces, ¿está diciendo que si he creado campos en una migración, luego los hago disponibles usando attr_accessible, no hay necesidad de crear un captador y establecedor? Pero si el campo no está en la base de datos, ¿por qué attr_accessible no actúa como un captador / definidor? Si incluyo una línea "has_secure_password", attr_accessible se vuelve suficiente para permitir que getter / setter: contraseña y: contraseña_confirmación aunque no estén en la base de datos. Muy confundido;)
tentimes
2

En dos palabras:

attr_accessores getter, settermétodo mientras que attr_accessiblees decir que ese atributo particular es accesible o no. Eso es.


Deseo agregar que debemos usar el parámetro Strong en lugar de attr_accessibleprotegernos de la asignación masiva.

¡Salud!

Shrivastava Manish
fuente
2

Un resumen rápido y conciso de la diferencia:

attr_accessores una manera fácil de crear accesores de lectura y escritura en su clase. Se utiliza cuando no tiene una columna en su base de datos, pero aún desea mostrar un campo en sus formularios. Este campo es un “virtual attribute”en un modelo Rails.

atributo virtual : un atributo que no corresponde a una columna en la base de datos.

attr_accessible se utiliza para identificar los atributos a los que pueden acceder sus métodos de controlador, lo que hace que una propiedad esté disponible para la asignación masiva. Solo permitirá el acceso a los atributos que especifique, denegando el resto.

Muhammad Yawar Ali
fuente