mirror of
https://github.com/TracksApp/tracks.git
synced 2026-01-29 12:16:11 +01:00
Support for tagging of actions!
Made a start on tagging support. You can add tags via the action forms (just single word tags, separated by a space so far), update tags via the edit form (same limitations), and also search for all actions with a particular tag: /todo/tag/[tag_name] Tests for tagging are a bit rudimentary at the moment, and you can't as yet use tags consisting of multiple words, or search for conjunctions of tags (e.g. foo+bar), but I'm hoping to add these. Also no validation, so don't try anything funny! I'm also planning on letting the user create custom links to /todo/tag pages, so that you can use a tag for inbox, someday/maybe, today, a meta-project, priority, or whatever you like. git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@400 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
parent
3fb15f81a5
commit
36fcfe5c59
19 changed files with 317 additions and 20 deletions
|
|
@ -33,6 +33,7 @@ class TodoController < ApplicationController
|
|||
def create
|
||||
@item = @user.todos.build
|
||||
p = params['request'] || params
|
||||
# @item.tag_with(params[:tag_list])
|
||||
@item.attributes = p['todo']
|
||||
|
||||
if p['todo']['project_id'].blank? && !p['project_name'].blank? && p['project_name'] != 'None'
|
||||
|
|
@ -69,6 +70,7 @@ class TodoController < ApplicationController
|
|||
@item.show_from = parse_date_per_user_prefs(p['todo']['show_from'])
|
||||
end
|
||||
|
||||
@item.tag_with(params[:tag_list], @user)
|
||||
@saved = @item.save
|
||||
|
||||
respond_to do |wants|
|
||||
|
|
@ -124,6 +126,7 @@ class TodoController < ApplicationController
|
|||
|
||||
def update
|
||||
@item = check_user_return_item
|
||||
@item.tag_with(params[:tag_list], @user)
|
||||
@original_item_context_id = @item.context_id
|
||||
@original_item_project_id = @item.project_id
|
||||
@original_item_was_deferred = @item.deferred?
|
||||
|
|
@ -159,6 +162,8 @@ class TodoController < ApplicationController
|
|||
params['item']['show_from'] = parse_date_per_user_prefs(params['item']['show_from'])
|
||||
end
|
||||
|
||||
|
||||
|
||||
@saved = @item.update_attributes params["item"]
|
||||
@context_changed = @original_item_context_id != @item.context_id
|
||||
@item_was_activated_from_deferred_state = @original_item_was_deferred && @item.active?
|
||||
|
|
@ -234,6 +239,19 @@ class TodoController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# /todo/tag/[tag_name] shows all the actions tagged with tag_name
|
||||
#
|
||||
def tag
|
||||
@tag = tag_name = params[:id]
|
||||
if Tag.find_by_name(tag_name)
|
||||
@todos = Todo.find_tagged_with(tag_name, @user)
|
||||
else
|
||||
@todos = []
|
||||
end
|
||||
|
||||
@count = @todos.size unless @todos.empty?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_user_return_item
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ class Todo < ActiveRecord::Base
|
|||
belongs_to :project
|
||||
belongs_to :user
|
||||
|
||||
acts_as_taggable
|
||||
acts_as_state_machine :initial => :active, :column => 'state'
|
||||
|
||||
state :active, :enter => Proc.new { |t| t[:show_from] = nil }
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
has_many :notes, :order => "created_at DESC", :dependent => :delete_all
|
||||
has_one :preference, :dependent => :destroy
|
||||
has_many :taggings
|
||||
has_many :tags, :through => :taggings, :select => "DISTINCT tags.*"
|
||||
|
||||
attr_protected :is_admin
|
||||
|
||||
|
|
|
|||
|
|
@ -43,14 +43,17 @@ Event.observe($('todo_project_name'), "focus", projectAutoCompleter.activate.bin
|
|||
Event.observe($('todo_project_name'), "click", projectAutoCompleter.activate.bind(projectAutoCompleter));
|
||||
</script>
|
||||
|
||||
<label for="tag_list">Tags</label>
|
||||
<%= text_field_tag "tag_list", nil, :size => 40, :tabindex => 5 %>
|
||||
|
||||
<label for="todo_due">Due</label>
|
||||
<%= text_field("todo", "due", "size" => 10, "class" => "Date", "onfocus" => "Calendar.setup", "tabindex" => 5, "autocomplete" => "off") %>
|
||||
<%= text_field("todo", "due", "size" => 10, "class" => "Date", "onfocus" => "Calendar.setup", "tabindex" => 6, "autocomplete" => "off") %>
|
||||
|
||||
<label for="todo_show_from">Show from</label>
|
||||
<%= text_field("todo", "show_from", "size" => 10, "class" => "Date", "onfocus" => "Calendar.setup", "tabindex" => 6, "autocomplete" => "off") %>
|
||||
<%= text_field("todo", "show_from", "size" => 10, "class" => "Date", "onfocus" => "Calendar.setup", "tabindex" => 7, "autocomplete" => "off") %>
|
||||
|
||||
<%= source_view_tag( @source_view ) %>
|
||||
<div class="submit_box"><input type="submit" value="Add item" tabindex="7" /></div>
|
||||
<div class="submit_box"><input type="submit" value="Add item" tabindex="8" /></div>
|
||||
<% end -%><!--[eoform:todo]-->
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@
|
|||
Event.observe($('<%= dom_id(@item, 'project_name') %>'), "click", editFormProjectAutoCompleter.activate.bind(editFormProjectAutoCompleter));
|
||||
</script>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label"><label for="<%= dom_id(@item, 'tag_list') %>">Tags</label></td>
|
||||
<td><%= text_field_tag "tag_list", @item.tags.collect{|t| t.name}.join(" "), :size => 40 %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label"><label for="<%= dom_id(@item, 'due') %>">Due</td>
|
||||
<td><input name="item[due]" id="<%= dom_id(@item, 'due') %>" type="text" value="<%= format_date(@item.due) %>" tabindex="12" size="10" onfocus="Calendar.setup" autocomplete="off" class="Date" /></td>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,17 @@
|
|||
<% end -%>
|
||||
|
||||
<%= sanitize(item.description) %>
|
||||
|
||||
<%= if item.tags.blank?
|
||||
""
|
||||
else
|
||||
tag_string = ""
|
||||
item.tags.each do |t|
|
||||
tag_string << "<span class=\"tag\">" + link_to(t.name, :action => "tag", :id => t.name) + "</span>"
|
||||
end
|
||||
tag_string
|
||||
end
|
||||
%>
|
||||
|
||||
<% if item.deferred? && item.due -%>
|
||||
(action due on <%= format_date(item.due) %>)
|
||||
|
|
@ -32,6 +43,10 @@
|
|||
<% if (parent_container_type == "context" || parent_container_type == "tickler") && item.project_id -%>
|
||||
<%= item_link_to_project( item ) %>
|
||||
<% end -%>
|
||||
<% if (parent_container_type == "tag") -%>
|
||||
<%= item_link_to_context( item ) %>
|
||||
<%= item_link_to_project( item ) if item.project_id %>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
|
||||
<% if item.notes? -%>
|
||||
|
|
|
|||
22
tracks/app/views/todo/tag.rhtml
Normal file
22
tracks/app/views/todo/tag.rhtml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<div id="display_box">
|
||||
|
||||
<div id="t" class="container context">
|
||||
<h2>
|
||||
All actions tagged with '<%= @tag %>'
|
||||
</h2>
|
||||
<div id="t_items" class="items toggle_target">
|
||||
<div id="t_empty-nd" style="display:<%= @todos.empty? ? 'block' : 'none'%>;">
|
||||
<div class="message"><p>Currently there are no actions tagged with <%= @tag %></p></div>
|
||||
</div>
|
||||
<%= render :partial => "todo/item", :collection => @todos, :locals => { :parent_container_type => "tag" } %>
|
||||
</div><!-- [end:items] -->
|
||||
</div><!-- [end:t-->
|
||||
|
||||
|
||||
|
||||
</div><!-- End of display_box -->
|
||||
|
||||
<div id="input_box">
|
||||
<%= render :partial => "shared/add_new_item_form" %>
|
||||
<%= render "sidebar/sidebar" %>
|
||||
</div><!-- End of input box -->
|
||||
23
tracks/db/migrate/024_add_tag_support.rb
Normal file
23
tracks/db/migrate/024_add_tag_support.rb
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
class AddTagSupport < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :taggings do |t|
|
||||
t.column :taggable_id, :integer
|
||||
t.column :tag_id, :integer
|
||||
t.column :taggable_type, :string
|
||||
t.column :user_id, :integer
|
||||
end
|
||||
create_table :tags do |t|
|
||||
t.column :name, :string
|
||||
t.column :created_at, :datetime
|
||||
t.column :updated_at, :datetime
|
||||
end
|
||||
|
||||
add_index :tags, :name
|
||||
add_index :taggings, [:tag_id, :taggable_id, :taggable_type]
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :taggings
|
||||
drop_table :tags
|
||||
end
|
||||
end
|
||||
|
|
@ -2,13 +2,13 @@
|
|||
# migrations feature of ActiveRecord to incrementally modify your database, and
|
||||
# then regenerate this schema definition.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 23) do
|
||||
ActiveRecord::Schema.define(:version => 24) do
|
||||
|
||||
create_table "contexts", :force => true do |t|
|
||||
t.column "name", :string, :default => "", :null => false
|
||||
t.column "hide", :integer, :limit => 4, :default => 0, :null => false
|
||||
t.column "position", :integer, :default => 0, :null => false
|
||||
t.column "user_id", :integer, :default => 0, :null => false
|
||||
t.column "name", :string, :default => "", :null => false
|
||||
t.column "position", :integer, :default => 0, :null => false
|
||||
t.column "hide", :boolean, :default => false
|
||||
t.column "user_id", :integer, :default => 1
|
||||
end
|
||||
|
||||
add_index "contexts", ["user_id"], :name => "index_contexts_on_user_id"
|
||||
|
|
@ -61,7 +61,7 @@ ActiveRecord::Schema.define(:version => 23) do
|
|||
create_table "projects", :force => true do |t|
|
||||
t.column "name", :string, :default => "", :null => false
|
||||
t.column "position", :integer, :default => 0, :null => false
|
||||
t.column "user_id", :integer, :default => 0, :null => false
|
||||
t.column "user_id", :integer, :default => 1
|
||||
t.column "description", :text
|
||||
t.column "state", :string, :limit => 20, :default => "active", :null => false
|
||||
end
|
||||
|
|
@ -76,17 +76,34 @@ ActiveRecord::Schema.define(:version => 23) do
|
|||
|
||||
add_index "sessions", ["session_id"], :name => "sessions_session_id_index"
|
||||
|
||||
create_table "taggings", :force => true do |t|
|
||||
t.column "taggable_id", :integer
|
||||
t.column "tag_id", :integer
|
||||
t.column "taggable_type", :string
|
||||
t.column "user_id", :integer
|
||||
end
|
||||
|
||||
add_index "taggings", ["tag_id", "taggable_id", "taggable_type"], :name => "index_taggings_on_tag_id_and_taggable_id_and_taggable_type"
|
||||
|
||||
create_table "tags", :force => true do |t|
|
||||
t.column "name", :string
|
||||
t.column "created_at", :datetime
|
||||
t.column "updated_at", :datetime
|
||||
end
|
||||
|
||||
add_index "tags", ["name"], :name => "index_tags_on_name"
|
||||
|
||||
create_table "todos", :force => true do |t|
|
||||
t.column "context_id", :integer, :default => 0, :null => false
|
||||
t.column "description", :string, :limit => 100, :default => "", :null => false
|
||||
t.column "context_id", :integer, :default => 0, :null => false
|
||||
t.column "project_id", :integer
|
||||
t.column "description", :string, :default => "", :null => false
|
||||
t.column "notes", :text
|
||||
t.column "created_at", :datetime
|
||||
t.column "due", :date
|
||||
t.column "completed_at", :datetime
|
||||
t.column "project_id", :integer
|
||||
t.column "user_id", :integer, :default => 0, :null => false
|
||||
t.column "user_id", :integer, :default => 1
|
||||
t.column "show_from", :date
|
||||
t.column "state", :string, :limit => 20, :default => "immediate", :null => false
|
||||
t.column "state", :string, :limit => 20, :default => "immediate", :null => false
|
||||
end
|
||||
|
||||
add_index "todos", ["user_id", "state"], :name => "index_todos_on_user_id_and_state"
|
||||
|
|
@ -96,10 +113,10 @@ ActiveRecord::Schema.define(:version => 23) do
|
|||
add_index "todos", ["user_id", "context_id"], :name => "index_todos_on_user_id_and_context_id"
|
||||
|
||||
create_table "users", :force => true do |t|
|
||||
t.column "login", :string, :limit => 80
|
||||
t.column "password", :string, :limit => 40
|
||||
t.column "login", :string, :limit => 80, :default => "", :null => false
|
||||
t.column "password", :string, :limit => 40, :default => "", :null => false
|
||||
t.column "word", :string
|
||||
t.column "is_admin", :integer, :limit => 4, :default => 0, :null => false
|
||||
t.column "is_admin", :boolean, :default => false, :null => false
|
||||
t.column "first_name", :string
|
||||
t.column "last_name", :string
|
||||
t.column "auth_type", :string, :default => "database", :null => false
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ div#input_box {
|
|||
}
|
||||
|
||||
div.item-container {
|
||||
padding: 2px;
|
||||
padding: 3px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
|
@ -317,6 +317,28 @@ div#project_status > div {
|
|||
a.footer_link {color: #cc3334; font-style: normal;}
|
||||
a.footer_link:hover {color: #fff; background-color: #cc3334 !important;}
|
||||
|
||||
/* Tag formatting */
|
||||
|
||||
span.tag {
|
||||
font-size: 0.8em;
|
||||
background-color: #CCE7FF;
|
||||
color: #000;
|
||||
padding: 1px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
span.tag a,
|
||||
span.tag a:link,
|
||||
span.tag a:active,
|
||||
span.tag a:visited {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
span.tag a:hover {
|
||||
background-color: #99CCFF;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* Flash box styling */
|
||||
|
||||
div#message_holder {
|
||||
|
|
|
|||
22
tracks/test/fixtures/taggings.yml
vendored
Normal file
22
tracks/test/fixtures/taggings.yml
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Todo 1 should be tagged with foo and bar
|
||||
foo_bar1:
|
||||
id: 1
|
||||
tag_id: 1
|
||||
taggable_id: 1 # Call Bill Gates
|
||||
taggable_type: Todo
|
||||
user_id: 1
|
||||
|
||||
foo_bar2:
|
||||
id: 2
|
||||
tag_id: 2
|
||||
taggable_id: 1 # Call Bill Gates
|
||||
taggable_type: Todo
|
||||
user_id: 1
|
||||
|
||||
# Todo 2 should be tagged with foo
|
||||
foo:
|
||||
id: 3
|
||||
tag_id: 1
|
||||
taggable_id: 2 # Call dinosaur exterminator
|
||||
taggable_type: Todo
|
||||
user_id: 1
|
||||
17
tracks/test/fixtures/tags.yml
vendored
Normal file
17
tracks/test/fixtures/tags.yml
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
foo:
|
||||
id: 1
|
||||
name: foo
|
||||
created_at: <%= Time.now.utc.to_s(:db) %>
|
||||
updated_at: <%= Time.now.utc.to_s(:db) %>
|
||||
|
||||
bar:
|
||||
id: 2
|
||||
name: bar
|
||||
created_at: <%= Time.now.utc.to_s(:db) %>
|
||||
updated_at: <%= Time.now.utc.to_s(:db) %>
|
||||
|
||||
baz:
|
||||
id: 3
|
||||
name: baz
|
||||
created_at: <%= Time.now.utc.to_s(:db) %>
|
||||
updated_at: <%= Time.now.utc.to_s(:db) %>
|
||||
|
|
@ -5,7 +5,7 @@ require 'todo_controller'
|
|||
class TodoController; def rescue_action(e) raise e end; end
|
||||
|
||||
class TodoControllerTest < Test::Unit::TestCase
|
||||
fixtures :users, :preferences, :projects, :contexts, :todos
|
||||
fixtures :users, :preferences, :projects, :contexts, :todos, :tags, :taggings
|
||||
|
||||
def setup
|
||||
@controller = TodoController.new
|
||||
|
|
@ -67,7 +67,7 @@ class TodoControllerTest < Test::Unit::TestCase
|
|||
def test_update_item
|
||||
t = Todo.find(1)
|
||||
@request.session['user_id'] = users(:admin_user).id
|
||||
xhr :post, :update, :id => 1, :_source_view => 'todo', "item"=>{"context_id"=>"1", "project_id"=>"2", "id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}
|
||||
xhr :post, :update, :id => 1, :_source_view => 'todo', "item"=>{"context_id"=>"1", "project_id"=>"2", "id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo bar"
|
||||
#assert_rjs :page, "todo_1", :visual_effect, :highlight, :duration => '1'
|
||||
t = Todo.find(1)
|
||||
assert_equal "Call Warren Buffet to find out how much he makes per day", t.description
|
||||
|
|
@ -76,5 +76,14 @@ class TodoControllerTest < Test::Unit::TestCase
|
|||
assert_equal expected, actual, "Expected #{expected.to_s(:db)}, was #{actual.to_s(:db)}"
|
||||
end
|
||||
|
||||
def test_tag
|
||||
@request.session['user_id'] = users(:admin_user).id
|
||||
@user = User.find(@request.session['user_id'])
|
||||
@tagged = Todo.find_tagged_with('foo', @user).size
|
||||
get :tag, :id => 'foo'
|
||||
assert_success
|
||||
assert_equal 2, @tagged
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
|
|||
5
tracks/vendor/plugins/acts_as_taggable/init.rb
vendored
Normal file
5
tracks/vendor/plugins/acts_as_taggable/init.rb
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
require 'acts_as_taggable'
|
||||
ActiveRecord::Base.send(:include, ActiveRecord::Acts::Taggable)
|
||||
|
||||
require File.dirname(__FILE__) + '/lib/tagging'
|
||||
require File.dirname(__FILE__) + '/lib/tag'
|
||||
4
tracks/vendor/plugins/acts_as_taggable/lib/README
vendored
Normal file
4
tracks/vendor/plugins/acts_as_taggable/lib/README
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Acts As Taggable
|
||||
=================
|
||||
|
||||
Allows for tags to be added to multiple classes.
|
||||
59
tracks/vendor/plugins/acts_as_taggable/lib/acts_as_taggable.rb
vendored
Normal file
59
tracks/vendor/plugins/acts_as_taggable/lib/acts_as_taggable.rb
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
module ActiveRecord
|
||||
module Acts #:nodoc:
|
||||
module Taggable #:nodoc:
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def acts_as_taggable(options = {})
|
||||
write_inheritable_attribute(:acts_as_taggable_options, {
|
||||
:taggable_type => ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s,
|
||||
:from => options[:from]
|
||||
})
|
||||
|
||||
class_inheritable_reader :acts_as_taggable_options
|
||||
|
||||
has_many :taggings, :as => :taggable, :dependent => true
|
||||
has_many :tags, :through => :taggings
|
||||
|
||||
include ActiveRecord::Acts::Taggable::InstanceMethods
|
||||
extend ActiveRecord::Acts::Taggable::SingletonMethods
|
||||
end
|
||||
end
|
||||
|
||||
module SingletonMethods
|
||||
def find_tagged_with(list, user)
|
||||
find_by_sql([
|
||||
"SELECT #{table_name}.* FROM #{table_name}, tags, taggings " +
|
||||
"WHERE #{table_name}.#{primary_key} = taggings.taggable_id " +
|
||||
"AND taggings.user_id = ? " +
|
||||
"AND taggings.taggable_type = ? " +
|
||||
"AND taggings.tag_id = tags.id AND tags.name IN (?)",
|
||||
user.id, acts_as_taggable_options[:taggable_type], list
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
def tag_with(list, user)
|
||||
Tag.transaction do
|
||||
taggings.destroy_all
|
||||
|
||||
Tag.parse(list).each do |name|
|
||||
if acts_as_taggable_options[:from]
|
||||
send(acts_as_taggable_options[:from]).tags.find_or_create_by_name(name).on(self, user)
|
||||
else
|
||||
Tag.find_or_create_by_name(name).on(self, user)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def tag_list
|
||||
tags.collect { |tag| tag.name.include?(" ") ? '"' + tag.name + '"' : tag.name }.join(" ")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
40
tracks/vendor/plugins/acts_as_taggable/lib/tag.rb
vendored
Normal file
40
tracks/vendor/plugins/acts_as_taggable/lib/tag.rb
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
class Tag < ActiveRecord::Base
|
||||
has_many :taggings
|
||||
|
||||
def self.parse(list)
|
||||
tag_names = []
|
||||
|
||||
# first, pull out the quoted tags
|
||||
list.gsub!(/\"(.*?)\"\s*/ ) { tag_names << $1; "" }
|
||||
|
||||
# then, replace all commas with a space
|
||||
list.gsub!(/,/, " ")
|
||||
|
||||
# then, get whatever's left
|
||||
tag_names.concat list.split(/\s/)
|
||||
|
||||
# strip whitespace from the names
|
||||
tag_names = tag_names.map { |t| t.strip }
|
||||
|
||||
# delete any blank tag names
|
||||
tag_names = tag_names.delete_if { |t| t.empty? }
|
||||
|
||||
return tag_names
|
||||
end
|
||||
|
||||
def tagged
|
||||
@tagged ||= taggings.collect { |tagging| tagging.taggable }
|
||||
end
|
||||
|
||||
def on(taggable, user)
|
||||
tagging = taggings.create :taggable => taggable, :user => user
|
||||
end
|
||||
|
||||
def ==(comparison_object)
|
||||
super || name == comparison_object.to_s
|
||||
end
|
||||
|
||||
def to_s
|
||||
name
|
||||
end
|
||||
end
|
||||
13
tracks/vendor/plugins/acts_as_taggable/lib/tagging.rb
vendored
Normal file
13
tracks/vendor/plugins/acts_as_taggable/lib/tagging.rb
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
class Tagging < ActiveRecord::Base
|
||||
belongs_to :tag
|
||||
belongs_to :taggable, :polymorphic => true
|
||||
belongs_to :user
|
||||
|
||||
def self.tagged_class(taggable)
|
||||
ActiveRecord::Base.send(:class_name_of_active_record_descendant, taggable.class).to_s
|
||||
end
|
||||
|
||||
def self.find_taggable(tagged_class, tagged_id)
|
||||
tagged_class.constantize.find(tagged_id)
|
||||
end
|
||||
end
|
||||
1
tracks/vendor/plugins/acts_as_taggable/test/acts_as_taggable_test.rb
vendored
Normal file
1
tracks/vendor/plugins/acts_as_taggable/test/acts_as_taggable_test.rb
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Testing goes here
|
||||
Loading…
Add table
Add a link
Reference in a new issue