13

我使用設計和Rails 4.我有一個用戶模型,我有2個額外的表單字段,例如延長一個web應用程序的工作,當用戶註冊後,他還可以提交自己的第一個/姓氏。 (根據http://blog.12spokes.com/web-design-development/adding-custom-fields-to-your-devise-user-model-in-rails-4/)。我現在要添加一個機構模型。這種模式的has_many:用戶,belongs_to的用戶:機構。我希望能夠以相同的形式我註冊用戶的註冊機構的名稱。我知道我需要在我的機構模型nested_attribute,因爲這是父,我會稍微顯示。當我嘗試註冊用戶我在控制檯中:Unpermited參數:機構Rails 4.0與Devise。嵌套屬性Unpermited參數

我的提示是,我不能更新我的父類(機構)根據我的孩子類(用戶)。可能有解決辦法嗎?還是有人經歷過類似的事情?

class Institutions < ActiveRecord::Base 
    has_many :users, 
    accepts_nested_attributes_for :users 
end 

class User < ActiveRecord::Base 
    devise :database_authenticatable, :registerable, 
    :recoverable, :rememberable, :trackable, :validatable 
    belongs_to :institution 
end 

註冊/ new.html.erb這裏我有嵌套形式

<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|  %> 
<%= devise_error_messages! %> 
. 
. 
    <%= f.fields_for :institutions do |i| %> 
     <p><%= i.label :name %><br /> 
     <%= i.text_field :institutions_attr %></p> 
    <% end %> 

基於我有聯繫前面,我創建了一個新的用戶:: ParameterSanitizer的教程,從Devise :: ParameterSanitizer繼承,並重寫sign_up方法如下:

的lib/user_sanitizer.rb

private 
def sign_up 
    default_params.permit(:first_name, :last_name ,:email, :password, :password_confirmation, :current_password, institutions_attributes: [:id, :name]) 
end 

最後,我application_controller.rb

class ApplicationController < ActionController::Base 
    protect_from_forgery with: :exception 

    protected 
    def devise_parameter_sanitizer 
    if resource_class == User 
    User::ParameterSanitizer.new(User, :user, params) 
    else 
    super 
    end 
    end 
end 

感謝您的閱讀!

控制檯PARAMS輸出:

{"utf8"=>"✓", 
"authenticity_token"=>"JKuN6K5l0iwFsj/25B7GKDj7WEHR4DO3oaVyGxGJKvU=", 
"user"=>{"email"=>"[email protected]", 
"first_name"=>"abc", 
"last_name"=>"xyz", 
"institutions"=>{"name"=>"Government"}, 
"password"=>"[FILTERED]", 
"password_confirmation"=>"[FILTERED]"}, 
"commit"=>"Sign up"} 

編輯

至於建議,我已經加入

params.require(resource_name).permit(:email, :first_name, :last_name, institution: [:name], :password, :password_confirmation) and I get an *error syntax error, unexpected ',', expecting => ...nstitution: [:name], :password, :password_confirmation)* 

但是,如果我重新編輯到

params.require(resource_name).permit(:email, :first_name, :last_name, :password, :password_confirmation, institution: [:name]) 

我得到沒有語法錯誤,但我得到非預期參數:機構在請求。

我的看法是,這是因爲用戶是Institution的孩子。但是,我一直無法找到解決辦法。

回答

33

的config/routes.rb中

創建自己的登記控制器是這樣的...(see Devise documentation for the details of overriding controllers here ...)...這是更優雅的方式,而不是通過ApplicationController

devise_for :users, controllers: {registrations: 'users/registrations'} 

app/controllers/users/registrations_controller.rb

