ActsAsTaggableOn::Taggable::Core::ClassMethods

Public Instance Methods

adjust_taggings_alias(taggings_alias) click to toggle source
# File lib/acts_as_taggable_on/acts_as_taggable_on/core.rb, line 207
def adjust_taggings_alias(taggings_alias)
  if taggings_alias.size > 75
    taggings_alias = 'taggings_alias_' + Digest::SHA1.hexdigest(taggings_alias)
  end
  taggings_alias
end
grouped_column_names_for(object) click to toggle source

all column names are necessary for PostgreSQL group clause

# File lib/acts_as_taggable_on/acts_as_taggable_on/core.rb, line 64
def grouped_column_names_for(object)
  object.column_names.map { |column| "#{object.table_name}.#{column}" }.join(", ")
end
initialize_acts_as_taggable_on_core() click to toggle source
# File lib/acts_as_taggable_on/acts_as_taggable_on/core.rb, line 17
def initialize_acts_as_taggable_on_core
  include taggable_mixin
  tag_types.map(&:to_s).each do |tags_type|
    tag_type         = tags_type.to_s.singularize
    context_taggings = "#{tag_type}_taggings".to_sym
    context_tags     = tags_type.to_sym
    taggings_order   = (preserve_tag_order? ? "#{ActsAsTaggableOn::Tagging.table_name}.id" : [])

    class_eval do
      # when preserving tag order, include order option so that for a 'tags' context
      # the associations tag_taggings & tags are always returned in created order
      has_many_with_compatibility context_taggings, :as => :taggable,
                                  :dependent => :destroy,
                                  :class_name => "ActsAsTaggableOn::Tagging",
                                  :order => taggings_order,
                                  :conditions => ["#{ActsAsTaggableOn::Tagging.table_name}.context = (?)", tags_type],
                                  :include => :tag

      has_many_with_compatibility context_tags, :through => context_taggings,
                                  :source => :tag,
                                  :class_name => "ActsAsTaggableOn::Tag",
                                  :order => taggings_order

    end

    taggable_mixin.class_eval             def #{tag_type}_list              tag_list_on('#{tags_type}')            end            def #{tag_type}_list=(new_tags)              set_tag_list_on('#{tags_type}', new_tags)            end            def all_#{tags_type}_list              all_tags_list_on('#{tags_type}')            end, __FILE__, __LINE__ + 1
  end
end
is_taggable?() click to toggle source
# File lib/acts_as_taggable_on/acts_as_taggable_on/core.rb, line 203
def is_taggable?
  true
end
taggable_mixin() click to toggle source
# File lib/acts_as_taggable_on/acts_as_taggable_on/core.rb, line 214
def taggable_mixin
  @taggable_mixin ||= Module.new
end
taggable_on(preserve_tag_order, *tag_types) click to toggle source
# File lib/acts_as_taggable_on/acts_as_taggable_on/core.rb, line 58
def taggable_on(preserve_tag_order, *tag_types)
  super(preserve_tag_order, *tag_types)
  initialize_acts_as_taggable_on_core
end
tagged_with(tags, options = {}) click to toggle source

Return a scope of objects that are tagged with the specified tags.

@param tags The tags that we want to query for @param [Hash] options A hash of options to alter you query:

* <tt>:exclude</tt> - if set to true, return objects that are *NOT* tagged with the specified tags
* <tt>:any</tt> - if set to true, return objects that are tagged with *ANY* of the specified tags
* <tt>:match_all</tt> - if set to true, return objects that are *ONLY* tagged with the specified tags
* <tt>:owned_by</tt> - return objects that are *ONLY* owned by the owner

Example:

