[英]Rails 4.1 User registration with polymorphic associations for multiple roles using devise ForbiddenAttributes error
我是Rails的新手,所以我從Rails 4開始學習它。我必須使用兩種類型的用戶-客戶和公司,因此我決定為其使用多態關聯。 現在,我正在嘗試通過devise (ver. 3.4.0)
為這些模型進行注冊和認證。 我在這里尋找解決方案並找到了答案,但據我了解它僅適用於Rails3。在Rails 4上,我無法解決允許屬性的問題,並且不斷收到錯誤ActiveModel::ForbiddenAttributesError
t.string "email",
t.string "encrypted_password",
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count",
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.datetime "created_at"
t.datetime "updated_at"
t.string "role_type"
t.integer "role_id"
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
belongs_to :role, :polymorphic => true
end
t.string "client_name"
t.datetime "created_at"
t.datetime "updated_at"
class Client < ActiveRecord::Base
has_one :user, :as => :role
end
t.string "company_name"
t.datetime "created_at"
t.datetime "updated_at"
t.string "company_tel"
class Company < ActiveRecord::Base
has_one :user, :as => :role
end
然后,我創建了一個用於設計的自定義視圖和注冊控制器,並將其放在routs.rb
:
devise_for :users, :controllers => { :registrations => 'registrations' }
resources :users
devise_scope :user do
get 'client/sign_up' => 'registrations#new', :user => { :user_type => 'client' }
get 'company/sign_up' => 'registrations#new', :user => { :user_type => 'company' }
end
注冊視圖
#views/registration/new.html.erb
<h2>Sign up</h2>
<%
# customized code begin
params[:user][:user_type] ||= 'client'
if ["client", "company"].include? params[:user][:user_type].downcase
child_class_name = params[:user][:user_type].downcase.camelize
user_type = params[:user][:user_type].downcase
else
child_class_name = "Client"
user_type = "client"
end
resource.role = child_class_name.constantize.new if resource.role.nil?
# customized code end
%>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<% my_devise_error_messages! # customized code %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<% # customized code begin %>
<%= fields_for resource.role do |rf| %>
<% render :partial => "#{child_class_name.underscore}_fields", :locals => { :f => rf } %>
<% end %>
<%= hidden_field :user, :user_type, :value => user_type %>
<% # customized code end %>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render :partial => "devise/shared/links" %>
該表格根據用戶類型包括部分附加字段
對於客戶
#views/registration/_client_fields.html.erb
<div><%= f.label :client_name %><br />
<%= f.text_field :client_name %></div>
對於公司
#views/registration/_company_fields.html.erb
<div><%= f.label :company_name %><br />
<%= f.text_field :company_name %></div>
<div><%= f.label :company_tel %><br />
<%= f.text_field :company_tel %></div>
Custon設計注冊控制器
#controllers/registration_controller.rb
class RegistrationsController < Devise::RegistrationsController
def create
user_params = sign_up_params # is sign_up_params not able to edit?
user_type = user_params.delete (:user_type) #take out user_type from user_params
child_class_params = user_params.delete (user_type.to_s.underscore.to_sym) #obtain a nested hash (:company or :client)
logger.debug "sign_up_params: #{sign_up_params}" #DEBUG
logger.debug "user_params: #{user_params}" #DEBUG
logger.debug "user_type: #{user_type}" #DEBUG
logger.debug "child_class_params: #{child_class_params}" #DEBUG
build_resource(user_params)
# crate a new child instance depending on the given user type
child_class = user_type.camelize.constantize
resource.role = child_class.new(child_class_params)
# first check if child instance is valid
# cause if so and the parent instance is valid as well
# it's all being saved at once
valid = resource.valid?
valid = resource.role.valid? && valid
# customized code end
if valid && resource.save # customized code
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_flashing_format?
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
@validatable = devise_mapping.validatable?
if @validatable
@minimum_password_length = resource_class.password_length.min
end
respond_with resource
end
end
end
現在,我需要允許公司或客戶使用參數和嵌套參數,所以我這樣做了:
#controllers/application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u|
u.permit(:email, :password, :password_confirmation, :user_type).tap do |wl|
if params[:company]
wl[:company] = params[:company]
elsif params[:client]
wl[:client] = params[:client]
end
end
}
end
end
所有參數都傳遞給控制器,但我認為許可公司和客戶嵌套參數存在問題,因為在網上ActiveModel::ForbiddenAttributesError in RegistrationsController#create
仍然存在ActiveModel::ForbiddenAttributesError in RegistrationsController#create
resource.role = child_class.new(child_class_params)
調試信息:
sign_up_params: {"email"=>"example@expample.com", "password"=>"12345678", "password_confirmation"=>"12345678", "user_type"=>"company", "company"=>{"company_name"=>"expample company name", "company_tel"=>"223-2323-2"}}
user_params: {"email"=>"example@expample.com", "password"=>"12345678", "password_confirmation"=>"12345678"}
user_type: company
child_class_params: {"company_name"=>"expample company name", "company_tel"=>"223-2323-2"}
您可以看到所有必要的參數都通過sign_up_params
傳遞給了控制器,那么為什么ForbiddenAttributes
錯誤?
問題已解決,這可能對我仍然不了解問題是什么的人有用,但我做到了:
resource.role = child_class.new(child_class_params.symbolize_keys)
它開始正常工作,沒有錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.