ForbiddenAttributesError 清除
ForbiddenAttributesError With Clearance
我正在使用许可进行注册,并且在注册表单中除了电子邮件和密码之外还有一些额外的属性,包括 first_name、last_name、角色和大学(如果角色是职员) .
我有三个用户角色:
enum role: { staff: 0, clinician: 1, admin: 2 }
我的实现有问题,因为注册尝试导致以下错误:
ActiveModel::ForbiddenAttributesError in Clearance::UsersController#create
将这行代码突出显示为有问题的行:
Clearance.configuration.user_model.new(user_params).tap do |user|
我做错了什么?任何帮助将不胜感激。
这是我的全部 app/clearance/users_controller.rb
class Clearance::UsersController < Clearance::BaseController
if respond_to?(:before_action)
before_action :redirect_signed_in_users, only: [:create, :new]
skip_before_action :require_login, only: [:create, :new], raise: false
skip_before_action :authorize, only: [:create, :new], raise: false
else
before_filter :redirect_signed_in_users, only: [:create, :new]
skip_before_filter :require_login, only: [:create, :new], raise: false
skip_before_filter :authorize, only: [:create, :new], raise: false
end
layout 'authentication'
def new
@user = user_from_params
render template: "users/new"
end
def create
@user = user_from_params
if @user.save
case @user.role
when "staff"
validate_user(@user)
when "clinician"
user.update_attribute(:approved, true)
deliver_email(@user)
end
else
render template: "users/new"
end
end
private
def validate_user(user)
if user.whitelisted?
user.update_attribute(:approved, true)
deliver_email(user)
else
redirect_to sign_in_path,
notice: "Your request will be analyzed"
end
end
def deliver_email(user)
user.forgot_password! #Generates confirmation token only
mail = ::ClearanceMailer.confirm_email(user)
if mail.respond_to?(:deliver_later)
mail.deliver_later
else
mail.deliver
end
redirect_to sign_in_path,
notice: "Please confirm your email address."
end
def avoid_sign_in
warn "[DEPRECATION] Clearance's `avoid_sign_in` before_filter is " +
"deprecated. Use `redirect_signed_in_users` instead. " +
"Be sure to update any instances of `skip_before_filter :avoid_sign_in`" +
" or `skip_before_action :avoid_sign_in` as well"
redirect_signed_in_users
end
def redirect_signed_in_users
if signed_in?
redirect_to Clearance.configuration.redirect_url
end
end
def url_after_create
Clearance.configuration.redirect_url
end
def user_params
params.require(:user).permit(
:email,
:password,
:role,
:first_name,
:last_name,
:university_id
)
end
Clearance.configuration.user_model.new(user_params).tap do |user|
user.email = email
user.password = password
user.role = role
user.first_name = first_name
user.last_name = last_name
if role == "staff"
user.university = University.find(university)
end
end
end
def user_params
params[Clearance.configuration.user_parameter] || Hash.new
end
end
问题是您不断调用 user_params
,其中 returns 符号 :user
。你需要更多这样的东西来定位正确的参数:
def user_from_params
email = params[:user].delete(:email)
password = params[:user].delete(:password)
role = params[:user].delete(:role)
first_name = params[:user].delete(:first_name)
last_name = params[:user].delete(:last_name)
university_id = params[user].delete(:university_id)
# and you can use whatever other params you sent with params[:user] here
Clearance.configuration.user_model.new(params[:user]).tap do |user|
user.email = email
user.password = password
user.role = role
user.first_name = first_name
user.last_name = last_name
if role == "staff"
user.university = University.find(university)
end
end
end
许可可用于使用强参数的新版本 Rails 和不使用强参数的旧版本 Rails。这意味着此代码比预期的要复杂一些。 default implementation of user_from_params
显式分配电子邮件和密码,因此我们在使用 attr_accessible 或强参数时完全避免批量分配。但是,我们还使用 Clearance.configuration.user_model.new(user_params)
.
将其余参数传递给用户模型
我不会覆盖 user_from_params
,而是研究覆盖 user_params
,以明确允许您想要允许的字段:
def user_params
params.require(:user).permit(
:email,
:password,
:role,
:first_name,
:last_name,
:university_id
)
end
值得指出的是,像这样分配 role
实际上看起来像是一个批量分配漏洞。您允许用户 select 他们的访问级别。如果这是某种可以接受的受信任系统,那么我想您采用的方法似乎不错。如果您依靠某些前端表单字段来限制谁可以注册每个角色...不要。
这个方法应该存在于你的用户控制器中,它应该继承自 Clearance::UsersController
。您似乎选择了重新定义 Clearance::UsersController
。我建议像下面这样创建您自己的 UsersController:
class UsersController < Clearance::UsersController
layout "authentication"
private
def user_params
params.require(:user).permit(
:email,
:password,
:role,
:first_name,
:last_name,
:university_id
)
end
end
这有 none 您提交的控制器的用户验证逻辑。我会尝试将其移至您的 User
模型。如果做不到这一点,您也可以在控制器中覆盖 create
。
您需要确保您的路由文件指向您的 UsersController
而不是 Clearance::UsersController
.
我正在使用许可进行注册,并且在注册表单中除了电子邮件和密码之外还有一些额外的属性,包括 first_name、last_name、角色和大学(如果角色是职员) .
我有三个用户角色:
enum role: { staff: 0, clinician: 1, admin: 2 }
我的实现有问题,因为注册尝试导致以下错误:
ActiveModel::ForbiddenAttributesError in Clearance::UsersController#create
将这行代码突出显示为有问题的行:
Clearance.configuration.user_model.new(user_params).tap do |user|
我做错了什么?任何帮助将不胜感激。
这是我的全部 app/clearance/users_controller.rb
class Clearance::UsersController < Clearance::BaseController
if respond_to?(:before_action)
before_action :redirect_signed_in_users, only: [:create, :new]
skip_before_action :require_login, only: [:create, :new], raise: false
skip_before_action :authorize, only: [:create, :new], raise: false
else
before_filter :redirect_signed_in_users, only: [:create, :new]
skip_before_filter :require_login, only: [:create, :new], raise: false
skip_before_filter :authorize, only: [:create, :new], raise: false
end
layout 'authentication'
def new
@user = user_from_params
render template: "users/new"
end
def create
@user = user_from_params
if @user.save
case @user.role
when "staff"
validate_user(@user)
when "clinician"
user.update_attribute(:approved, true)
deliver_email(@user)
end
else
render template: "users/new"
end
end
private
def validate_user(user)
if user.whitelisted?
user.update_attribute(:approved, true)
deliver_email(user)
else
redirect_to sign_in_path,
notice: "Your request will be analyzed"
end
end
def deliver_email(user)
user.forgot_password! #Generates confirmation token only
mail = ::ClearanceMailer.confirm_email(user)
if mail.respond_to?(:deliver_later)
mail.deliver_later
else
mail.deliver
end
redirect_to sign_in_path,
notice: "Please confirm your email address."
end
def avoid_sign_in
warn "[DEPRECATION] Clearance's `avoid_sign_in` before_filter is " +
"deprecated. Use `redirect_signed_in_users` instead. " +
"Be sure to update any instances of `skip_before_filter :avoid_sign_in`" +
" or `skip_before_action :avoid_sign_in` as well"
redirect_signed_in_users
end
def redirect_signed_in_users
if signed_in?
redirect_to Clearance.configuration.redirect_url
end
end
def url_after_create
Clearance.configuration.redirect_url
end
def user_params
params.require(:user).permit(
:email,
:password,
:role,
:first_name,
:last_name,
:university_id
)
end
Clearance.configuration.user_model.new(user_params).tap do |user|
user.email = email
user.password = password
user.role = role
user.first_name = first_name
user.last_name = last_name
if role == "staff"
user.university = University.find(university)
end
end
end
def user_params
params[Clearance.configuration.user_parameter] || Hash.new
end
end
问题是您不断调用 user_params
,其中 returns 符号 :user
。你需要更多这样的东西来定位正确的参数:
def user_from_params
email = params[:user].delete(:email)
password = params[:user].delete(:password)
role = params[:user].delete(:role)
first_name = params[:user].delete(:first_name)
last_name = params[:user].delete(:last_name)
university_id = params[user].delete(:university_id)
# and you can use whatever other params you sent with params[:user] here
Clearance.configuration.user_model.new(params[:user]).tap do |user|
user.email = email
user.password = password
user.role = role
user.first_name = first_name
user.last_name = last_name
if role == "staff"
user.university = University.find(university)
end
end
end
许可可用于使用强参数的新版本 Rails 和不使用强参数的旧版本 Rails。这意味着此代码比预期的要复杂一些。 default implementation of user_from_params
显式分配电子邮件和密码,因此我们在使用 attr_accessible 或强参数时完全避免批量分配。但是,我们还使用 Clearance.configuration.user_model.new(user_params)
.
我不会覆盖 user_from_params
,而是研究覆盖 user_params
,以明确允许您想要允许的字段:
def user_params
params.require(:user).permit(
:email,
:password,
:role,
:first_name,
:last_name,
:university_id
)
end
值得指出的是,像这样分配 role
实际上看起来像是一个批量分配漏洞。您允许用户 select 他们的访问级别。如果这是某种可以接受的受信任系统,那么我想您采用的方法似乎不错。如果您依靠某些前端表单字段来限制谁可以注册每个角色...不要。
这个方法应该存在于你的用户控制器中,它应该继承自 Clearance::UsersController
。您似乎选择了重新定义 Clearance::UsersController
。我建议像下面这样创建您自己的 UsersController:
class UsersController < Clearance::UsersController
layout "authentication"
private
def user_params
params.require(:user).permit(
:email,
:password,
:role,
:first_name,
:last_name,
:university_id
)
end
end
这有 none 您提交的控制器的用户验证逻辑。我会尝试将其移至您的 User
模型。如果做不到这一点,您也可以在控制器中覆盖 create
。
您需要确保您的路由文件指向您的 UsersController
而不是 Clearance::UsersController
.