Rails 4.0 with Devise。 嵌套属性Unpermited参数

我正在使用Devise和Rails 4开发一个Web应用程序。我有一个用户模型,我已经扩展了2个额外的表单字段,这样当用户注册时,他也可以提交他的名字/姓氏。 (基于http://blog.12spokes.com/web-design-development/adding-custom-fields-to-your-devise-user-model-in-rails-4/ )。 我现在想要添加一个Institution模型。 此模型has_many :用户和用户belongs_to :institution。 我希望能够在注册用户的同一表格上注册该机构的名称 。 我知道我需要在我的Institution模型中使用nested_attribute,因为这是父类,我将稍微展示一下。 当我尝试注册用户时,我进入控制台: Unpermited参数:机构

我的提示是我无法根据我的子类(User)更新我的父类(Institution)。 可能有解决方案吗? 或者有没有人经历类似的事情?

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 

registrations / new.html.erb这里我有嵌套表格

  resource_name, :url => registration_path(resource_name)) do |f| %>  . .  


基于我之前链接的教程,我创建了一个新的User :: ParameterSanitizer ,它inheritance自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 

谢谢你的阅读!

控制台参数输出:

 {"utf8"=>"✓", "authenticity_token"=>"JKuN6K5l0iwFsj/25B7GKDj7WEHR4DO3oaVyGxGJKvU=", "user"=>{"email"=>"abc@foo.com", "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] ) 

我没有语法错误,但我得到Unpermited参数:请求中的机构。

我的信念是,这是因为用户是机构的孩子。 但是,我无法找到解决方法。

配置/ routes.rb中

像这样创建你自己的注册控制器…( 参见Devise文档,了解覆盖控制器的详细信息…… )…这是更优雅的方式,而不是通过ApplicationController

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

应用程序/控制器/用户/ registrations_controller.rb

覆盖新方法以创建与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 

分贝/迁移/ xxxxxxxxxxxxxx_create_profiles.rb

这是生成Profile模型的迁移( 请注意对User的引用 )…此示例配置文件仅将fullname保留为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 

应用程序/视图/设计/注册/ new.html

 <% resource.build_profile if resource.profile.nil? %> <%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %> 
    <%= devise_error_messages! %>
  • <%= f.fields_for :profile do |profile_fields| %> <%= profile_fields.label :fullname %> <%= profile_fields.text_field :fullname %> <% end %>
  • <%= f.label :password %> <%= f.password_field :password %>
  • <%= f.label :password_confirmation %> <%= f.password_field :password_confirmation %>
  • <%= f.submit %>
  • <%= render "devise/shared/links" %>

<% end %>

您必须创建自己的注册控制器才能执行此操作,具体方法如下:

的routes.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 

附加信息(嵌套属性+一些测试)

另请注意,如果您正在使用association和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 )

使用rails 5.1和devise 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 

这里的关键是你可以做以下而不需要单独的控制器:

  • 允许嵌套属性
  • 构建表单构建器的关系