Short answer
Well, if I understand this correctly, I think I have a solution that just uses the basic ActiveRecord utilities and does not use finder_sql.
May potentially use:
user.tags.all.distinct
Or, conversely, in the user model, change the has_many tags to
has_many :tags, -> {distinct}, through: :articles
You can create a helper method for the user to get this:
def distinct_tags self.tags.all.distinct end
Evidence
From your question, I believe that you have the following scenario:
- A user can have many articles.
- The article belongs to one user.
- Tags can belong to many articles.
- Articles can have many tags.
- You want to get all the individual tags that the user has associated with the articles they created.
With this in mind, I created the following migrations:
class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name, limit: 255 t.timestamps null: false end end end class CreateArticles < ActiveRecord::Migration def change create_table :articles do |t| t.string :name, limit: 255 t.references :user, index: true, null: false t.timestamps null: false end add_foreign_key :articles, :users end end class CreateTags < ActiveRecord::Migration def change create_table :tags do |t| t.string :name, limit: 255 t.timestamps null: false end end end class CreateArticlesTagsJoinTable < ActiveRecord::Migration def change create_table :articles_tags do |t| t.references :article, index: true, null:false t.references :tag, index: true, null: false end add_index :articles_tags, [:tag_id, :article_id], unique: true add_foreign_key :articles_tags, :articles add_foreign_key :articles_tags, :tags end end
And models:
class User < ActiveRecord::Base has_many :articles has_many :tags, through: :articles def distinct_tags self.tags.all.distinct end end class Article < ActiveRecord::Base belongs_to :user has_and_belongs_to_many :tags end class Tag < ActiveRecord::Base has_and_belongs_to_many :articles end
Then run the database with a lot of data:
10.times do |tagcount| Tag.create(name: "tag #{tagcount+1}") end 5.times do |usercount| user = User.create(name: "user #{usercount+1}") 1000.times do |articlecount| article = Article.new(user: user) 5.times do |tagcount| article.tags << Tag.find(tagcount+usercount+1) end article.save end end
Finally, in the rails console:
user = User.find(3) user.distinct_tags
leads to the following result:
Tag Load (0.4ms) SELECT DISTINCT `tags`.* FROM `tags` INNER JOIN `articles_tags` ON `tags`.`id` = `articles_tags`.`tag_id` INNER JOIN `articles` ON `articles_tags`.`article_id` = `articles`.`id` WHERE `articles`.`user_id` = 3 =>