Module: HasMachineTags::Finder

Defined in:
lib/has_machine_tags/finder.rb

Instance Method Summary collapse

Instance Method Details

#condition_from_tags(tags) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/has_machine_tags/finder.rb', line 34

def condition_from_tags(tags)
  tag_sql = tags.map {|t|
    if match = Tag.match_wildcard_machine_tag(t)
      string = match.map {|k,v|
        sanitize_sql(["#{tags_alias}.#{k} = ?", v])
      }.join(" AND ")
      "(#{string})"
    else
      sanitize_sql(["#{tags_alias}.name = ?", t])
    end
  }.join(" OR ")
end

#default_find_options_for_tagged_withObject



55
56
57
58
59
60
61
# File 'lib/has_machine_tags/finder.rb', line 55

def default_find_options_for_tagged_with
  { :select => "DISTINCT #{table_name}.*",
    :joins => "LEFT OUTER JOIN #{Tagging.table_name} #{taggings_alias} ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key} AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)} " +
              "LEFT OUTER JOIN #{Tag.table_name} #{tags_alias} ON #{tags_alias}.id = #{taggings_alias}.tag_id",
    # :group      => group
  }
end

#find_options_for_tagged_with(tags, options = {}) ⇒ Object

:stopdoc:



25
26
27
28
29
30
31
32
# File 'lib/has_machine_tags/finder.rb', line 25

def find_options_for_tagged_with(tags, options = {})
  tags = TagList.new(tags)
  return {} if tags.empty?
  conditions = []
  conditions << sanitize_sql(options.delete(:conditions)) if options[:conditions]
  conditions << condition_from_tags(tags)
  default_find_options_for_tagged_with.update(:conditions=>conditions.join(" AND ")).update(options)
end

#find_tagged_with(*args) ⇒ Object

Takes a string of delimited tags or an array of tags. Note that each tag is interpreted as a possible wildcard machine tag.

Options:

:conditions - A piece of SQL conditions to add to the query.

Example:

Url.tagged_with 'something' # => fetches urls tagged with 'something'
Url.tagged_with 'gem:'      # => fetches urls tagged with tags that have namespace gem
Url.tagged_with 'gem, something' # =>  fetches urls that are tagged with 'something'
  or 'gem'

Note: This method really only needs to be used with Rails < 2.1 . 
Rails 2.1 and greater should use tagged_with(), which acts the same but with
the benefits of named_scope.


19
20
21
22
# File 'lib/has_machine_tags/finder.rb', line 19

def find_tagged_with(*args)
  options = find_options_for_tagged_with(*args)
  options.blank? ? [] : find(:all,options)
end

#old_find_options_for_find_tagged_with(tags, options = {}) ⇒ Object

TODO: add back in options as needed. Options:

:exclude - Find models that are not tagged with the given tags.
:match_all - Find models that match all of the given tags, not just one (doesn't work with machine tags yet).


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/has_machine_tags/finder.rb', line 67

def old_find_options_for_find_tagged_with(tags, options = {}) #:nodoc:
  # options.reverse_merge!(:match_all=>true)
  machine_tag_used = false
  if options.delete(:exclude)
    tags_conditions = tags.map { |t| sanitize_sql(["#{Tag.table_name}.name = ?", t]) }.join(" OR ")
    conditions << sanitize_sql(["#{table_name}.id NOT IN (SELECT #{Tagging.table_name}.taggable_id FROM #{Tagging.table_name} LEFT OUTER JOIN #{Tag.table_name} ON #{Tagging.table_name}.tag_id = #{Tag.table_name}.id WHERE (#{tags_conditions}) AND #{Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})", tags])
  else
    conditions << condition_from_tags(tags)
    
    if options.delete(:match_all)
      group = "#{taggings_alias}.taggable_id HAVING COUNT(#{taggings_alias}.taggable_id) = "
      if machine_tag_used
        #Since a machine tag matches multiple tags per given tag, we need to dynamically calculate the count
        #TODO: this select needs to return differently for each taggable_id
        group += "(SELECT count(id) FROM #{Tag.table_name} #{tags_alias} WHERE #{tag_sql})"
      else
        group += tags.size.to_s
      end
    end
  end
  default_find_options_for_tagged_with.update(:conditions=>conditions.join(" AND ")).update(options)
end

#taggings_aliasObject



47
48
49
# File 'lib/has_machine_tags/finder.rb', line 47

def taggings_alias
  "#{table_name}_taggings"
end

#tags_aliasObject



51
52
53
# File 'lib/has_machine_tags/finder.rb', line 51

def tags_alias
  "#{table_name}_tags"
end