2016-12-30 44 views
3

我有一个方便的范围是includes相关的模型,以加快表的渲染等:使用Rails的选择中选择()中加入(未覆盖)属性?

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

回答

5

如果你去通过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)或它使用table_name.*build_select中的else分支)。

您应该能够使用相同的逻辑build_select用来确保select_values有东西,你开始添加更多让您排序的执行都因build_selectifelse分支机构预填充select_values使用默认table_name.*前。你可以修补自己的select版本到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 

,然后说这样的话:

> Post.select_append('6 as column_six').to_sql 
=> "select `posts`.*, 6 as column_six from ..." 

,同时保留 “正常” select行为:

> Post.select('11 as column_eleven').to_sql 
=> "select 11 as column_eleven from ..." 

您不必当然猴子补丁,但它对于这样的事情似乎是合理的。