【问题标题】:Rails undefined method 'map' for nil:NilClass用于 nil:NilClass 的 Rails 未定义方法“映射”
【发布时间】:2014-08-06 04:25:32
【问题描述】:

当我尝试从嵌套表单创建新记录时收到此消息。奇怪的是,当我退格到上一页(带有“创建”按钮的页面)并再次点击“创建”时,记录就被创建了。所以我不确定为什么它不会第一次创建记录,因为在第一次和第二次按下按钮期间我没有更改控制器中的创建方法。在此之前经历过的任何人都可以帮助我理解为什么会发生这种情况会很棒。

型号

class Benefit < ActiveRecord::Base
  belongs_to :account
  has_many :employee_benefits
  has_many :benefit_plans, :inverse_of => :benefit   
  belongs_to :benefit_coverage_period
  belongs_to :benefit_type_id, :class_name => "LookupTable", :foreign_key => "benefit_type"

  attr_accessible :account_id, :active, :attachment, :automatic_rollover, :id, :benefit_id, :benefit_type_id 
  attr_accessible :benefit_coverage_id, :benefit_type, :is_pretax, :benefit_coverage_period_id
  attr_accessible :description, :enrollable, :link, :name, :has_plans, :has_custom_amount, :benefit_plans_attributes

  validates_format_of :link, :message => "Please enter a valid URL", :with => /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix

  accepts_nested_attributes_for :benefit_plans, allow_destroy: true
end

class BenefitPlan < ActiveRecord::Base
  belongs_to :benefit, :inverse_of => :benefit_plans
  validates_presence_of :benefit
  has_many :employee_benefits
  has_many :benefit_coverages

  attr_accessible :benefit_id, :description, :name, :benefit_coverages_attributes, :link, :attachment

  accepts_nested_attributes_for :benefit_coverages, allow_destroy: true
end

class BenefitCoverage < ActiveRecord::Base
  belongs_to :benefit_plan  
  has_many :employee_benefits
  belongs_to :name_id, :class_name => "LookupTable", :foreign_key => "name"

  attr_accessible :benefit_plan_id, :name, :paycheck_deduction, :percentage_split, :total_cost

  accepts_nested_attributes_for :employee_benefits
end

控制器

def new
  @benefit = Benefit.new
  @benefit_coverage_periods = @account.benefit_coverage_periods
  1.times { @benefit.benefit_plans.build(:name => 'Default Plan') }
  @lookup_tables = LookupTable.where(:active => :true).find_all_by_group(30) || []
  @lookup_tables1 = LookupTable.where(:active => :true).find_all_by_group(31) || []
end

def create
  @benefit = Benefit.new(params[:benefit])
  @lookup_tables = LookupTable.where(:active => :true).find_all_by_group(30) || []
  @lookup_tables1 = LookupTable.where(:active => :true).find_all_by_group(31) || []
  @benefit_coverage_periods = @account.benefit_coverage_periods

  if @benefit.save
    redirect_to benefits_path, :notice => 'Benefit was successfully created.'
  else
    render :action => "new"
end

查看

= form_for @benefit, :html => { :class => "form-horizontal" }, :validate => true do |f|
  = f.hidden_field :account_id, :value => @account.id
  .control-group
    = f.label :name, :class => "control-label"
    .controls
      = f.text_field :name, :class => "text_field"
  .control-group
    = f.label :benefit_type, "Benefit Type", :class => "control-label"
    .controls
      = f.collection_select :benefit_type, @lookup_tables1, :id, :title, :prompt => true
...

错误

