nil:NilClass的自联接关联未定义方法

伊娃

我有一个模型Item,它使用单表继承实现,共有三种类型。Item具有树结构,该结构使用has_many:through关系表示父级(称为组)和子级(称为sub_items)。一个子类(我们将其称为ItemA)在任何时候都必须只有一个父类(但其他子类可以有0个或多个父类)。我不知道如何实施验证来强制执行树层次结构的规则,因此我将其遗漏了。

ItemA有一个辅助方法parent,以获取其父对象。有时这种方法会提出来undefined method 'first' for nil:NilClass它并不总是发生,但在某些情况下会发生。

情况1

我正在使用jqGrid列出所有ItemAs。我对某些列(包括父列)使用了排序功能。网格最初将成功加载ItemA,表明它们全都具有应有的父项。但是,当我尝试对父列进行排序时,我会收到错误消息,好像它们突然消失了一样。当我includes(:groups)从排序方法中删除时,它消失了。我不知道为什么会有帮助,但我认为问题已解决。直到...

情况二

我正在用Rspec,Factory Girl和Selenium测试我的应用程序。在我的测试之一中,我parent在使用Factory Girl创建的ItemA实例上调用该方法。它引发了错误。parent间接使用该方法的测试不会失败。例如,该parent方法在ItemA的索引页面上被调用,并且许多测试毫无问题地访问了该页面。这种情况尚未解决。我的应用程序不再有对的调用includes,因此这次不属于该应用程序。

相关代码

项目A

class ItemA < Item
  # This method is called in Situation 1
  def self.sort_by_parent sort_order
    all.sort_by(&:parent_name).tap do |i|
      i.reverse! if sort_order == :desc
    end
  end
  
  def parent
    groups.take
  end

  def parent_name
    parent.component_name
  end
end

物品

class Item < ActiveRecord::Base
  has_many :item_groups, foreign_key: 'sub_item_id', dependent: :destroy
  has_many :groups, through: :item_groups
  has_many :group_items, class_name: 'ItemGroup', foreign_key: 'group_id', dependent: :destroy
  has_many :sub_items, through: :group_items
end

update_spec

feature 'ItemA editing', js: true do
  given!(:item_a) { create(:item_a) }
  given!(:parent) { create(:item_b) }

  scenario 'when parent', focus: true do
    itemas_page = ItemAsPage.visit # This is a custom page object

    # Situation 2 occurs here
    itemas_page.edit_parent item_a.parent_name, parent.component_name

    expect(itemas_page).to have_item_a_with parent.component_name
  end
end

为什么该parent方法有时读为nil,如何使它始终产生一个值?

编辑:在更改代码时,我遇到了更多导致此错误的情况。我检查了来源。这是快照ActiveRecord::FinderMethods

module ActiveRecord::FinderMethods
  def take(limit = nil)
    limit ? limit(limit).to_a : find_take
  end

  private
  def find_take
    if loaded?
      @records.first
    else
      @take ||= limit(1).to_a.first
    end
  end
end

出于调试目的,我将parent方法修改为如下所示:

def parent
  groups.tap {|g| puts '@records: ' + g.instance_variable_get(:@records).inspect }.take
end

@records是零。我尝试将其更改groups.reload.take为可以@records加载,但无法正常工作。我正在使用groups.limit(1).to_a.first,目前正在运行,但是我很想知道我的应用程序中是哪种错误导致了此问题。

伊娃

事实证明,尽管调用了reload,Rails仍然使用查询的缓存版本。此处描述相同的问题可以解决此问题:

class ItemA < Item
  def parent
    ActiveRecord::Base.uncached { groups.take }
  end
end

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章