[ActiveRecord] Feature proposal: decorating ActiveRecord relations

Previous Topic Next Topic
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

[ActiveRecord] Feature proposal: decorating ActiveRecord relations

Matthieu Libeer
Hello again :)

tldr: Allow adding columns calculated on-the-fly to an ActiveRecord relation, then manipulate those like regular DB columns.

rationale by an example: Suppose we want to report the histogram of the number of likes per post.
We could load all posts and likes in memory and count in Ruby but that would be inefficient.
Instead, we would like to use a column `likes_count` as if it was a regular column stored in DB (counter caching would be another option).
To do that, SQL forces us into adding the column on the fly, and then wrapping the query in a subquery to use it in a group statement.

The SQL we're looking to generate is the following:
SELECT likes_count, COUNT(*)
(SELECT COUNT(*) FROM likes WHERE post_id = posts.id) AS likes_count
FROM posts
) posts
GROUP BY likes_count

It would be great to be able to write just this:
class Post < ApplicationRecord
scope :decorate_with_likes_count, -> do
decorate_with(:likes_count, 'SELECT COUNT(*) FROM likes WHERE post_id = posts.id')


note: The implementation is as simple as the following. It might of course need some changes were it to make it to Core.
It has drastically improved my codebase's readability.
module ActiveRecord
module QueryMethods
    def decorate_with(column_name, sql_definition, subquery_name = nil)
wrap_subquery select('*').select("(#{sql_definition}) AS #{column_name}"), subquery_name

    def wrap_subquery(subquery, name = nil)
model.unscoped.from(subquery, name || table_name)

module Querying
delegate :wrap_subquery, :decorate_with, to: :all

You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/rubyonrails-core.
For more options, visit https://groups.google.com/d/optout.