User.tagged_with("awesome", "cool")                     # Users that are tagged with awesome and cool
User.tagged_with("awesome", "cool", :exclude => true)   # Users that are not tagged with awesome or cool
User.tagged_with("awesome", "cool", :any => true)       # Users that are tagged with awesome or cool
User.tagged_with("awesome", "cool", :match_all => true) # Users that are tagged with just awesome and cool
User.tagged_with("awesome", "cool", :owned_by => foo ) # Users that are tagged with just awesome and cool by 'foo'
# File lib/acts_as_taggable_on/acts_as_taggable_on/core.rb, line 84
def tagged_with(tags, options = {})
  tag_list = ActsAsTaggableOn::TagList.from(tags)
  empty_result = where("1 = 0")

  return empty_result if tag_list.empty?

  joins = []
  conditions = []
  having = []
  select_clause = []

  context = options.delete(:on)
  owned_by = options.delete(:owned_by)
  alias_base_name = undecorated_table_name.gsub('.','_')
  quote = ActsAsTaggableOn::Tag.using_postgresql? ? '"' : ''

  if options.delete(:exclude)
    if options.delete(:wild)
      tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{like_operator} ? ESCAPE '!'", "%#{escape_like(t)}%"]) }.join(" OR ")
    else
      tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{like_operator} ?", t]) }.join(" OR ")
    end

    conditions << "#{table_name}.#{primary_key} NOT IN (SELECT #{ActsAsTaggableOn::Tagging.table_name}.taggable_id FROM #{ActsAsTaggableOn::Tagging.table_name} JOIN #{ActsAsTaggableOn::Tag.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})"

    if owned_by
      joins <<  "JOIN #{ActsAsTaggableOn::Tagging.table_name}" +
                "  ON #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
                " AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)}" +
                " AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_id = #{owned_by.id}" +
                " AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_type = #{quote_value(owned_by.class.base_class.to_s)}"
    end

  elsif options.delete(:any)
    # get tags, drop out if nothing returned (we need at least one)
    tags = if options.delete(:wild)
      ActsAsTaggableOn::Tag.named_like_any(tag_list)
    else
      ActsAsTaggableOn::Tag.named_any(tag_list)
    end

    return empty_result unless tags.length > 0

    # setup taggings alias so we can chain, ex: items_locations_taggings_awesome_cool_123
    # avoid ambiguous column name
    taggings_context = context ? "_#{context}" : ''

    taggings_alias   = adjust_taggings_alias(
      "#{alias_base_name[0..4]}#{taggings_context[0..6]}_taggings_#{sha_prefix(tags.map(&:name).join('_'))}"
    )

    tagging_join  = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
                    "  ON #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
                    " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}"
    tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context

    # don't need to sanitize sql, map all ids and join with OR logic
    conditions << tags.map { |t| "#{taggings_alias}.tag_id = #{t.id}" }.join(" OR ")
    select_clause = "DISTINCT #{table_name}.*" unless context and tag_types.one?

    if owned_by
        tagging_join << " AND " +
            sanitize_sql([
                "#{taggings_alias}.tagger_id = ? AND #{taggings_alias}.tagger_type = ?",
                owned_by.id,
                owned_by.class.base_class.to_s
            ])
    end

    joins << tagging_join
  else
    tags = ActsAsTaggableOn::Tag.named_any(tag_list)

    return empty_result unless tags.length == tag_list.length

    tags.each do |tag|
      taggings_alias = adjust_taggings_alias("#{alias_base_name[0..11]}_taggings_#{sha_prefix(tag.name)}")
      tagging_join  = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
                      "  ON #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
                      " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}" +
                      " AND #{taggings_alias}.tag_id = #{tag.id}"

      tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context

      if owned_by
          tagging_join << " AND " +
            sanitize_sql([
              "#{taggings_alias}.tagger_id = ? AND #{taggings_alias}.tagger_type = ?",
              owned_by.id,
              owned_by.class.base_class.to_s
            ])
      end

      joins << tagging_join
    end
  end

  taggings_alias, tags_alias = adjust_taggings_alias("#{alias_base_name}_taggings_group"), "#{alias_base_name}_tags_group"

  if options.delete(:match_all)
    joins << "LEFT OUTER JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
             "  ON #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
             " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}"


    group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(self) : "#{table_name}.#{primary_key}"
    group = group_columns
    having = "COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"
  end

  select(select_clause)            .joins(joins.join(" "))            .where(conditions.join(" AND "))            .group(group)            .having(having)            .order(options[:order])            .readonly(false)
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.