This is my model:
class Tag < ActiveRecord::Base
# id, name
has_many :taggings
end
class Tagging < ActiveRecord::Base
# id, tag_id, owner_id, target_type, target_id
belongs_to :tag
belongs_to :owner, :class_name => 'User'
belongs_to :target, :polymorphic => true
validates_uniqueness_of :tag_id, :scope => [ :target_id, :target_type, :owner_id ]
end
class Asset < ActiveRecord::Base
# id, owner_id, title, type, etc
belongs_to :owner, :class_name => 'User'
has_many :taggings, :as => :target
has_many :taggers, :through => :taggings, :source => :owner, :uniq => true
has_many :tags, :through => :taggings, :uniq => true
end
class User < ActiveRecord::Base
# id, name, email, etc
has_many :assets, :foreign_key => 'owner_id'
has_many :my_taggings, :class_name => 'Tagging', :foreign_key => 'owner_id'
has_many :my_tags, :through => :my_taggings, :source => :tag, :uniq => true
has_many :taggings, :as => :target
has_many :taggers, :through => :taggings, :source => :owner, :uniq => true
has_many :tags, :through => :taggings, :uniq => true
end
All of the relations are working but I have an additional requirement that I can't find the solution for:
consider this relation in the Asset class
has_many :tags, :through => :taggings, :uniq => true
calling Asset.find( :first ).tags returns an array of Tags as expected but I need for each Tag to contain a count attribute indicating how many times the row would have appeared if :uniq => true was not specified.
eg. more than one User could apply the same Tag to an Asset. I'd like to display the tag name plus the number of users that applied it.
This should do exactly what you want.
has_many :tags_with_count, :source => :tag, :through => :taggings,
:group => "tags.id", :joins => :taggings,
:select = "tags.*, COUNT('taggings.id') AS frequency"
In terms of rows returned :group => :id will return the same set as :uniq => true, but it will also allow you to perform the calculations you want. This statement is more labour intensive than :uniq => true, so I've given it a different name allowing you to choose whether to fetch the unique tags with their grouped counts, or just the list of unique tags.
The above statement will add the frequency attribute to the records returned. Through the magic of method_missing, you can access that with @tag.frequency.
Usage:
@tags = @asset.tags_with_count
@tags.each{|tag| puts [tag.id, tag.name. tag.frequency].join "\t"}
Will print the id, name, and number of occurrences of each tag for @asset.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With