我有一个方便范围includes
相关模型,以加快表格的渲染等:
class Post < ApplicationRecord
...
scope :includes_for_post_row, -> { includes(:reasons).includes(:feedbacks => [:user]) }
工作正常。但是,现在,我想select
一个额外的属性。如果我已经知道我想要的初始属性,我可以这样做(在控制台中):
2.3.3 :005 > Post.select("`posts`.*, 42 AS column_forty_two").last.column_forty_two
Post Load (1.0ms) SELECT `posts`.*, 42 AS column_forty_two FROM `posts` ORDER BY `posts`.`id` DESC LIMIT 1
=> 42
这假设我知道我想要选择posts.*
,然后我会点击我的column_forty_two
列,这一切都有效。
我想在结果中添加column_forty_two
,而不会影响初始选择。例如,这应该有效:
p = Post.select("`posts`.*, 8 as column_eight").includes_for_post_row_with_forty_two
p.last.column_forty_two # => 42
p.last.column_eight # => 8
p.last.some_activerecord_property # => value
应该这样:
p = Post.all.includes_for_post_row_with_forty_two.last
p.last.column_forty_two # => 42
p.last.some_activerecord_property # => value
我如何select
其他列,而不会影响或覆盖.all
或我之前select
默认选择的现有列?
答案 0 :(得分:9)
如果你要深入研究ActiveRecord源代码(Rails经常是必要的任务),you'll see what's going on:
def build_select(arel)
if select_values.any?
arel.project(*arel_columns(select_values.uniq))
else
arel.project(@klass.arel_table[Arel.star])
end
end
select_values
是您提交给select
的所有内容的列表,默认情况下为空数组:
> Model.where(...).select_values
=> []
> Model.where(...).select('a').select_values
=> ["a"]
> Model.where(...).select('a').select('b').select_values
=> ["a", "b"]
当ActiveRecord最终解决构建SELECT子句时,它会使用您传递给select
的内容(if
中的build_select
分支)或者它使用{ {1}} table_name.*
中的else
分支。
在开始添加更多内容之前,您应该能够使用build_select
使用的相同逻辑来确保build_select
具有某些内容,以便您同时执行select_values
和{{通过使用默认if
预填else
来{1}}的分支。您可以将自己的build_select
版本修补到select_values
模块中:
table_name.*
然后说出类似的话:
select
离开&#34;正常&#34>仅ActiveRecord::QueryMethods
行为:
module ActiveRecord
module QueryMethods
def select_append(*fields)
if(!select_values.any?)
fields.unshift(arel_table[Arel.star])
end
select(*fields)
end
end
end
你当然不必修补补丁,但这种事情似乎是合理的。