將新方法覆蓋到cre吃了如下的User模型相關聯的Profile ...運行configure_permitted_parameters方法之前,消毒參數(注如何添加嵌套參數

class Users::RegistrationsController < Devise::RegistrationsController 

    before_filter :configure_permitted_parameters 

    # GET /users/sign_up 
    def new 

    # Override Devise default behaviour and create a profile as well 
    build_resource({}) 
    resource.build_profile 
    respond_with self.resource 
    end 

    protected 

    def configure_permitted_parameters 
    devise_parameter_sanitizer.for(:sign_up) { |u| 
     u.permit(:email, :password, :password_confirmation, :profile_attributes => :fullname) 
    } 
    end 
end 

DB /遷移/ xxxxxxxxxxxxxx_create_profiles.rb

這是生成Profile模型的遷移(請注意參考User)...此示例配置文件僅將fullname保存爲e User的擴展,但隨意添加,只要你願意!

class CreateProfiles < ActiveRecord::Migration 
    def change 
    create_table :profiles do |t| 
     t.references :user 
     t.string :fullname 
     t.timestamps 
    end 
    end 
end 

應用程序/模型/ user.rb

class User < ActiveRecord::Base 

    # Associations 
    has_one :profile, dependent: :destroy, autosave: true 

    # Allow saving of attributes on associated records through the parent, 
    # :autosave option is automatically enabled on every association 
    accepts_nested_attributes_for :profile 

    # Devise 
    # Include default devise modules. Others available are: 
    # :confirmable, :lockable, :timeoutable and :omniauthable 
    devise :database_authenticatable, :registerable, 
     :recoverable, :rememberable, :trackable, :validatable 
end 

應用程序/模型/ profile.rb

class Profile < ActiveRecord::Base 

    # Associations 
    belongs_to :user 

    # Validations 
    validates :fullname, presence: true 
end 

應用程序/視圖/設計/註冊/新。 html

<% resource.build_profile if resource.profile.nil? %> 
<%= form_for(resource, :as => resource_name, 
         :url => registration_path(resource_name)) do |f| %> 
    <ul> 

    <%= devise_error_messages! %> 

    <li class="fullname"> 
     <%= f.fields_for :profile do |profile_fields| %> 
     <%= profile_fields.label :fullname %> 
     <%= profile_fields.text_field :fullname %> 
     <% end %> 
    </li> 
    <li class="email"> 
     <%= f.label :email %> 
     <%= f.email_field :email, :autofocus => true %> 
    </li> 
    <li class="password"> 
     <%= f.label :password %> 
     <%= f.password_field :password %> 
    </li> 
    <li class="password"> 
     <%= f.label :password_confirmation %> 
     <%= f.password_field :password_confirmation %> 
    </li> 
    <li> 
     <%= f.submit %> 
    </li> 
    <li> 
     <p><%= render "devise/shared/links" %></p> 
    </li> 
    </ul> 
<% end %> 
+5

優秀答案 –

+1

非常感謝King'ori,這正是我一直在尋找的!爲我節省了幾個小時的挫折。 – DerProgrammer

+0

@ king'ori Maina我正在使用devise_auth_token gem,並且在掉落上述同樣寶石的方法後,我仍然收到Unermitted參數:我的服務器日誌中存在帳戶錯誤 – Anjan

13

你必須創建自己的登記控制器這樣做,這裏是如何:

路線。RB

devise_for :users, controllers: {registrations: 'registrations'} 

控制器

你必須要允許(抱歉,如果我留給你的領域取代:your_fields,但是最讓我的回答更普遍,因此可用於任何人都可以通過)

class RegistrationsController < Devise::RegistrationsController 

    private 

    def sign_up_params 
     allow = [:email, :your_fields, :password, :password_confirmation] 
     params.require(resource_name).permit(allow) 
    end 

end 

附加信息(嵌套屬性+一些測試)

另外請注意,如果您使用的聯想和accepts_nested_attributes_for你將有params結構這樣

model: {field, field, field, associated_model: {field, field}}

和關閉過程必須在您sign_up_params方法使用相同的結構。如果您需要了解這一點,你可以改變sign_up_params方法是這樣的內容:

def sign_up_params 
     params.require(resource_name).permit! 
    end 

這將允許任何PARAM,然後發佈形式(它應該通過這一次),然後尋找到你的Rails控制檯查看的params結構,最後你可以建立sign_up_params方法正確

檢查這更多信息http://www.railsexperiments.com/using-strong-parameters-with-nested-forms/

在你的情況,你應該使用:

params.require(resource_name).permit(:email, :first_name, :last_name, institutions: [:name], :password, :password_confirmation)

+0

THX的答覆。我確實嘗試過。我沒有工作,因爲它仍然不允許Institution模型的參數。 –

+0

Ok編輯我的回答 – Benj

+0

我看到了^ _ ^。我按照以下方式編寫它:allow = [:email,:first_name,:last_name,:password,:password_confirmation,:name],其中:name是另一個模型中的字段。 –

2

使用Rails 5.1,並制定4.4.1以下是最短和作品不錯:

應用程序/模型/ user.rb

after_initialize do 
    build_profile if new_record? && profile.blank? 
end 

應用程序/控制器/ application_controller.rb

before_action :configure_permitted_parameters, if: :devise_controller? 

def configure_permitted_parameters 
    devise_parameter_sanitizer.permit(:sign_up, keys: [{ profile_attributes: :name }]) 
end 

這裏的關鍵是你可以做下面的事情,而不需要單獨的con troller:

  • 許可證嵌套屬性
  • 的表單生成器生成的關係