Rails:向“form_for ... as :: user”添加字段时出现未定义的方法错误

时间:2016-04-28 20:14:24

标签: ruby-on-rails forms ruby-on-rails-4

在我的项目中,我使用了来自 Ryan Bigg的“多租户与Rails”的想法。每个帐户都有很多用户,帐户所有者可以邀请可以在发送给他们的电子邮件中点击"Accept invitation"的用户。如果用户尚未在站点上登录/注册,则将呈现以下表单partial:

_anonymous_accept.html.erb

<%= form_for(@invitation, url: accepted_invitation_path(params[:slug], @invitation), as: :user) do |f| %>

  <%= f.label :email %>
  <%= f.email_field :email, value: @invitation.email, class: 'form-control' %>

  <%= f.label :password %>
  <%= f.password_field :password, class: 'form-control' %>

  <%= f.label :password_confirmation, "Confirmation" %>
  <%= f.password_field :password_confirmation, class: 'form-control' %>

  <%= f.submit "Accept invitation", class: "button" %>

<% end %>

在提交时,这由邀请控制器中的已接受操作处理:

invitations_controller.rb

def accept
  store_location_for(:user, request.fullpath)
  @invitation = Invitation.find_by!(token: params[:id])
end

def accepted
  @invitation = Invitation.find_by!(token: params[:id])

  if user_signed_in?
    user = current_user
  else
    user_params = params[:user].permit(
      :email,
      :password,
      :password_confirmation
    )

    user = User.create!(user_params)
    sign_in(user)
  end

  current_account.users << user

  flash[:success] = "Welcome! You have joined the #{current_account.name} account!"
  redirect_to dashboard_path(params[:slug])
end

现在,这完全有效,直到我向表单添加更多字段。我不希望用户能够在不输入全名的情况下进行注册,因此我尝试将以下行添加到上面的代码示例中:

# added to the above sample from _anonymous_accept.html.erb

<%= f.label :firstname %>
<%= f.text_field :firstname, class: 'form-control' %>

<%= f.label :lastname %>
<%= f.text_field :lastname, class: 'form-control' %>

和此:

# added to the permitted user params in the accepted action in invitations_controller.rb

:firstname,
:lastname,

这些更改会破坏代码并向我提供此错误:

NoMethodError in Accounts::InvitationsController#accept 
undefined method `firstname' for #<Invitation:0x0000000478cb58>

我无法看到此错误背后的逻辑,因为电子邮件和密码参数被接受,而不是名字和姓氏,当它们都来自同一个用户模型时。

有人有任何建议吗?

编辑:

从服务器日志中,按要求:

NoMethodError (undefined method `firstname' for #<Invitation:0x00000005a32208>):
  app/views/accounts/invitations/_anonymous_accept.html.erb:12:in `block in _app_views_accounts_invitations__anonymous_accept_html_erb___2610584697742424634_41597720'
  app/views/accounts/invitations/_anonymous_accept.html.erb:9:in `_app_views_accounts_invitations__anonymous_accept_html_erb___2610584697742424634_41597720'
  app/views/accounts/invitations/accept.html.erb:9:in `_app_views_accounts_invitations_accept_html_erb__4463442190025129055_39118520'

编辑2:

# from db/schema.rb

create_table "invitations", force: :cascade do |t|
  t.string   "email"
  t.integer  "account_id"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.string   "token"
end

# from models/invitation.rb

class Invitation < ActiveRecord::Base
  belongs_to :account
  before_create :generate_token

  validates :email, presence: true

  def to_param
    token
  end

  private

  def generate_token
    self.token = SecureRandom.hex(16)
  end
end

3 个答案:

答案 0 :(得分:0)

您的表单适用于@invitation实例对象,该对象没有任何firstnamelastname属性。 如果邀请与用户模型有关系,请在邀请时使用fields_for或添加firstname&amp; lastname字段到您的邀请模式。

答案 1 :(得分:0)

可能问题来自于设计。试试这种方式,让我知道......

class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) << [:firstname, :lastname]
  end
end

将此项添加到invitation.rb文件中。

<强>更新

attr_accessor :firstname, :lastname

答案 2 :(得分:0)

好吧,我让它成功了。不过,这可能是一种廉价的解决方法。

我替换了这些行:

# from _anonymous_accept.html.erb

<%= f.label :firstname %>
<%= f.text_field :firstname, class: 'form-control' %>

<%= f.label :lastname %>
<%= f.text_field :lastname, class: 'form-control' %>

......用以下几行:

<%= label_tag("user[firstname]", "Your first name:") %>
<%= text_field_tag("user[firstname]") %>

<%= label_tag("user[lastname]", "Your last name:") %>
<%= text_field_tag("user[lastname]") %>

所以我想我只是绕过对未定义方法的调用:firstname和:lastname,形式为helper。

如果这真的很糟糕,请告诉我: - )