在将"custom"字段添加到 Devise 注册表时遇到问题



我正在为Devise注册表单添加一个"帐户计划"选择字段。

我的用户模型称为User,我的帐户计划模型称为AccountPlan。由于预计大多数用户实际上不是账户持有人,因此User通过PaidAccount连接到AccountPlan,即User具有一个AccountPlanPaidAccount

class User < ActiveRecord::Base
has_one :paid_account
has_one :account_plan, through: :paid_account
end

然后是我表格的相关部分:

<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { id: "payment-form" }) do |f| %>
<%= f.collection_select :account_plan, @account_plans, :id, :name_with_price %>
<% end %>

我的问题是,当我提交表单时(在我添加:account_plan字段之前,表单一直运行良好),我得到了

"2"的未定义方法"id":字符串

它告诉我有问题的行是super,这当然没有特别的帮助。我发现这句冒犯的台词是这样的,所以它显然不喜欢params的一些东西。

然而,令人困惑的是,如果我在控制台上执行User.new(account_plan: AccountPlan.new),它就可以了。所以,如果我的表单吐出这个HTML

<select id="user_account_plan" name="user[account_plan]"><option value="2">Lite ($10.00/mo)</option>
<option value="3">Professional ($20.00/mo)</option>
<option value="4">Plus ($30.00/mo)</option>
</select>

那么我不明白问题应该是什么。

如果有帮助的话,这是我的控制器代码:

class RegistrationsController < Devise::RegistrationsController
def new
@account_plans = AccountPlan.order(:price)
super
end
def create
super
Stripe.api_key = Rails.configuration.stripe_secret_key
Stripe::Customer.create(
card: params[:stripeToken],
description: resource.email
)
end
end

我猜PaidAccount包含许多付费账户的额外属性,包括账户计划的具体说明,即可用计划的列表。所以你的关系应该看起来像

class PaidAccount < ActiveRecord::Base
belongs_to :account_plan
end

(这意味着PaidAccount具有属性account_plan_id)

有两种方法:使用嵌套形式,或者使用更特别的形式。

使用嵌套窗体

我正在使用simple_formhaml-->请检查一下,这使代码更容易编写和显示:)

因此,在这种情况下,我会做以下操作:

class User 
has_one :paid_account
has_one :account_plan, through: :paid_account
accepts_nested_attributes_for :paid_account
end

因为我们没有创建一个新的account_plan,所以我们正在链接到一个现有的。

你的表格会变成:

= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { id: "payment-form" }) do |f|
= f.simple_fields_for :paid_account do |pa|
= pa.association :account_plan

这种方法的问题是:什么时候创建paid_account,如果看不到代码的其余部分,就很难判断。我看到两个选项:

  • 您只想在选择帐户计划时创建它
  • 或者您只允许用户在已经决定付款时选择帐户计划(并且您已经可以创建PaidAccount对象)

我猜这是第一个选项。为了使嵌套表单工作,您必须始终创建嵌套的PaidAccount,并在未填写帐户计划时保存时将其删除。这实际上很容易做到,因此我们添加了

accepts_nested_attributes_for :paid_account, reject_if: :blank

并且您的控制器new动作应该变成:

def new
@account_plans = AccountPlan.order(:price)
build_resource({})
resource.build_paid_account 
respond_with self.resource
end

还要注意,你必须正确地指定你的强参数,所以你的permits应该看起来像

def post_params
params.require(:user).permit(:email, :password, :paid_account_attributes => [:account_path_id])
end

更特别的方法

  • 像以前一样使用视图
  • 允许post_params中的account_plan(如上所述)
  • 在创建操作中检查account_plan的值,并在需要时使用正确的帐户计划构建PaidAccount

所以你的create动作看起来像

def create
account_plan_id = params[:user].delete(:account_plan)
super
if account_plan_id.present?
resource.build_paid_account(account_plan_id: account_plan_id)
end
Stripe.api_key = Rails.configuration.stripe_secret_key
Stripe::Customer.create(
card: params[:stripeToken],
description: resource.email
)
end

我认为您有两个问题:

  • 在collection_select中使用:account_plan_id作为对象的方法

  • 你必须"净化"你的params(因为Rails 4中的强参数-阅读更多https://github.com/plataformatec/devise#strong-参数)用于具有设计的附加字段。因此,在您的registrations_controller中添加可接受的参数,如:

    def sign_up_paramsparams.require(:user)permit(:email、:password、:password_confirmation、:current_password、:account_plan_id以及注册时所需的其他内容)结束

相关内容

  • 没有找到相关文章

最新更新