ActsAsTaggableOn Error - #tagged_with no results
ActsAsTaggableOn is a popular Ruby on Rails library to effortlessly introduce tagging to ActiveRecord models. It is one of the most common libraries I have used over the years including in this blog. I encountered what seem to be an issue with ActsAsTaggable #tagged_with
method not properly selecting the tagged resource class.
Background
A few months back I updated my blog. I wanted to add tutorials and product reviews. I decided to go STI (single-table inheritance). I ended up with Posts::Blog
, Posts::Tutorial
and Posts::ProductReview
. But the tagged_with
method wasn't returning any posts and I decide to inspect the SQL.
Posts::Blog.tagged_with "Rails 5" # => []
Posts::Blog.tagged_with("Rails 5").to_sql
# Note that the SQL is not of the exact query
"SELECT \"posts\".* FROM \"posts\" INNER JOIN \"taggings\" \"post_taggings_86357b1\" ON \"post_taggings_86357b1\".\"taggable_id\" = \"posts\".\"id\" AND \"post_taggings_86357b1\".\"taggable_type\" = 'Post' AND \"post_taggings_86357b1\".\"tag_id\" IN (SELECT \"tags\".\"id\" FROM \"tags\" WHERE LOWER(\"tags\".\"name\") ILIKE 'rails 5' ESCAPE '!') WHERE \"posts\".\"type\" = 'Posts::Blog' AND \"posts\".\"aasm_state\" = 'published' AND \"posts\".\"child_post\" = FALSE AND \"posts\".\"aasm_state\" = 'published' ORDER BY \"posts\".\"published_at\" DESC LIMIT 30 OFFSET 0"
Notice that the taggable_type: 'Post'
and not Posts::Blog
. I looked for a solution and looks like the library in the past has had a similar issue. But I couldn't find a solution for the tagged_with
method.
So I updated the query as follows:
# app/concepts/posts/operations/marketing/index.rb
module Post::Operation::Marketing
class Index < Trailblazer::Operation
# ...
def filter(ctx, params:, **)
model = ctx[:model]
posts = resolve_policy(ctx).parent_posts
posts = posts.includes(%i[featured_image])
posts = posts.search(ctx[:model].query) if ctx[:model].query.present?
posts = posts.published unless params[:all] == 'true'
posts = posts.where(category_id: params[:category_id]) if params[:category_id]
# Basically to join `tag` through `taggings` and query the tag name.
posts = posts.joins(taggings: :tag).where(tag: { name: params[:tag] }) if params[:tag]
posts = posts.order(published_at: :desc)
ctx[:posts] = posts
end
# ...
end
Once the query was updated the tag filter is operational. I wish there was a way to fix it, but for now, this will do.
About the Author
Ziyan Junaideen -
Ziyan is an expert Ruby on Rails web developer with 8 years of experience specializing in SaaS applications. He spends his free time he writes blogs, drawing on his iPad, shoots photos.