Rails 5 Active Record左外连接未显示关联属性问题求助
我来帮你拆解下这个问题:你用Rails的left_joins查询时明明选了product_features.pfeature_id,但返回的Product实例就是不显示这个字段,可原生SQL却能正常输出——这其实是Active Record的特性导致的,不是你查询写错了!
为什么会这样?
Active Record的实例默认只会展示对应模型表中定义的字段,pfeature_id是product_features表的字段,不属于products表,所以控制台打印实例时(调用的是inspect方法),不会把这个额外查询的字段展示出来。但实际上,这个字段的数据已经被加载到实例的attributes哈希里了,只是没显式显示而已。
另外,先提个小细节:你的Product模型里has_many :product_feature应该改成复数has_many :product_features,Rails的关联名称要和表名(复数)对应,不然可能会触发关联查询的异常哦。
怎么解决?
下面给你几个实用的方案:
1. 直接获取隐藏的字段值
虽然控制台不显示,但你可以直接从实例的属性哈希里取出pfeature_id:
b = Product.left_joins(:product_features).select("products.id, products.name, product_features.pfeature_id").where("products.id>8").take(2) # 方法1:通过attributes哈希访问 b.first.attributes["pfeature_id"] # 方法2:更简洁的写法 b.first[:pfeature_id]
执行后你就能看到对应的值了,比如第一个实例的nil,第二个的8。
2. 让控制台默认显示额外字段
如果你希望每次打印实例时都能看到pfeature_id,可以重写模型的inspect方法,自定义显示内容:
class Product < ApplicationRecord has_many :product_features has_many :pfeatures, through: :product_features def inspect # 把所有属性(包括额外查询的字段)都拼起来显示 attr_str = attributes.map { |k, v| "#{k}: #{v.inspect}" }.join(', ') "#<Product #{attr_str}>" end end
改完之后再执行查询,控制台输出的Product实例就会包含pfeature_id了。
3. 用虚拟属性映射字段
你也可以在模型里定义一个虚拟属性,让查询到的pfeature_id直接绑定到这个属性上:
class Product < ApplicationRecord has_many :product_features has_many :pfeatures, through: :product_features # 定义虚拟属性 attr_accessor :pfeature_id # 封装查询方法 def self.with_pfeature_id left_joins(:product_features) .select("products.*, product_features.pfeature_id") end end
之后查询时就可以直接像访问模型字段一样用b.first.pfeature_id获取值了。
验证一下
你可以在控制台里跑这段代码确认数据确实存在:
b = Product.left_joins(:product_features).select("products.id, products.name, product_features.pfeature_id").where("products.id>8").take(2) # 打印所有属性 puts b.first.attributes
输出会显示类似{"id"=>9, "name"=>"redKnife", "pfeature_id"=>nil}的内容,说明数据其实已经被加载到实例里了。
内容的提问来源于stack exchange,提问作者David Gleba

