Rails 5.2中为何无法直接传行对象数组给.excluding/.where.not方法
ActiveRecord查询传参问题说明
问题场景
学习ActiveRecord完成RSpec测试练习时,发现将代码修改为results = Row.where.not(id: rows_not_included)即可通过测试,但存在以下疑问:
- 为什么不能直接将存储行对象的变量传给
.excluding方法,无需显式引用列名就得到预期结果? - 是对「行对象」的理解有误,还是存在未掌握的知识点?
- 为什么必须引用具体列名才能让参数按预期被解析?
- 为什么RSpec的expect断言中可以识别指向表中行的实例变量数组,但在作为ActiveRecord查询参数传入时却无法识别?
当前运行环境:Rails 5.2.4
测试代码与报错信息
核心测试代码
@row_1 = Row.create(:blah, :blah_blah) @row_2 = Row.create(:blah, :blah_blah) @row_3 = Row.create(:blah, :blah_blah) @row_4 = Row.create(:blah, :blah_blah) rows_not_included = [@row_1, @row_3] expected_result = [@row_2, @row_4] results = Row.excluding(rows_not_included) # 注:Row.where.not(rows_not_included) 会产生同类报错 expect(results).to eq(expected_result)
调用.where.not报错输出
[1] pry(#<RSpec::ExampleGroups::ActiveRecordObstacleCourseWeek2>)> Item.where.not(items_not_included) NoMethodError: undefined method `include?' for #<Item:0x00007fa61caa1e90> from /Users/brennastuart/.rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/activemodel-5.2.8/lib/active_model/attribute_methods.rb:430:in `method_missing'
调用.excluding报错输出
[4] pry(#<RSpec::ExampleGroups::ActiveRecord>)> Item.excluding(items_not_included) NoMethodError: undefined method `excluding' for #<Class:0x00007fcab2853ea8> from /Users/brennas/.rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/activerecord-5.2.8/lib/active_record/dynamic_matchers.rb:22:in `method_missing'
原因解析
.excluding(别名.without)是Rails 6.0才新增的查询方法,5.2.4版本未实现该方法,触发NoMethodError是版本不兼容导致,和传参逻辑无关。- 直接向
.where.not传入ActiveRecord对象数组报错,由查询方法的参数解析规则导致:.where正向查询时支持直接传入ActiveRecord对象作为条件,框架会自动提取对象主键值生成匹配条件,但这个自动提取逻辑不会透传到.not链式调用中。直接给.where.not传对象数组时,框架会将其作为普通条件哈希解析,不会主动提取对象主键,因此抛出方法不存在的错误。- RSpec的
eq匹配器是纯Ruby层面的值对比,仅校验两个数组的元素是否完全一致,和ActiveRecord的查询参数解析逻辑完全独立,不存在识别规则不一致的矛盾。
- 写法
Row.where.not(id: rows_not_included)能通过测试,是因为显式指定了匹配列为主键id,此时框架会自动对传入的ActiveRecord对象数组做类型转换,提取每个对象的id值,最终生成WHERE id NOT IN (...)的正确SQL语句。
补充:Rails 6+版本的
excluding方法本质是语法糖,底层实现就是自动封装了where.not(primary_key => 记录数组)的逻辑,没有特殊的对象识别黑魔法。
内容的提问来源于stack exchange,提问作者Brenna S
相关产品推荐
相关产品推荐

