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で同じタスクをどのように達成しますか?
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))
ただし、この単一行により、すべてのユーザーがpermit
tedロールを変更できます。次のような別のフィルターを介して、管理者または他の任意の役割によるこのアクションへのアクセスのみを許可することを忘れないでください。
authorize! :update, @user, :message => 'Not authorized as an administrator.'
。 。 。 DeviseとCanCanを認証と承認に使用している場合に機能します。
新しいRails 4サイトを作成すると、生成されたコントローラーに、サニタイズされたパラメーターを受信するために使用するプライベートメソッドが含まれるようになります。これはニースのイディオムで、次のようになります。
private
def user_params
params.require(:user).permit(:username, :email, :password)
end
一括割り当てを許可する古い方法は、次のようなものを使用することでした:
attr_accessible :username, :email, :password
モデル上で特定のパラメーターをアクセス可能としてマークします。
アップグレードするには、いくつかのオプションがあります。最適な解決策は、paramsメソッドを使用してコントローラーをリファクタリングすることです。しかし、これは今の時間よりも多くの作業になるかもしれません。
別の方法は、attr_accessibleメソッドを復元するprotected_attributes gemを使用することです。これにより、1つの大きな注意点があり、わずかにスムーズなアップグレードパスが実現します。
In Rails 3 attr_accessible呼び出しのないモデルはすべての属性を許可しました。
In Rails 4 protected_attributes gemを使用すると、この動作は逆になります。attr_accessible呼び出しのないモデルはすべての属性が制限されます。すべてのモデルでattr_accessibleを宣言する必要があります。 attr_accessibleを使用している場合は、これをすべてのモデルに追加する必要があります。これは、paramsメソッドを作成するだけの作業になる場合があります。
この問題は、 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
コントローラーアクションに新しいuser_paramsメソッドを追加することを忘れないでください:
def create
@user = User.new(user_params)
@user.save
redirect_to 'wherever'
end