我有一个模型,Item,有三种类型,使用Single Table Inheritance实现。 Item具有树层次结构,使用has_many:through关系表示父项(称为组)和子项(称为sub_items)。其中一个子类(我们称之为ItemA)必须始终只有一个父类(但其他子类可以有0个或更多个父类)。我无法弄清楚如何实施强制执行树层次结构规则的验证,所以我把它们排除了。
ItemA有一个辅助方法parent
来获取其父级。有时这种方法会引发undefined method 'first' for nil:NilClass
。它并不总是发生,但在某些情况下确实如此。
我正在使用jqGrid列出所有ItemAs。我对某些列使用排序功能,包括父列。网格最初会成功加载ItemAs,表明他们都有父母应该这样做。但是,当我尝试对父列进行排序时,我会得到错误,好像它们突然消失了一样。当我从排序方法中删除includes(:groups)
时,它就消失了。我不明白为什么会有所帮助,但我认为问题已经解决了。直到...
我正在使用Rspec,Factory Girl和Selenium测试我的应用程序。在我的一个测试中,我在使用Factory Girl创建的ItemA实例上调用parent
方法。它引发了错误。我使用parent
方法的测试间接不会失败。例如,在ItemA的索引页面上调用parent
方法,并且许多测试都会毫无问题地访问该页面。这种情况尚未解决。我的应用程序不再对includes
进行任何调用,因此这次不是其中的一部分。
意达
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
,这是有效的,但我很想知道我的应用中出现了什么类型的错误导致了这个问题。
答案 0 :(得分:0)
事实证明,尽管调用reload,Rails仍然使用查询的缓存版本。 here描述了同样的问题。这解决了它:
class ItemA < Item
def parent
ActiveRecord::Base.uncached { groups.take }
end
end