mirror of
https://github.com/TracksApp/tracks.git
synced 2026-01-06 01:08:50 +01:00
restore all associations for tags. All tests are passing
This commit is contained in:
parent
b2e34d4694
commit
b2e6253b4c
8 changed files with 107 additions and 41 deletions
|
|
@ -1,5 +1,4 @@
|
|||
module TodosHelper
|
||||
|
||||
|
||||
def remote_star_icon(todo=@todo)
|
||||
link_to( image_tag_for_star(todo),
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ class RecurringTodo < ActiveRecord::Base
|
|||
|
||||
has_many :todos
|
||||
|
||||
include IsTaggable
|
||||
|
||||
named_scope :active, :conditions => { :state => 'active'}
|
||||
named_scope :completed, :conditions => { :state => 'completed'}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
|
||||
# The Tag model. This model is automatically generated and added to your app if
|
||||
# you run the tagging generator included with has_many_polymorphs.
|
||||
|
||||
class Tag < ActiveRecord::Base
|
||||
|
||||
|
||||
has_many :taggings
|
||||
has_many :taggable, :through => :taggings
|
||||
|
||||
DELIMITER = "," # Controls how to split and join tagnames from strings. You may need to change the <tt>validates_format_of parameters</tt> if you change this.
|
||||
JOIN_DELIMITER = ", "
|
||||
|
||||
|
|
@ -12,26 +11,6 @@ class Tag < ActiveRecord::Base
|
|||
validates_presence_of :name
|
||||
validates_uniqueness_of :name, :case_sensitive => false
|
||||
|
||||
# Change this validation if you need more complex tag names.
|
||||
# validates_format_of :name, :with => /^[a-zA-Z0-9\_\-]+$/, :message => "can not contain special characters"
|
||||
|
||||
# Set up the polymorphic relationship.
|
||||
has_many_polymorphs :taggables,
|
||||
:from => [:todos, :recurring_todos],
|
||||
:through => :taggings,
|
||||
:dependent => :destroy,
|
||||
:skip_duplicates => false,
|
||||
:parent_extend => proc {
|
||||
# Defined on the taggable models, not on Tag itself. Return the tagnames
|
||||
# associated with this record as a string.
|
||||
def to_s
|
||||
self.map(&:name).sort.join(Tag::JOIN_DELIMITER)
|
||||
end
|
||||
def all_except_starred
|
||||
self.reject{|tag| tag.name == Todo::STARRED_TAG_NAME}
|
||||
end
|
||||
}
|
||||
|
||||
# Callback to strip extra spaces from the tagname before saving it. If you
|
||||
# allow tags to be renamed later, you might want to use the
|
||||
# <tt>before_save</tt> callback instead.
|
||||
|
|
@ -43,9 +22,4 @@ class Tag < ActiveRecord::Base
|
|||
taggings.create :taggable => taggable, :user => user
|
||||
end
|
||||
|
||||
# Tag::Error class. Raised by ActiveRecord::Base::TaggingExtensions if
|
||||
# something goes wrong.
|
||||
class Error < StandardError
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
|
||||
# The Tagging join model. This model is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs.
|
||||
|
||||
class Tagging < ActiveRecord::Base
|
||||
class Tagging < ActiveRecord::Base
|
||||
|
||||
belongs_to :tag
|
||||
belongs_to :taggable, :polymorphic => true
|
||||
|
||||
# If you also need to use <tt>acts_as_list</tt>, you will have to manage the tagging positions manually by creating decorated join records when you associate Tags with taggables.
|
||||
# acts_as_list :scope => :taggable
|
||||
|
||||
|
||||
# This callback makes sure that an orphaned <tt>Tag</tt> is deleted if it no longer tags anything.
|
||||
def after_destroy
|
||||
tag.destroy_without_callbacks if tag and tag.taggings.count == 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,12 +2,16 @@ class Todo < ActiveRecord::Base
|
|||
|
||||
after_save :save_predecessors
|
||||
|
||||
# relations
|
||||
# associations
|
||||
belongs_to :context
|
||||
belongs_to :project
|
||||
belongs_to :user
|
||||
belongs_to :recurring_todo
|
||||
|
||||
# Tag association
|
||||
include IsTaggable
|
||||
|
||||
# Dependencies associations
|
||||
has_many :predecessor_dependencies, :foreign_key => 'predecessor_id', :class_name => 'Dependency', :dependent => :destroy
|
||||
has_many :successor_dependencies, :foreign_key => 'successor_id', :class_name => 'Dependency', :dependent => :destroy
|
||||
has_many :predecessors, :through => :successor_dependencies
|
||||
|
|
@ -16,7 +20,7 @@ class Todo < ActiveRecord::Base
|
|||
:source => :predecessor, :conditions => ['NOT (todos.state = ?)', 'completed']
|
||||
has_many :pending_successors, :through => :predecessor_dependencies,
|
||||
:source => :successor, :conditions => ['todos.state = ?', 'pending']
|
||||
|
||||
|
||||
# scopes for states of this todo
|
||||
named_scope :active, :conditions => { :state => 'active' }
|
||||
named_scope :active_or_hidden, :conditions => ["todos.state = ? OR todos.state = ?", 'active', 'project_hidden']
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ end
|
|||
require 'name_part_finder'
|
||||
require 'tracks/todo_list'
|
||||
require 'tracks/config'
|
||||
require 'tagging_extensions' # Needed for tagging-specific extensions
|
||||
require 'digest/sha1' #Needed to support 'rake db:fixtures:load' on some ruby installs: http://dev.rousette.org.uk/ticket/557
|
||||
|
||||
if ( SITE_CONFIG['authentication_schemes'].include? 'ldap')
|
||||
|
|
|
|||
91
lib/is_taggable.rb
Normal file
91
lib/is_taggable.rb
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# These methods are adapted from has_many_polymorphs' tagging_extensions
|
||||
|
||||
module IsTaggable
|
||||
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
|
||||
# Add tags associations
|
||||
has_many :taggings, :as => :taggable
|
||||
has_many :tags, :through => :taggings do
|
||||
def to_s
|
||||
self.map(&:name).sort.join(Tag::JOIN_DELIMITER)
|
||||
end
|
||||
def all_except_starred
|
||||
self.reject{|tag| tag.name == Todo::STARRED_TAG_NAME}
|
||||
end
|
||||
end
|
||||
|
||||
def tag_list
|
||||
tags.reload
|
||||
tags.to_s
|
||||
end
|
||||
|
||||
def tag_list=(value)
|
||||
tag_with(value)
|
||||
end
|
||||
|
||||
# Replace the existing tags on <tt>self</tt>. Accepts a string of tagnames, an array of tagnames, or an array of Tags.
|
||||
def tag_with list
|
||||
list = tag_cast_to_string(list)
|
||||
|
||||
# Transactions may not be ideal for you here; be aware.
|
||||
Tag.transaction do
|
||||
current = tags.map(&:name)
|
||||
_add_tags(list - current)
|
||||
_remove_tags(current - list)
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Add tags to <tt>self</tt>. Accepts a string of tagnames, an array of tagnames, or an array of Tags.
|
||||
#
|
||||
# We need to avoid name conflicts with the built-in ActiveRecord association methods, thus the underscores.
|
||||
def _add_tags incoming
|
||||
tag_cast_to_string(incoming).each do |tag_name|
|
||||
# added following check to prevent empty tags from being saved (which will fail)
|
||||
unless tag_name.blank?
|
||||
begin
|
||||
tag = Tag.find_or_create_by_name(tag_name)
|
||||
raise Tag::Error, "tag could not be saved: #{tag_name}" if tag.new_record?
|
||||
tags << tag
|
||||
rescue ActiveRecord::StatementInvalid => e
|
||||
raise unless e.to_s =~ /duplicate/i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Removes tags from <tt>self</tt>. Accepts a string of tagnames, an array of tagnames, or an array of Tags.
|
||||
def _remove_tags outgoing
|
||||
outgoing = tag_cast_to_string(outgoing)
|
||||
tags.delete(*(tags.select{|tag| outgoing.include? tag.name}))
|
||||
end
|
||||
|
||||
def tag_cast_to_string obj
|
||||
case obj
|
||||
when Array
|
||||
obj.map! do |item|
|
||||
case item
|
||||
# removed next line as it prevents using numbers as tags
|
||||
# when /^\d+$/, Fixnum then Tag.find(item).name # This will be slow if you use ids a lot.
|
||||
when Tag then item.name
|
||||
when String then item
|
||||
else
|
||||
raise "Invalid type"
|
||||
end
|
||||
end
|
||||
when String
|
||||
obj = obj.split(Tag::DELIMITER).map do |tag_name|
|
||||
tag_name.strip.squeeze(" ")
|
||||
end
|
||||
else
|
||||
raise "Invalid object of class #{obj.class} as tagging method parameter"
|
||||
end.flatten.compact.map(&:downcase).uniq
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -261,7 +261,7 @@ class TodosControllerTest < ActionController::TestCase
|
|||
def test_find_tagged_with
|
||||
login_as(:admin_user)
|
||||
@user = User.find(@request.session['user_id'])
|
||||
tag = Tag.find_by_name('foo').todos
|
||||
tag = Tag.find_by_name('foo').taggings
|
||||
@tagged = tag.count
|
||||
get :tag, :name => 'foo'
|
||||
assert_response :success
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue