NoMethodError - 使用设计注册的连接 table 中嵌套表单的未定义方法

NoMethodError - undefined method for a nested form from a join table using devise registration

我正在关注 this tutorial 如何在我的 Devise 注册表中嵌套其他模型。我的新控制器出现错误:

'NoMethodError in Users::RegistrationsController#new undefined method `languages_user=' #'。

Languages_Users 是一个连接 table,我想知道这是否是它不起作用的原因,但我不明白解决方案是什么。我想在用户注册时添加 Languages_Users 的 2 个不同记录。

型号:

User.rb

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

  has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100#" }, :default_url => "/images/:style/missing.png"

  validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
  validates_presence_of :first_name, :last_name, :location, :nationality, :bio

  before_save :assign_role

  def assign_role
    self.role = Role.find_by name: "user" if self.role.nil?
  end

  has_many :languages_users
    has_many :languages, :through => :languages_users
  accepts_nested_attributes_for :languages_users

Language.rb

class Language < ActiveRecord::Base

    has_many :languages_users
    has_many :users, :through => :languages_users
end

Langauges_user.rb

class LanguagesUser < ActiveRecord::Base
    belongs_to :user
    belongs_to :language

    validates_presence_of :user_id, :language_id, :level 
    validates :user_id, :uniqueness => {:scope => :language_id, :message => 'can only delcare each language once. Please change the level of the language in Manage Languages.'}

end

控制器:

registrations_controller.rb

 class Users::RegistrationsController < Devise::RegistrationsController

  def new
    build_resource({})
     self.resource.languages_user = LanguagesUser.new[sign_up_params]
    respond_with self.resource
  end
 def create
    @user_id = current_user.id
    super
 end

 def sign_up_params
    allow = [:email, :password, :password_confirmation, [languages_user_attributes: [:language_id, :user_id, :level]]]
  end
end

用户的相关部分new.html.erb

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>
   <%= f.fields_for :langauges_user do |lu| %>
      <%#= lu.text_field :language_id %>
      <%= lu.collection_select(:language_id, Language.order('language ASC').all, :id, :language) %><br>
      <%= lu.hidden_field languages_user[level], value: 1 %>
    <% end %>
    <%= f.submit "Sign up" %>
 <% end %>

相关路线

 Rails.application.routes.draw do
  resources :languages_users
  devise_for :users, controllers: { registrations: "users/registrations" }
  resources :users
    get 'languages_users/:id/sign_up', to: 'languages_users#sign_up', as: 'sign_up'

 end

我还在学习 - 如果您需要查看其他内容,请告诉我。谢谢!

我对 Devise 的了解还不够快,因为我自己最近才开始使用它,但如果我理解正确的话,这不是与 Devise 相关的问题——只是因为 Devise 的问题而更难修复 self.resource 抽象。

您在一个重要方面偏离了您的教程:在教程中 User 创建了 Company 但是 Company has_many :users。在你的例子中,User 创建了一个 LanguagesUser,但在这里,User has_many :languages_users。这意味着新的语法。这一行,当前导致您的错误:

self.resource.languages_user = LanguagesUser.new[sign_up_params]

需要遵循:

self.resource.languages_users.build(sign_up_params) #but see below re sign_up_params

或者如果您想立即保存相关资源(我假设不是,因为您现在不在),您可以使用 createcreate! 而不是 build.

放在一边

您可能 运行 使用您的 sign_up_params 方法遇到不同的麻烦,该方法似乎也偏离了教程 - 它实际上并未使用 allow 数组将任何内容列入白名单参数,至少如您问题中所写。在任何情况下,请注意他们在实例化 Company 时没有使用它,因此在构建 LanguagesUser 时它可能也不适合目的。

一旦您修复了 sign_up_params 方法,对 sign_up_params[:languages_user_attributes] 的简单调用就可以帮助您完成任务。或者您可以使用自己的参数白名单设置嵌套对象。