ruby-on-rails - 模型实例方法第一次运行返回错误结果,随后返回正确结果
问题描述
我有三个模型,与 has_many 相关:通过关联:
class Account < ApplicationRecord
has_many :account_owners
has_many :employees, through: account_owners
def is_owned_or_belongs_to_team_of_employees(employee)
employee.team.any? { |m| employees.include?(m) }
end
end
class AccountOwner < ApplicationRecord
belongs_to :account
belongs_to :employee
end
class Employee < ApplicationRecord
has_many :account_owners
has_many :accounts, through: :account_owners
def team
self.class.where(
'id IN (?)',
self. class.find_by_sql(['WITH RECURSIVE search_tree(id, path) AS (
SELECT id, ARRAY[id]
FROM employees
WHERE id = ?
UNION ALL
SELECT employees.id, path || employees.id
FROM search_tree
JOIN employees ON employees.manager_id = search_tree.id
WHERE NOT employees.id = ANY(path)
)
SELECT id FROM search_tree ORDER BY path',
self.id])
).order(:id)
end
end
我正在开发环境中的 Rails 控制台中手动测试该方法(使用我首先加载到数据库中的一些固定装置)Account#is_owned_or_belongs_to_team_of_employees
。
当我在控制台中运行该方法时,会发生以下情况:
> a = Account.first
=> #<Account id: 534788375, name: "Sales Rep 1 (elena)-owned account", code: "EEE", created_at: "2018-07-15 09:41:55", updated_at: "2018-07-15 09:41:55">
> e = Employee.find_by(first_name: 'Elena')
=> #<Employee id: 701979064, first_name: "Elena", last_name: "López", manager_id: 1069403509, created_at: "2018-07-15 09:41:55", updated_at: "2018-07-15 09:41:55", mobile: nil, work: nil>
> e.team
=> #<ActiveRecord::Relation [#<Employee id: 701979064, first_name: "Elena", last_name: "López", manager_id: 1069403509, created_at: "2018-07-15 09:41:55", updated_at: "2018-07-15 09:41:55", mobile: nil, work: nil>]>
> a.is_owned_or_belongs_to_team_of e
=> nil
> a.is_owned_or_belongs_to_team_of e
=> true
如您所见,该方法nil
第一次返回true
(错误!),随后返回(正确!)。
令人惊奇的是,如果我定义这样的方法,我可以纠正问题:
def is_owned_or_belongs_to_team_of employee
puts "employees are #{employees.inspect}"
employee.team.any? { |m| employees.include?(m) }
end
现在执行是正确的,并且该方法始终返回相同的结果(true
在我的示例中):
> a = Account.first
=> #<Account id: 534788375, name: "Sales Rep 1 (elena)-owned account", code: "EEE", created_at: "2018-07-15 09:41:55", updated_at: "2018-07-15 09:41:55">
> e = Employee.find_by(first_name: 'Elena')
=> #<Employee id: 701979064, first_name: "Elena", last_name: "López", manager_id: 1069403509, created_at: "2018-07-15 09:41:55", updated_at: "2018-07-15 09:41:55", mobile: nil, work: nil>
> e.team
=> #<ActiveRecord::Relation [#<Employee id: 701979064, first_name: "Elena", last_name: "López", manager_id: 1069403509, created_at: "2018-07-15 09:41:55", updated_at: "2018-07-15 09:41:55", mobile: nil, work: nil>]>
> a.is_owned_or_belongs_to_team_of e
=> true
> a.is_owned_or_belongs_to_team_of e
=> true
如果我删除该puts
语句,我们将返回到第一个问题:该方法返回nil
第一次,然后返回true
以下时间。
而且,令人惊讶的是,如果我保留该puts
声明但删除inspect
(也就是说,我只是这样做,puts "employees are #{employees}"
我们也回到第一方:nil
第一次,以及true
以下时间。
任何想法?这里发生了什么?
顺便说一句,我正在运行 Ruby 2.5.1 和 Rails 5.2.0。
解决方案
我很高兴我偶然发现了这只独角兽的虫子!
在调试了几个小时后,我发现了以下内容:
any?
在Rails 5.2 版本中有新的变化应该委托给Enumerable
令人惊讶的是,如果你在实现中放置一个 binding.pry
any?
并调用super
它,即使是第一次也会返回 true,然后方法返回nil
。~/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.2.0/lib/active_record/relation.rb @ line 228 ActiveRecord::Relation#any?:
如果你添加到
employee.team
.to_a
一切工作一致。- 如果你把
any? { |_| true }
它返回true。 - 如果您检查块内的值,
include?
它会返回 true 但any?
仍会返回nil
!!! - 如果您避免解决
has_may through
关联(通过在块之前调用.to_a
),甚至在any?
块内使用不同的关联,一切都会按预期工作。 - 使用任何其他 ruby 版本可以解决问题。
概括
该问题是在开始包含时在 ruby2.5.1
rails中引入的。它在尝试解决其块中的关联时发生。v5.2.0
ActiveRecord::Relation
Enumerable
%w(none? any? one? many?)
has many through
推荐阅读
- javascript - 图像尺寸问题,宽度和高度不起作用
- android - Android Automotive types.hal 更改未自动生成
- java - EWS Java API 2.0 - 找不到自动发现服务
- python - 在 List Python 中查找位于特定字符串之间的字符串
- c# - 如何在 .NET Core Kestrel 中禁用 HTTP URL 方向
- user-interface - 在 Wxpython 中拖放图像
- reactjs - 阅读布局时,`useLayoutEffect` 是否优于`useEffect`?
- unity3d - 在由多个对撞机组成的飞机上修复鬼碰撞?
- gemfire - GemFire OQL 查询 - 如何在 WHERE 子句中使用 SELECT 语句的计数?
- python - 我如何计算python中的成员我需要完整的代码