为什么Rails会为我的模型中存在的属性提供"无方法错误"? - Rails 3

mar*_*ion 0 ruby-on-rails ruby-on-rails-3

这是我得到的错误:

NoMethodError in Devise::RegistrationsController#create

undefined method `trial_duration' for nil:NilClass
app/models/user.rb:120:in `set_trial_end'
Run Code Online (Sandbox Code Playgroud)

这是我的相关部分 User.rb

before_create :set_trial_end

def set_trial_end
  plan = self.plan
  end_of_trial = Date.today + self.plan.trial_duration.days
  self.trial_end_date = end_of_trial.to_date
end
Run Code Online (Sandbox Code Playgroud)

奇怪的是,如果我查看我的数据库,对于分配了计划并查看trial_duration属性的用户,我会收到回复:

ruby-1.9.2-p0 > tu
 => #<User id: 29, email: "test50@abc.com", encrypted_password: "$2a$10$TKKQmBYem.vDq.mwDutv2u92Vick0X0jAIUQT6A9.FM....", password_salt: "$2a$10$TKKQmBYem.vDq.mwDutv2u", reset_password_token: nil, remember_token: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2011-06-18 23:03:12", last_sign_in_at: "2011-06-18 23:03:12", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", username: "test50", first_name: "Test", last_name: "Fifty", created_at: "2011-06-18 23:02:48", updated_at: "2011-06-18 23:03:12", invitation_token: nil, invitation_sent_at: nil, plan_id: 2, current_state: nil, confirmation_token: nil, confirmed_at: "2011-06-18 23:03:12", confirmation_sent_at: "2011-06-18 23:02:47", space_used: 0, failed_attempts: 0, unlock_token: nil, locked_at: nil, trial_end_date: "2011-07-02", active_subscription: nil, customer_id: nil> 
ruby-1.9.2-p0 > tu.plan
 => #<Plan id: 2, name: "Boutique", storage: 100.0, num_of_projects: 99999, num_of_clients: 10, cached_slug: "boutique", created_at: "2011-01-31 09:46:57", updated_at: "2011-08-11 08:22:48", amount: 19, trial_duration: 14, trial_duration_unit: "days", currency: "USD", billing_cycle: 28, billing_cycle_unit: "days"> 
ruby-1.9.2-p0 > tu.plan.trial_duration
 => 14
ruby-1.9.2-p0 > tu.plan.trial_duration.days
 => 14 days 
Run Code Online (Sandbox Code Playgroud)

所以不确定为什么Rails会给我这个错误.

有任何想法吗?

编辑1:

在我看来,我有这个:

<% if params[:promo] %>
    <%= text_field_tag "xcode", nil, :placeholder => "Coupon Code" %><br /> 
<%= hidden_field_tag(:plan_id, "1") %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

在POST中,从我的日志中,您可以看到参数plan_id设置为1

Started POST "/users" for 127.0.0.1 at 2011-08-24 03:11:07 -0500
  Processing by Devise::RegistrationsController#create as HTML
  Parameters: {"utf8"=>"?", "authenticity_token"=>"Jp2GHxnuVOVnI/sfr1CB4EQ9URCTJynv/2Ek4AiU8Lg=", "user"=>{"username"=>"test.user", "first_name"=>"Testing", "last_name"=>"User", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "email"=>"testuser@abc.com"}, "xcode"=>"testcouponcode", "plan_id"=>"1", "commit"=>"Register"}
nil
Run Code Online (Sandbox Code Playgroud)

但我仍然Plan can't be blank在下一页收到错误.

我添加了after_validation回调而不是after_create,所以我不再是NoMethodError.但问题没有解决.

mu *_*ort 5

你正在使用before_create假设self.plan已设置的钩子:

before_create :set_trial_end

def set_trial_end
  #...
  end_of_trial = Date.today + self.plan.trial_duration.days
Run Code Online (Sandbox Code Playgroud)

你的错误说:

undefined method `trial_duration' for nil:NilClass
Run Code Online (Sandbox Code Playgroud)

你的电话self.plan也是如此.nilset_trial_end

也许你想要一个after_create钩子,这样你就可以使用一些实例数据了.即使这样,你也要检查self.plan.nil?(以防万一)并使用验证来确保你得到一个:

class User < ActiveRecord::Base
  validates_presence_of :plan_id
  #...
Run Code Online (Sandbox Code Playgroud)

或者也许一个after_validation钩子会更好地为你服务.