【发布时间】:2014-09-28 07:29:29
【问题描述】:
我有一个模型 Item,它有三种类型,使用单表继承实现。 Item 有一个树层次结构,它使用 has_many :through 关系表示父级(称为组)和子级(称为 sub_items)。其中一个子类(我们称之为 ItemA)必须始终只有一个父级(但其他子类可以有 0 个或多个父级)。我不知道如何实现可以强制执行树层次结构规则的验证,所以我将它们排除在外。
ItemA 有一个辅助方法parent,用于获取其父项。有时这种方法会引发undefined method 'first' for nil:NilClass。它并不总是发生,但在某些情况下会发生。
情况1
我正在使用 jqGrid 列出所有 ItemAs。我对某些列使用排序功能,包括父列。网格最初会成功加载 ItemAs,表明它们都有应有的父级。但是,当我尝试对父列进行排序时,我会收到错误,好像它们突然消失了一样。当我从排序方法中删除 includes(:groups) 时,它就消失了。我不明白为什么这会有所帮助,但我认为问题已经解决了。直到……
情况2
我正在使用 Rspec、Factory Girl 和 Selenium 测试我的应用程序。在我的一个测试中,我在使用 Factory Girl 创建的 ItemA 实例上调用 parent 方法。它引发了错误。我间接使用parent 方法的测试不会失败。例如,在 ItemA 的索引页面上调用 parent 方法,许多测试访问该页面没有问题。这种情况一直没有得到解决。我的应用不再有任何对 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 方法有时会读取为零,我如何让它始终产生一个值?
编辑:当我更改代码时,我遇到了更多导致此错误的情况。我检查了来源。这是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,它正在工作,但我很想知道我的应用程序中的哪种错误导致了这个问题。
【问题讨论】:
标签: ruby-on-rails ruby rspec jqgrid associations