17

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

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

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这里我有嵌套表格

<%= 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 %>

根据我之前链接的教程,我创建了一个新的User::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

感谢您的阅读!

控制台参数输出:

{"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] ) 

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

我相信这是因为用户是机构的孩子。但是,我一直无法找到解决此问题的方法。

4

3 回答 3

38

配置/路由.rb

像这样创建自己的注册控制器...(有关覆盖控制器的详细信息,请参阅设计文档...)...与通过ApplicationController

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

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

覆盖新方法以创建Profile与模型关联的方法,如下所示...在清理参数之前User运行该方法(注意如何添加嵌套参数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/migrate/xxxxxxxxxxxxxxx_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| %>
  <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 %>
于 2013-12-19T14:33:28.100 回答
12

为此,您必须创建自己的注册控制器,方法如下:

路线.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

这将允许任何参数,然后发布您的表单(这次应该通过)并查看您的 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 )

于 2013-07-20T23:03:20.690 回答
7

使用 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

这里的关键是您可以在不制作单独控制器的情况下执行以下操作:

  • 允许嵌套属性
  • 为表单构建器建立关系
于 2018-02-16T15:05:10.790 回答