Module: RocketTag::Taggable::ClassMethods

Defined in:
lib/rocket_tag/taggable.rb

Instance Method Summary collapse

Instance Method Details

#_with_tag_context(context) ⇒ Object



105
106
107
108
109
110
111
# File 'lib/rocket_tag/taggable.rb', line 105

def _with_tag_context context
  if context
    where{taggings.context == my{context} }
  else
    where{ }
  end
end

#attr_taggable(*contexts) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/rocket_tag/taggable.rb', line 204

def attr_taggable *contexts

  if contexts.blank?
    contexts = [:tag]
  end

  rocket_tag.contexts += contexts

  setup_for_rocket_tag

  contexts.each do |context|
    class_eval do

      has_many "#{context}_taggings".to_sym, 
        :source => :taggable,  
        :as => :taggable,
        :conditions => { :context => context }

      has_many "#{context}_tags".to_sym,
        :source => :tag,
        :through => :taggings,
        :conditions => [ "taggings.context = ?", context ]


      validate context do
        if not send(context).kind_of? Enumerable
          errors.add context, :invalid
        end
      end


      # Return an array of RocketTag::Tags for the context
      define_method "#{context}" do
        cache_tags
        read_context(context)
      end


      define_method "#{context}=" do |list|
        list = Manager.parse_tags list

        # Ensure the tags are loaded
        cache_tags
        write_context(context, list)

        (@tag_dirty ||= Set.new) << context


      end
    end
  end
end

#rocket_tagObject



101
102
103
# File 'lib/rocket_tag/taggable.rb', line 101

def rocket_tag
  @rocket_tag ||= RocketTag::Taggable::Manager.new(self)
end

#setup_for_rocket_tagObject



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/rocket_tag/taggable.rb', line 160

def setup_for_rocket_tag
  unless @setup_for_rocket_tag
    @setup_for_rocket_tag = true
    class_eval do
      default_scope do
        preload{taggings}.preload{tags}
      end

      before_save do
        @tag_dirty ||= Set.new

        @tag_dirty.each do |context|
          # Get the current tags for this context
          list = send(context)

          # Destroy all taggings
          destroy_tags_for_context context

          # Find existing tags
          exisiting_tags = Tag.where{name.in(my{list})}
          exisiting_tag_names = exisiting_tags.map &:name

          # Find missing tags
          tags_names_to_create = list - exisiting_tag_names 

          # Create missing tags
          created_tags = tags_names_to_create.map do |tag_name|
            Tag.create :name => tag_name
          end

          # Recreate taggings
          tags_to_assign = exisiting_tags + created_tags

          tags_to_assign.each do |tag|
            tagging = Tagging.new :tag => tag, :taggable => self, :context => context, :tagger => nil
            self.taggings << tagging
          end
        end
        @tag_dirty = Set.new
      end
    end
  end
end

#tagged_with(tags_list, options = {}) ⇒ Object

Generates a query that provides the matches along with an extra column :tags_count.



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/rocket_tag/taggable.rb', line 127

def tagged_with tags_list, options = {}
  on = options.delete :on

  inner = select{count(~id).as(tags_count)}
      .select("#{self.table_name}.*").
      joins{tags}.
      where{tags.name.in(my{tags_list})}.
      _with_tag_context(on).
      group{~id}

  # Wrap the inner query with an outer query to shield
  # the group and aggregate clauses from downstream
  # queries
  r = from("(#{inner.to_sql}) #{table_name}")

  if options.delete :all
    r = r.where{tags_count==my{tags_list.length}}
  end

  if min = options.delete(:min)
    r = r.where{tags_count>=my{min}}
  end

  if options.delete :sifter
    squeel do
      id.in(r.select{"id"})
    end
  else
    r.select("*")
  end

end

#tagged_with_sifter(tags_list, options = {}) ⇒ Object

Generates a sifter or a where clause depending on options. The sifter generates a subselect with the body of the clause wrapped up so that it can be used as a condition within another squeel statement.

Query optimization is left up to the SQL engine.



120
121
122
123
# File 'lib/rocket_tag/taggable.rb', line 120

def tagged_with_sifter tags_list, options = {}
  options[:sifter] = true
  tagged_with tags_list, options
end