web-dev-qa-db-fra.com

Erreur d'attributs interdits dans Rails 4 en rencontrant une situation où l'on aurait utilisé attr_accessible dans les versions antérieures de Rails

Avec la récente mise à niveau vers Rails 4, la mise à jour des attributs à l'aide de code ressemblant au ci-dessous ne fonctionne pas, j'obtiens un ActiveModel::ForbiddenAttributes Erreur:

@user.update_attributes(params[:user], :as => :admin)

Où l'utilisateur a la ligne attr_accessible suivante dans le modèle:

attr_accessible :role_ids, :as =>admin
# or any attribute other than :role_ids contained within :user

Comment accomplissez-vous la même tâche dans Rails 4?

39
Ecnalyr

Rails 4 possède désormais des fonctionnalités de la gemme strong_parameters intégrée par défaut.

Il n'est plus nécessaire d'appeler :as => :admin, vous n'avez pas non plus besoin du attr_accessible :user_attribute, :as => admin dans votre modèle. La raison en est que, par défaut, les applications Rails ont désormais la "sécurité" pour chaque attribut sur les modèles. Vous devez permit l'attribut auquel vous souhaitez accéder/modifier.

Il ne vous reste plus qu'à appeler permit pendant update_attributes:

@user.update_attributes(params[:user], permit[:user_attribute])

ou, pour être plus précis:

@user.update_attributes(params[:user].permit(:role_ids))

Cette seule ligne, cependant, permet à tout utilisateur de modifier le rôle permitted. Vous devez vous rappeler de n'autoriser l'accès à cette action que par un administrateur ou tout autre rôle souhaité via un autre filtre tel que le suivant:

authorize! :update, @user, :message => 'Not authorized as an administrator.'

. . . ce qui fonctionnerait si vous utilisez Devise et CanCan pour l'authentification et l'autorisation.

41
Ecnalyr

Si vous créez un nouveau site Rails 4, vous remarquerez que les contrôleurs générés incluent désormais une méthode privée que vous utilisez pour recevoir vos paramètres nettoyés. Ceci est un idiome agréable et ressemble à ceci:

private

  def user_params
    params.require(:user).permit(:username, :email, :password)
  end

L'ancienne façon d'autoriser l'attribution de masse consistait à utiliser quelque chose comme:

attr_accessible :username, :email, :password

sur votre modèle pour marquer certains paramètres comme accessibles.

Mise à niveau

Pour mettre à niveau, vous avez plusieurs options. Votre meilleure solution serait de refactoriser vos contrôleurs avec une méthode params. Cela pourrait être plus de travail que vous n'en avez pour l'instant.

Gemme Protected_attributes

L'alternative serait d'utiliser la gemme protected_attributes qui rétablit la méthode attr_accessible. Cela permet un chemin de mise à niveau légèrement plus fluide avec une mise en garde majeure.

Avertissement majeur

Dans Rails 3 tout modèle sans appel attr_accessible autorise cependant tous les attributs.

Dans Rails 4 avec la gemme protected_attributes, ce comportement est inversé. Tout modèle sans appel attr_accessible a tous les attributs restreints. Vous devez maintenant déclarer attr_accessible sur tous vos modèles. Cela signifie, si vous ne l'avez pas en utilisant attr_accessible, vous devrez l'ajouter à tous vos modèles, ce qui peut être autant de travail que de simplement créer une méthode params.

https://github.com/Rails/protected_attributes

35
superluminary

Ce problème peut également être causé par le bijou Cancan

Ajoutez simplement à application_controller.rb

before_filter do
  resource = controller_name.singularize.to_sym
  method = "#{resource}_params"
  params[resource] &&= send(method) if respond_to?(method, true)
end

Fonctionne sans aucune modification de code supplémentaire ici: https://github.com/ryanb/cancan/issues/835#issuecomment-18663815

9
Yavor Kirov

N'oubliez pas d'ajouter votre nouvelle méthode user_params à l'action du contrôleur:

  def create
    @user = User.new(user_params)

    @user.save
    redirect_to 'wherever'
  end
4
Haymaker87