2016-12-30 1 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 

Это предполагает, что я знаю, что я хочу, чтобы выбрать 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 наконец-то вокруг, чтобы строить ВЫБЕРИТЕ причину, он либо использует, когда вы перешли на selectif отрасли в build_select) или использует table_name.* (филиал else в build_select).

Вы должны быть в состоянии использовать ту же логику, что build_select использует для того, чтобы select_values есть кое-что, прежде чем начать добавлять более, что вы как бы выполнить оба if и else ветви build_select по предварительно заполнив 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 ..." 

Конечно, у вас нет обезьянника, но это кажется разумным для такого рода вещей.

Смежные вопросы