NoMethodError - undefined method `map' for nil:NilClass:
15:00:09 web.1   |   actionpack (3.2.14)                   lib/action_view/helpers/form_options_helper.rb:364:in `options_from_collection_for_select'
15:00:09 web.1   |   actionpack (3.2.14) lib/action_view/helpers/form_options_helper.rb:600:in `to_collection_select_tag'
15:00:09 web.1   |   actionpack (3.2.14) lib/action_view/helpers/form_options_helper.rb:191:in `collection_select'
15:00:09 web.1   |   actionpack (3.2.14) lib/action_view/helpers/form_options_helper.rb:646:in `collection_select'
15:00:09 web.1   |   client_side_validations (3.2.6) lib/client_side_validations/action_view/form_builder.rb:77:in `collection
_select_with_client_side_validations'
15:00:09 web.1   |   app/views/benefits/_form.html.haml:10:in `block in _app_views_benefits__form_html_haml___5210787370672092
58_70323180464100'
15:00:09 web.1   |   haml (4.1.0.beta.1) lib/haml/helpers/action_view_mods.rb:132:in `block (2 levels) in form_for_with_haml'
15:00:09 web.1   |   haml (4.1.0.beta.1) lib/haml/helpers.rb:284:in `with_tabs'
15:00:09 web.1   |   haml (4.1.0.beta.1) lib/haml/helpers/action_view_mods.rb:132:in `block in form_for_with_haml'
15:00:09 web.1   |   actionpack (3.2.14) lib/action_view/helpers/capture_helper.rb:40:in `block in capture'
15:00:09 web.1   |   actionpack (3.2.14) lib/action_view/helpers/capture_helper.rb:187:in `with_output_buffer'
...

【问题讨论】:

    标签: ruby-on-rails-3


    【解决方案1】:

    堆栈跟踪告诉您解决此问题所需知道的一切。学钓鱼吧!

    首先,“未定义方法 X 用于 Y”的意思是“您试图在对象 Y 上调用方法 X,但 Y 没有该方法”。在这种情况下,您尝试在 nil 上调用 map,而 nil 没有实现 map。所以我们正在寻找一个我们称之为map 的地方,然后我们将尝试找出为什么我们称之为map 的对象可能为nil。

    15:00:09 web.1 | app/views/benefits/_form.html.haml:10:in `block in _app_views_benefits__form_html_haml___5210787370672092

    这告诉您查看 _form.html.haml 中的第 10 行。这就是你要解决问题的地方。但是,问题发生在 lib/action_view/helpers/form_options_helper.rb:364options_from_collection_for_select 方法中。这是一个很好的猜测,对应于这一行:

    = f.collection_select :benefit_type, @lookup_tables1, :id, :title, :prompt => true

    如果您查看那里的源代码,您可以看到它在调用什么。从堆栈跟踪的顶部向后工作:

    我们可以看到它在传入的collection 上调用map。通过跟踪堆栈跟踪回到FormBuilder#collection_select 方法,我们可以准确确定这是哪个参数 - @lookup_tables1,在您的案例。

    现在,@lookup_tables1 已在您的 new 操作中设置,但它并未在您的 create 操作中设置,当您使用 render action: :new 时。由此,我们可以推测,当您第一次尝试保存您的福利记录时,save 失败并返回 false。您的第二个分支在那里运行,它尝试呈现 new 模板,但由于您没有设置 @lookup_tables1collection_select 尝试从 nil 集合创建选择框而失败。

    所以,你有两个任务:

    1. 在调用render action: :new 之前,从create 方法填充@lookup_tables1
    2. 找出您的福利记录无法保存的原因,并解决该问题。

    顺便说一句,您应该将 Rails 更新到最新的 3.x 系列(目前为 3.2.19)。 3.2.14 有几个漏洞已被修复。

    【讨论】:

    • 克里斯,感谢您出色的解释和教育。我已经更新了我的代码,现在页面呈现 :action => "new" 没有错误。但是,它仍然不会在第一次提交时保存/创建。您是否知道或听说过为什么在第一次提交时不会创建记录但在第二次提交时会创建记录?
    • 出现这种情况的原因有很多。您可以尝试调用#save! 而不是save,因为这样会在记录保存失败时抛出异常。在保存失败后,您可以交替查看记录中 #errors 的内容,以确定它为什么不运行。
    • 关于#save 的好建议!错误在于验证 - 验证失败:福利计划福利覆盖福利计划不能为空。
    • 正如我所提到的,我使用的是嵌套表单。所以从我有限的理解来看,也许我的模特伙伴是不正确的。但是,我仍然对为什么第二次提交会创建包含所有正确关联字段的记录感到困惑。上面添加的模型。
    • 说实话,我并没有真正过多地使用嵌套表单(主要是因为我似乎总是对它们有很大的麻烦)。但是,我建议使用 pry gem - 在您的创建操作中打一个 binding.pry,您可以在保存模型之前检查模型的状态等,看看它的状态是否符合您的预期。
    猜你喜欢
    • 2019-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多