web-dev-qa-db-ja.com

以前のバージョンのRailsでattr_accessibleを使用していた状況に遭遇したときのRails 4の禁止属性エラー

Rails 4への最近のアップグレードでは、次のようなコードを使用して属性を更新しても機能しません。ActiveModel::ForbiddenAttributesエラーが発生します。

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

ユーザーがモデル内に次のattr_accessible行を持っている場合:

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

Rails 4で同じタスクをどのように達成しますか?

39
Ecnalyr

Rails 4には、デフォルトで組み込みの strong_parameters gemの機能があります。

:as => :adminを呼び出す必要がなくなり、モデルにattr_accessible :user_attribute, :as => adminが必要なくなりました。その理由は、デフォルトでは、Railsアプリはモデルのすべての属性に対して「セキュリティ」を持っているためです。アクセス/変更したい属性をpermitする必要があります。

あとは、update_attributesの間にpermitを呼び出すだけです。

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

または、より正確に言うと:

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

ただし、この単一行により、すべてのユーザーがpermittedロールを変更できます。次のような別のフィルターを介して、管理者または他の任意の役割によるこのアクションへのアクセスのみを許可することを忘れないでください。

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

。 。 。 DeviseとCanCanを認証と承認に使用している場合に機能します。

41
Ecnalyr

新しいRails 4サイトを作成すると、生成されたコントローラーに、サニタイズされたパラメーターを受信するために使用するプライベートメソッドが含まれるようになります。これはニースのイディオムで、次のようになります。

private

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

一括割り当てを許可する古い方法は、次のようなものを使用することでした:

attr_accessible :username, :email, :password

モデル上で特定のパラメーターをアクセス可能としてマークします。

アップグレード

アップグレードするには、いくつかのオプションがあります。最適な解決策は、paramsメソッドを使用してコントローラーをリファクタリングすることです。しかし、これは今の時間よりも多くの作業になるかもしれません。

Protected_attributes gem

別の方法は、attr_accessibleメソッドを復元するprotected_attributes gemを使用することです。これにより、1つの大きな注意点があり、わずかにスムーズなアップグレードパスが実現します。

大注意

In Rails 3 attr_accessible呼び出しのないモデルはすべての属性を許可しました。

In Rails 4 protected_attributes gemを使用すると、この動作は逆になります。attr_accessible呼び出しのないモデルはすべての属性が制限されます。すべてのモデルでattr_accessibleを宣言する必要があります。 attr_accessibleを使用している場合は、これをすべてのモデルに追加する必要があります。これは、paramsメソッドを作成するだけの作業になる場合があります。

https://github.com/Rails/protected_attributes

35
superluminary

この問題は、 Cancan gem が原因の場合もあります。

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

コードをさらに変更することなく動作するのは、ここからです: https://github.com/ryanb/cancan/issues/835#issuecomment-18663815

9
Yavor Kirov

コントローラーアクションに新しいuser_paramsメソッドを追加することを忘れないでください:

  def create
    @user = User.new(user_params)

    @user.save
    redirect_to 'wherever'
  end
4
Haymaker87