web-dev-qa-db-fra.com

"AVERTISSEMENT: impossible d'attribuer en masse des attributs protégés"

J'ai utilisé des techniques RESTful pour générer un modèle (en fait, j'utilise Devise gem, ce qui me permet de le faire) et j'ai ajouté de nouveaux champs nommés prénom et nom au modèle. La migration s'est bien passée. J'ai ajouté attr_accessor: first_name,: last_name au modèle et je m'attendais à ce que cela fonctionne. Mais lorsque j'essaie d'assigner en masse de nouvelles instances avec Doctor.create ({: first_name => "MyName"}), etc., je reçois des erreurs indiquant que je ne peux pas attribuer en masse des attributs protégés.

Je pensais que l’usage d’attr_accessor était de contourner la protection des champs d’un modèle. Pouvez-vous m'aider à donner un sens à ce message?

Edit: oh, et d'ailleurs les enregistrements ne sont pas créés non plus. Je pensais qu'ils devraient l'être car il ne s'agit que d'un avertissement, mais ils ne figurent pas dans la base de données.

Edit2: voici mon modèle

class Doctor < User
  has_many :patients
  has_many :prescriptions, :through=> :patients

  validates_presence_of :invitations, :on => :create, :message => "can't be blank"

  attr_accessor :invitations
end

et le schéma, qui ne comporte ni les prénoms, ni les noms de famille, car ils sont créés dans la table users, qui est l'ancêtre des docteurs. J'ai utilisé l'héritage de table unique.

create_table :doctors do |t|
  t.integer :invitations

  t.timestamps
end

et ceci est la migration pour changer la table des utilisateurs

add_column :users, :first_name, :string
add_column :users, :last_name, :string
add_column :users, :type, :string

EDIT: voici le fichier de départ. Je n'inclus pas la méthode truncate_db_table, mais cela fonctionne.

%w{doctors patients}.each do |m|
  truncate_db_table(m)  
end  

Doctor.create(:invitations=>5, :email=>"[email protected]", :first_name=>"Name", :last_name=>"LastName")
Patient.create(:doctor_id=>1, :gender=>"male", :date_of_birth=>"1991-02-24")
67
picardo

Ne confondez pas attr_accessor avec attr_accessible. L'accesseur est intégré à Ruby et définit une méthode d'accesseur en lecture - model_instance.foo # returns something - et une méthode de définition - model_instance.foo = 'bar'.

Accessible est défini par Rails et rend l'attribut assignable en masse (fait l'inverse de attr_protected).

Si first_name est un champ de la table de base de données de votre modèle, Rails a déjà défini les getters et les setters pour cet attribut. Il suffit d’ajouter attr_accessible :first_name.

140
Robert Speicher

Pour pirater votre application de manière non sécurisée et totalement impropre au mode de production:

Allez à /config/application.rb Faites défiler vers le bas jusqu'à la fin où vous trouverez

{config.active_record.whitelist_attributes = true}

Réglez-le sur false.

EDIT/btw (après 4 mois de travail intensif avec Ruby, y compris un atelier de 11 semaines): DHH estime que pour les noobies (ses mots), "opérationnel" est plus important que "très sécurisé" .

AVIS: Beaucoup de développeurs expérimentés Rails) sont très passionnés par le fait que pas veut que vous le fassiez.

MISE À JOUR: 3 ans plus tard, une autre façon de le faire - encore une fois, non sécurisée, mais meilleure que la solution ci-dessus, probablement parce que vous devez le faire pour chaque modèle.

class ModelName < ActiveRecord::Base
  column_names.each do |col|
    attr_accessible col.to_sym
  end
  ...
end
11
boulder_ruby

N'utilisez pas attr_accessor ici. ActiveRecord les crée automatiquement sur le modèle. En outre, ActiveRecord ne créera pas d'enregistrement si une erreur de validation ou d'affectation en masse est générée.

EDIT: Vous n'avez pas besoin d'une table de médecins, vous avez besoin d'une table d'utilisateurs avec une colonne de type pour gérer Rails héritage d'une table) . Les invitations seront sur les utilisateurs Ah, je vois dans votre exemple de code ajouté que vous avez le type sur les utilisateurs. Supprimez la table des médecins, déplacez les invitations vers les utilisateurs, et je pense que vous devriez être d'accord. Supprimez également attr_accessor. Inutile.

N'oubliez pas que Rails STI utilise la même table pour toutes les classes et sous-classes d'un modèle particulier. Tous vos enregistrements Doctor seront des lignes dans la table des utilisateurs avec un type de "docteur".

EDIT: De plus, êtes-vous sûr de vouloir uniquement valider la présence des invitations lors de la création et non les mises à jour?

2
Dave Sims

Ajouter attr_accessible : variable1, variable2 dans votre fichier de routage de table.

2
Aneez

D'accord avec @Robert Speicher, mais je vous recommande fortement d'utiliser paramètre Fort au lieu de attr_accessible pour protéger de la cession en masse.

À votre santé!

0
Manish Shrivastava

Si vous souhaitez désactiver la protection d'attribution en masse pour un appel individuel (mais pas globalement), l'option :without_protection => true Peut être utilisée. Je trouve cela utile pour les migrations et autres endroits où les clés/valeurs du hachage sont codées en dur ou connues pour être sûres.

Exemple ici (fonctionne dans Rails 3.2 également): https://apidock.com/Rails/v3.1.0/ActiveRecord/Base/create/class

0
Kyle McClellan