2016-12-30 7 views
3

私はなど、includes関連のモデルは、テーブルのレンダリングを高速化することの利便スコープを持っている:Railsのselect()を使用して、選択した属性を追加(上書きしない)しますか?

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 

これは私が、私はちょうど私のcolumn_forty_two列にタック、私はposts.*を選択したい知っていることを前提とし、それすべての作品。

最初の選択に影響を与えずに、結果に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 

をどのように影響するか.allや私自身のことで、デフォルトで選択された既存の列を上書きせずにI select追加列、先にselect

答えて

5

あなたがyou'll see what's going on、(Railsのと、多くの場合、必要なタスク)のActiveRecordソースを掘りに行く場合:

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原因を構築することに周りになったとき、あなたがでselectifブランチに渡されてきたとき、それは使用していますどちらか)、またはtable_name.*build_selectelseブランチ)を使用します。

あなたはbuild_selectはあなたがソートのデフォルトで事前に充填select_valuesによってbuild_selectifelse枝の両方を実行するように、より多くの追加を開始する前にselect_valuesが何かを持っていることを確認するために使用するのと同じロジックを使用することができるはずtable_name.* 。あなたはActiveRecord::QueryMethodsモジュールにselectの独自のバージョンにパッチを適用できます。

module ActiveRecord 
    module QueryMethods 
    def select_append(*fields) 
     if(!select_values.any?) 
     fields.unshift(arel_table[Arel.star]) 
     end 
     select(*fields) 
    end 
    end 
end 

をしてからのようなものを言う:一人で "ノーマル" select振る舞いを残したまま

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

を:

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

もちろんサルのパッチは必要ありませんが、このようなことは妥当と思われます。

関連する問題