【问题标题】:Rails 4.0 with Devise. Nested attributes Unpermited parameters带有设计的 Rails 4.0。嵌套属性 不允许的参数
【发布时间】:2013-07-20 22:47:53
【问题描述】:

我正在使用 Devise 和 Rails 4 开发一个网络应用程序。我有一个 User 模型,我已经扩展了 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 模型中需要一个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 并覆盖了 @ 987654324@方法如下:

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 parameters: Institutions in the Request。

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

【问题讨论】:

    标签: ruby-on-rails devise nested-forms nested-attributes strong-parameters


    【解决方案1】:

    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

    重写新方法以创建与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/migrate/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
    

    app/models/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
    

    app/models/profile.rb

    class Profile < ActiveRecord::Base
    
      # Associations
      belongs_to :user
    
      # Validations
      validates :fullname, presence: true
    end
    

    app/views/devise/registrations/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 %>
    

    【讨论】:

    • 非常感谢 King'ori,这正是我想要的!为我节省了几个小时的挫败感。
    • @king'ori Maina 我正在使用 devise_auth_token gem,在使用同一个 gem 的方法后,我仍然收到 Unpermitted parameter: account error in my server log
    • @Anjan 不幸的是我之前没有使用过devise_auth_token,所以不知道从哪里开始。我猜Unpermitted parameter: account 错误意味着需要将:account 参数添加到允许的参数中。请参阅上面Users::RegistrationsController 类中的configure_permitted_parameters 方法,了解我如何添加配置文件属性。
    • 这个答案应该被接受为正确答案!
    【解决方案2】:

    您必须创建自己的注册控制器才能这样做,方法如下:

    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
    

    其他信息(嵌套属性 + 一些测试)

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

    【讨论】:

    • 感谢您的回复。我确实试过这个。我不工作,因为它仍然不允许机构模型的参数。
    • 我看到了^_^。我确实是这样写的:allow = [:email, :first_name, :last_name, :password, :password_confirmation, :name],其中 :name 是另一个模型中的字段。
    • 我想这与用户是机构的孩子这一事实有关。或者我错了
    • 顺便说一句,params.require(resource_name) 部分依赖于 User 是“父”模型这一事实,但在您的情况下,您应该将 resource_name 替换为 :institution。另一方面,我不知道设计对此有何反应,但这是另一个问题(我们在这里谈论的是强参数,对吧?)
    • 是的,我们正在谈论强参数,是的,在这种情况下,用户是孩子。我已经替换了 resource_name 并得到了这个“未找到参数:机构”,所以我猜它不起作用。
    【解决方案3】:

    使用 rails 5.1 和 devise 4.4.1 以下是最短的并且效果很好:

    app/models/user.rb

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

    app/controllers/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
    

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多