Selected virtual attributes will be now typecasted as usual attributes
#Rails version Supports rails 4.x and rails 5 now! Master is now runs on 5.x, rails_4 branch is for rails 4 support
This gem solves issue in rails: rails/rails#15185 for base_class.
It was impossible to select virtual attributes to object from its relations or any other way when using includes and where ( actually when includes becomes eager_load, i.e. when you add not SOME_CONDITION, but SOME_CONDITION_ON_INCLUDES, http://blog.bigbinary.com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html ).
Example from upper rails issue:
post = Post.includes(:comments).select("posts.*, 1 as testval").where( SOME_CONDITION ).first
post.testval # Undefined method!
This gem solves problem for base class i.e.
post = Post.includes(:comments).select("posts.*, 1 as testval").where( SOME_CONDITION ).first
post.testval # 1
but of course it doesn't include virtual attributes in included relations
post = Post.includes(:comments).select("posts.*, 1 as testval").where( SOME_CONDITION ).first
post.comments.first.testval # Undefined method!
Данный gem решает проблему в рельсах с виртуальными аттрибутами при использовании includes, когда рельсы собирают в запрос в joins с алиасами на все аттрибуты. В настоящий момент в модель не собираются никаким боком виртуальные аттрибуты ( имеется ввиду когда includes ведет себя как eager_load и создает сложный одинарный запрос, подробнее: http://blog.bigbinary.com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html ).
В частности проблема описана здесь: rails/rails#15185
В коде примера по ссылке выше это выглядит так:
post = Post.includes(:comments).select("posts.*, 1 as testval").where( SOME_CONDITION ).first
post.testval # Undefined method!
Данный gem решает эту проблему для базового класса, т.е.:
post = Post.includes(:comments).select("posts.*, 1 as testval").where( SOME_CONDITION ).first
post.testval # 1
Но это не касается, объектов попадающих под инклюд:
post = Post.includes(:comments).select("posts.*, 1 as testval").where( SOME_CONDITION ).first
post.comments.first.testval # Undefined method!
Add this line to your application's Gemfile:
#rails 4
gem 'rails_select_on_includes', '~> 0.4.11'
#rails 5
gem 'rails_select_on_includes', '~> 0.5.7'
And then execute:
$ bundle
Or install it yourself as:
$ gem install rails_select_on_includes
Works out of the box, monkey-patches base-class alias columns, for select attributes, and JoinBase with JoinDependency to proper typecasting.
It not affecting query creation, since query already contains all columns, i.e. to_sql returns same string. Works with selection in all formats:
- 'table_name.column' or 'table_name.column as column_1' will be parsed! distinct on can be used also
- '(subquery with AS) AS column_1 '
- Select with aliased arel function: .select(Comment.arel_table[:id].count.as('comments_count'))
- Select with aliased arel attirubte: .select(Comment.arel_table[:column].as('column_alias'))
Работает из коробки, нежно манки-патча алиасы прямо перед инстанцированием коллекции, а так же не менее нежно JoinBase и JoinDependency :), чтобы полученные аттрибуты были приличных типов, а не только строк, не влияет на создаваемый запрос в БД т.е to_sql не меняется.
Поддерживает select в следующих форматах :
- 'table_name.column' or 'table_name.column as column_1' will be parsed! distinct on can be used also
- '(subquery with AS) AS column_1 '
- Select with aliased arel function: .select(Comment.arel_table[:id].count.as('comments_count'))
- Select with aliased arel attirubte: .select(Comment.arel_table[:column].as('column_alias'))
rake test
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rails_select_on_includes.
The gem is available as open source under the terms of the MIT License.