Search code examples
activerecordruby-on-rails-5arelact-as-taggable-on

Project a single column of a table filtered by tag from act as taggale


Currently the only way I know to sub select in rails is with arel, for exmaple -

sub = x.where(y:'x').project(:id)
select = a.where(a[:x_id].in(sub))

question is, if x is using the acts as taggable on gem and need to filtered by a specific tag, use with tagged_with method.

How can I still achive same database efficiency, it looks like the tagged with method override the projection.

thanks,


Solution

  • You don't need Arel to build sub selects in Rails:

    sub = X.where(y: 'x')
    select = A.where(x_id: sub)
    

    generates the following SQL, assuming A's table name is as and X's is xs:

    SELECT "as".* FROM "as" WHERE "as"."x_id" IN (SELECT "xs"."id" FROM "xs" WHERE "xs"."y" = 'x')
    

    Testing with tagged_with worked: A.where(x_id: X.tagged_with('my_tag')) generates the expected SQL, at least for Rails 5.1, version on which I've tested.

    Edit

    You can specify the column used inside the subselect if needed. If you don't specify it, the primary key column is the default:

    sub = X.where(y: 'x').select(:x_y_id)
    select = A.where(x_id: sub)
    

    will generate the following SQL:

    SELECT "as".* FROM "as" WHERE "as"."x_id" IN (SELECT "xs"."x_y_id" FROM "xs" WHERE "xs"."y" = 'x')