Adding custom SELECT in ActiveRecord 3
Except for the default SELECT models.*
, ActiveRecord normally adds SELECT clauses, instead of replacing them.
> Project.select(:id).select(:name)=> Project Load (0.5ms) SELECT id, name FROM "projects"
Obviously, this doesn't help when you want "the default SELECT, plus any others I ask for."
You might try a select_star
scope
scope :select_star, -> { select("models.*") }scope :select_star, -> { select(self.arel_table[Arel.star]) } # Arel version, if feeling adventurous
which you could use in places where you want all the columns?
> Model.with_distance(point).select_star=> SELECT ST_DISTANCE(models.point_in_model, ST_GeographyFromText('0,0')) AS distance, models.* FROM ...
I have the same issue with select
behaviour. Let's conclude these bad spots:
- by default, when query is being constructed and we never run
select
before, theArel.star
is used to fetch all columns. - Some times we don't want ActiveRecord/ARel to add "*", ex. we are building some intermediate query or query for statistics, and that star just increases a work on our database (and can also affect the ruby callbacks that run on presence of attributes etc).
I think one of solutions (tested on Rails 4.2.4, that also can be easily applied for Rails 3) is to add the following code to your model or ActiveRecord::Base:
app/models/item.rb
...# include "items".* by defaultdefault_scope ->{select(arel_table[Arel.star])}# when we dont want to use all columnsscope :no_columns, ->{except(:select)}...
Now, for example we have the following scope in the app/models/item.rb
...scope :some_business_logic_scope, ->{ # doing some big query joins(...). where(...). select(...) # some virtual attributes # we dont need to run the following line any more # select(self.arel_table[Arel.star])}...
Usage
Item.select(:id) # selects all columnsItem.no_columns.select(:id) # selects only column idItem.no_columns.some_business_logic_scope # selects only required columnsItem.some_business_logic_scope # selects all attributes including those added by some_business_logic_scope