Dans Rails, quelle est la différence entre attr_accessor
et attr_accessible
? A ma connaissance, l’utilisation de attr_accessor
est utilisée pour créer des méthodes d’affichage et de définition pour cette variable, afin que nous puissions accéder à la variable comme Object.variable
ou Object.variable = some_value
.
J'ai lu que attr_accessible
rend cette variable spécifique accessible au monde extérieur. Est ce que quelqu'un peut me dire quelle est la différence
attr_accessor
est une méthode Ruby qui crée un getter et un setter. attr_accessible
est une méthode Rails qui vous permet de passer des valeurs à une affectation en masse: new(attrs)
ou update_attributes(attrs)
.
Voici une mission de masse:
Order.new({ :type => 'Corn', :quantity => 6 })
Vous pouvez imaginer que la commande peut également comporter un code de réduction, par exemple :price_off
. Si vous ne marquez pas :price_off
en tant que attr_accessible
, vous empêchez un code malveillant de fonctionner de la sorte:
Order.new({ :type => 'Corn', :quantity => 6, :price_off => 30 })
Même si votre formulaire n'a pas de champ pour :price_off
, s'il est dans votre modèle, il est disponible par défaut. Cela signifie qu'un POST spécialement construit peut toujours le définir. Utiliser attr_accessible
liste blanche les choses qui peuvent être assignées en masse.
Beaucoup de gens sur ce fil et sur Google expliquent très bien que attr_accessible
spécifie une liste blanche d'attributs qui peuvent être mis à jour en bloc ( tous les attributs d'un modèle d'objet ensemble à la même heure ) Il s’agit principalement (et uniquement) de protéger votre application contre l’exploit pirate "Affectation de masse".
Ceci est expliqué ici sur le Railsofficiel _ doc: Assignation en masse
attr_accessor
est un code Ruby permettant de créer (rapidement) des méthodes de définition et d'acquisition dans une classe. C'est tout.
Maintenant, ce qui manque comme explication, c'est que lorsque vous créez en quelque sorte un lien entre un modèle (Rails) et une table de base de données, vous n'avez JAMAIS, JAMAIS, JAMAIS besoin de attr_accessor
dans votre modèle pour créer des setters et des getters afin de: pouvoir modifier les enregistrements de votre table.
En effet, votre modèle hérite de toutes les méthodes de la classe ActiveRecord::Base
, qui définit déjà les accesseurs CRUD de base (Créer, Lire, Mettre à jour, Supprimer). Ceci est expliqué dans la documentation officielle ici Modèle Rails et ici Remplacer l'accesseur par défaut (allez au chapitre "Remplacer l'accesseur par défaut")
Dites par exemple que: nous avons une table de base de données appelée "utilisateurs" qui contient trois colonnes "prénom", "nom" et "rôle":
Instructions SQL:
CREATE TABLE users (
firstname string,
lastname string
role string
);
J'ai supposé que vous définissiez l'option config.active_record.whitelist_attributes = true
dans votre config/environment/production.rb afin de protéger votre application contre l'exploit d'affectation en masse. Ceci est expliqué ici: Mass Assignment
Votre modèle Rails fonctionnera parfaitement avec le modèle ci-dessous:
class User < ActiveRecord::Base
end
Cependant, vous devrez mettre à jour chaque attribut d'utilisateur séparément dans votre contrôleur pour que la vue de votre formulaire fonctionne:
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
Maintenant, pour vous faciliter la vie, vous ne voulez pas créer un contrôleur compliqué pour votre modèle utilisateur. Vous allez donc utiliser la méthode spéciale attr_accessible
dans votre modèle de classe:
class User < ActiveRecord::Base
attr_accessible :firstname, :lastname
end
Vous pouvez donc utiliser l’autoroute (affectation de masse) pour mettre à jour:
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
Vous n'avez pas ajouté les attributs de "rôle" à la liste attr_accessible
parce que vous ne laissez pas vos utilisateurs définir leur rôle par eux-mêmes (comme admin). Vous le faites vous-même sur une autre vue d'administration spéciale.
Bien que votre vue utilisateur ne présente pas de champ "rôle", un pirate peut facilement envoyer une requête HTTP POST incluant le "rôle" dans le hachage params. L'attribut "rôle" manquant sur le attr_accessible
est destiné à protéger votre application de cela.
Vous pouvez toujours modifier votre attribut user.role lui-même, comme ci-dessous, mais pas avec tous les attributs ensemble.
@user.role = DEFAULT_ROLE
Pourquoi diable utiliseriez-vous le attr_accessor
?
Eh bien, ce serait dans le cas où votre formulaire utilisateur affiche un champ qui n'existe pas dans votre table d'utilisateurs sous forme de colonne.
Par exemple, supposons que votre vue utilisateur affiche un champ "indiquez-le-administrateur-que-je-suis-ici". Vous ne voulez pas stocker cette information dans votre table. Vous voulez juste que Rails vous envoie un e-mail vous avertissant qu'un utilisateur "fou" ;-) s'est abonné.
Pour pouvoir utiliser ces informations, vous devez les stocker temporairement quelque part. Quoi de plus facile que de le récupérer dans un attribut user.peekaboo
?
Donc, vous ajoutez ce champ à votre modèle:
class User < ActiveRecord::Base
attr_accessible :firstname, :lastname
attr_accessor :peekaboo
end
Vous pourrez ainsi utiliser de manière éclairée l'attribut user.peekaboo
de votre contrôleur pour envoyer un courrier électronique ou faire ce que vous voulez.
ActiveRecord n'enregistre pas l'attribut "peekaboo" dans votre table lorsque vous effectuez un user.save
car elle ne voit aucune colonne correspondant à ce nom dans son modèle.
attr_accessor
est une méthode Ruby qui vous donne les méthodes setter et getter pour une variable d'instance du même nom. Donc, cela équivaut à
class MyModel
def my_variable
@my_variable
end
def my_variable=(value)
@my_variable = value
end
end
attr_accessible
est une méthode Rails qui détermine les variables pouvant être définies dans une affectation en masse.
Lorsque vous soumettez un formulaire et que vous avez quelque chose comme MyModel.new params[:my_model]
, vous souhaitez avoir un peu plus de contrôle pour que les utilisateurs ne puissent pas soumettre des éléments que vous ne souhaitez pas.
Vous pouvez faire attr_accessible :email
pour que, lorsque quelqu'un met à jour son compte, il puisse modifier son adresse e-mail. Mais vous ne feriez pas attr_accessible :email, :salary
car une personne pourrait alors définir son salaire par le biais d'une soumission de formulaire. En d'autres termes, ils pourraient pirater leur chemin vers une augmentation.
Ce type d'information doit être explicitement traité. Le supprimer du formulaire ne suffit pas. Quelqu'un pourrait entrer avec Firebug et ajouter l'élément dans le formulaire pour soumettre un champ de salaire. Ils pourraient utiliser le lien intégré pour soumettre un nouveau salaire à la méthode de mise à jour du contrôleur, ils pourraient créer un script qui soumet une publication avec ces informations.
Donc, attr_accessor
concerne la création de méthodes pour stocker des variables, et attr_accessible
concerne la sécurité des assignations en masse.
attr_accessor
est le code Ruby et est utilisé lorsque vous n'avez pas de colonne dans votre base de données, mais que vous souhaitez tout de même afficher un champ dans vos formulaires. La seule façon de permettre cela est de attr_accessor :fieldname
et vous pouvez utiliser ce champ dans votre vue ou modèle si vous le souhaitez, mais surtout dans votre vue.
Considérons l'exemple suivant
class Address
attr_reader :street
attr_writer :street
def initialize
@street = ""
end
end
Ici, nous avons utilisé attr_reader
( attribut lisible ) et attr_writer
( attribut en écriture ) pour accéder à l'objectif. Mais nous pouvons obtenir la même fonctionnalité en utilisant attr_accessor
. En bref, attr_accessor donne accès aux méthodes getter et setter.
Le code ainsi modifié est comme ci-dessous
class Address
attr_accessor :street
def initialize
@street = ""
end
end
attr_accessible
vous permet de répertorier toutes les colonnes pour lesquelles vous souhaitez autoriser l'affectation en masse. Le contraire de ceci est attr_protected
qui signifie ce champ que je ne veux PAS que quiconque soit autorisé à attribuer en masse à. Il est plus que probable que ce sera un champ dans votre base de données avec lequel vous ne voudrez plus faire de singe. Comme un champ d'état, ou similaire.
_attr_accessor
_ est la méthode getter
, setter
. alors que attr_accessible
signifie que cet attribut est accessible ou non. c'est ça.
Je souhaite ajouter que nous devrions utiliser paramètre Strong au lieu de _attr_accessible
_ pour protéger de la cession en masse.
À votre santé!
n aperçu rapide et concis de la différence:
attr_accessor
est un moyen simple de créer des accesseurs en lecture et en écriture dans votre classe. Il est utilisé lorsque vous n'avez pas de colonne dans votre base de données, mais que vous souhaitez tout de même afficher un champ dans vos formulaires. Ce champ est un“virtual attribute”
dans un modèle Rails.attribut virtuel - attribut ne correspondant pas à une colonne de la base de données.
attr_accessible
est utilisé pour identifier les attributs accessibles par vos méthodes de contrôleur rend une propriété disponible pour une affectation en masse. Elle autorisera uniquement l'accès aux attributs que vous spécifiez, refusant le reste.