web-dev-qa-db-fra.com

Différence entre attr_accessor et attr_accessible

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

234
felix

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.

256
Paul Rubel

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.

173
Douglas

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.

48
Joshua Cheek

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.

18
sk1712

En deux mots:

_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é!

2
Manish Shrivastava

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.

2
Muhammad Yawar Ali