Skip to content
This repository has been archived by the owner on Mar 19, 2021. It is now read-only.

Commit

Permalink
[Possible breaking change] ActsAsTaggableOn::Tag is not extend with A…
Browse files Browse the repository at this point in the history
…ctsAsTaggableOn::Utils anymore

fixes mbleigh#524
  • Loading branch information
seuros committed May 6, 2014
1 parent 5c1cfdd commit b99502d
Show file tree
Hide file tree
Showing 13 changed files with 115 additions and 64 deletions.
6 changes: 6 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ Re-run the migrations generator
rake acts_as_taggable_on_engine:install:migrations

It will create any new migrations and skip existing ones


##Breaking changes:

- ActsAsTaggableOn::Tag is not extend with ActsAsTaggableOn::Utils anymore.
Please use ActsAsTaggableOn::Utils instead
4 changes: 2 additions & 2 deletions lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,15 @@ def safe_to_sql(relation)

def generate_tagging_scope_in_clause(tagging_scope, table_name, primary_key)
table_name_pkey = "#{table_name}.#{primary_key}"
if ActsAsTaggableOn::Tag.using_mysql?
if ActsAsTaggableOn::Utils.using_mysql?
# See https://github.com/mbleigh/acts-as-taggable-on/pull/457 for details
scoped_ids = select(table_name_pkey).map(&:id)
tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN (?)", scoped_ids)
else
tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{safe_to_sql(select(table_name_pkey))})")
end

return tagging_scope
tagging_scope
end

def tagging_conditions(options)
Expand Down
31 changes: 15 additions & 16 deletions lib/acts_as_taggable_on/acts_as_taggable_on/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ def initialize_acts_as_taggable_on_core
# 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_taggable_compatibility context_taggings, as: :taggable,
dependent: :destroy,
class_name: 'ActsAsTaggableOn::Tagging',
order: taggings_order,
conditions: ["#{ActsAsTaggableOn::Tagging.table_name}.context = (?)", tags_type],
include: :tag
dependent: :destroy,
class_name: 'ActsAsTaggableOn::Tagging',
order: taggings_order,
conditions: ["#{ActsAsTaggableOn::Tagging.table_name}.context = (?)", tags_type],
include: :tag

has_many_with_taggable_compatibility context_tags, through: context_taggings,
source: :tag,
class_name: 'ActsAsTaggableOn::Tag',
order: taggings_order
source: :tag,
class_name: 'ActsAsTaggableOn::Tag',
order: taggings_order

end

Expand Down Expand Up @@ -96,13 +96,13 @@ def tagged_with(tags, options = {})
context = options.delete(:on)
owned_by = options.delete(:owned_by)
alias_base_name = undecorated_table_name.gsub('.', '_')
quote = ActsAsTaggableOn::Tag.using_postgresql? ? '"' : ''
quote = ActsAsTaggableOn::Utils.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 ')
tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{ActsAsTaggableOn::Utils.like_operator} ? ESCAPE '!'", "%#{ActsAsTaggableOn::Utils.escape_like(t)}%"]) }.join(' OR ')
else
tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{like_operator} ?", t]) }.join(' OR ')
tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{ActsAsTaggableOn::Utils.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, nil)})"
Expand Down Expand Up @@ -183,7 +183,7 @@ def tagged_with(tags, options = {})
group ||= [] # Rails interprets this as a no-op in the group() call below
if options.delete(:order_by_matching_tag_count)
select_clause = "#{table_name}.*, COUNT(#{taggings_alias}.tag_id) AS #{taggings_alias}_count"
group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(self) : "#{table_name}.#{primary_key}"
group_columns = ActsAsTaggableOn::Utils.using_postgresql? ? grouped_column_names_for(self) : "#{table_name}.#{primary_key}"
group = group_columns
order_by << "#{taggings_alias}_count DESC"

Expand All @@ -195,7 +195,7 @@ def tagged_with(tags, options = {})

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

group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(self) : "#{table_name}.#{primary_key}"
group_columns = ActsAsTaggableOn::Utils.using_postgresql? ? grouped_column_names_for(self) : "#{table_name}.#{primary_key}"
group = group_columns
having = "COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"
end
Expand Down Expand Up @@ -284,7 +284,7 @@ def all_tags_on(context)
opts = ["#{tagging_table_name}.context = ?", context.to_s]
scope = base_tags.where(opts)

if ActsAsTaggableOn::Tag.using_postgresql?
if ActsAsTaggableOn::Utils.using_postgresql?
group_columns = grouped_column_names_for(ActsAsTaggableOn::Tag)
scope.order("max(#{tagging_table_name}.created_at)").group(group_columns)
else
Expand Down Expand Up @@ -415,9 +415,8 @@ def save_tags
#
# @param [Array<String>] tag_list Tags to find or create
# @param [Symbol] context The tag context for the tag_list
def find_or_create_tags_from_list_with_context(tag_list, context)
def find_or_create_tags_from_list_with_context(tag_list, _context)
load_tags(tag_list)
end
end
end

2 changes: 1 addition & 1 deletion lib/acts_as_taggable_on/acts_as_taggable_on/related.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def exclude_self(klass, id)
end

def group_columns(klass)
if ActsAsTaggableOn::Tag.using_postgresql?
if ActsAsTaggableOn::Utils.using_postgresql?
grouped_column_names_for(klass)
else
"#{klass.table_name}.#{klass.primary_key}"
Expand Down
7 changes: 3 additions & 4 deletions lib/acts_as_taggable_on/tag.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# coding: utf-8
module ActsAsTaggableOn
class Tag < ::ActiveRecord::Base
extend ActsAsTaggableOn::Utils

attr_accessible :name if defined?(ActiveModel::MassAssignmentSecurity)

Expand Down Expand Up @@ -45,13 +44,13 @@ def self.named_any(list)
end

def self.named_like(name)
clause = ["name #{like_operator} ? ESCAPE '!'", "%#{escape_like(name)}%"]
clause = ["name #{ActsAsTaggableOn::Utils.like_operator} ? ESCAPE '!'", "%#{ActsAsTaggableOn::Utils.escape_like(name)}%"]
where(clause)
end

def self.named_like_any(list)
clause = list.map { |tag|
sanitize_sql(["name #{like_operator} ? ESCAPE '!'", "%#{escape_like(tag.to_s)}%"])
sanitize_sql(["name #{ActsAsTaggableOn::Utils.like_operator} ? ESCAPE '!'", "%#{ActsAsTaggableOn::Utils.escape_like(tag.to_s)}%"])
}.join(' OR ')
where(clause)
end
Expand Down Expand Up @@ -113,7 +112,7 @@ def comparable_name(str)
end

def binary
using_mysql? ? 'BINARY ' : nil
ActsAsTaggableOn::Utils.using_mysql? ? 'BINARY ' : nil
end

def unicode_downcase(string)
Expand Down
40 changes: 26 additions & 14 deletions lib/acts_as_taggable_on/tagger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,30 @@ module ClassMethods
def acts_as_tagger(opts={})
class_eval do
has_many_with_taggable_compatibility :owned_taggings,
opts.merge(
as: :tagger,
dependent: :destroy,
class_name: 'ActsAsTaggableOn::Tagging'
)
opts.merge(
as: :tagger,
dependent: :destroy,
class_name: 'ActsAsTaggableOn::Tagging'
)

has_many_with_taggable_compatibility :owned_tags,
through: :owned_taggings,
source: :tag,
class_name: 'ActsAsTaggableOn::Tag',
uniq: true
through: :owned_taggings,
source: :tag,
class_name: 'ActsAsTaggableOn::Tag',
uniq: true
end

include ActsAsTaggableOn::Tagger::InstanceMethods
extend ActsAsTaggableOn::Tagger::SingletonMethods
end

def is_tagger?
def tagger?
false
end

def is_tagger?
tagger?
end
end

module InstanceMethods
Expand All @@ -54,23 +58,31 @@ def tag(taggable, opts={})
skip_save = opts.delete(:skip_save)
return false unless taggable.respond_to?(:is_taggable?) && taggable.is_taggable?

fail 'You need to specify a tag context using :on' unless opts.key?(:on)
fail 'You need to specify some tags using :with' unless opts.key?(:with)
fail 'You need to specify a tag context using :on' unless opts.key?(:on)
fail 'You need to specify some tags using :with' unless opts.key?(:with)
fail "No context :#{opts[:on]} defined in #{taggable.class}" unless opts[:force] || taggable.tag_types.include?(opts[:on])

taggable.set_owner_tag_list_on(self, opts[:on].to_s, opts[:with])
taggable.save unless skip_save
end

def is_tagger?
def tagger?
self.class.is_tagger?
end

def is_tagger?
tagger?
end
end

module SingletonMethods
def is_tagger?
def tagger?
true
end

def is_tagger?
tagger?
end
end
end
end
21 changes: 15 additions & 6 deletions lib/acts_as_taggable_on/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,25 @@ module ActsAsTaggableOn
module Utils
extend self

# Use ActsAsTaggableOn::Tag connection
def connection
::ActiveRecord::Base.connection
ActsAsTaggableOn::Tag.connection
end

def using_postgresql?
connection && connection.adapter_name == 'PostgreSQL'
end

def postgresql_version
if using_postgresql?
connection.execute("SHOW SERVER_VERSION").first["server_version"].to_f
end
end

def postgresql_support_json?
postgresql_version >= 9.2
end

def using_sqlite?
connection && connection.adapter_name == 'SQLite'
end
Expand All @@ -20,7 +31,7 @@ def using_mysql?
end

def using_case_insensitive_collation?
using_mysql? && ::ActiveRecord::Base.connection.collation =~ /_ci\Z/
using_mysql? && connection.collation =~ /_ci\Z/
end

def supports_concurrency?
Expand All @@ -32,15 +43,13 @@ def sha_prefix(string)
end

def active_record4?
::ActiveRecord::VERSION::MAJOR == 4
::ActiveRecord::VERSION::MAJOR == 4
end

def active_record42?
active_record4? && ::ActiveRecord::VERSION::MINOR >= 2
active_record4? && ::ActiveRecord::VERSION::MINOR >= 2
end

private

def like_operator
using_postgresql? ? 'ILIKE' : 'LIKE'
end
Expand Down
3 changes: 3 additions & 0 deletions spec/acts_as_taggable_on/caching_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,7 @@
end
end

describe 'CachingWithArray' do
pending '#TODO'
end
end
16 changes: 8 additions & 8 deletions spec/acts_as_taggable_on/tag_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

describe 'named like any' do
context 'case insensitive collation and unique index on tag name' do
if described_class.using_case_insensitive_collation?
if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
before(:each) do
ActsAsTaggableOn::Tag.create(name: 'Awesome')
ActsAsTaggableOn::Tag.create(name: 'epic')
Expand All @@ -30,7 +30,7 @@
end

context 'case insensitive collation without indexes or case sensitive collation with indexes' do
if described_class.using_case_insensitive_collation?
if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
include_context 'without unique index'
end

Expand Down Expand Up @@ -67,7 +67,7 @@
end
end

unless ActsAsTaggableOn::Tag.using_sqlite?
unless ActsAsTaggableOn::Utils.using_sqlite?
describe 'find or create by unicode name' do
before(:each) do
@tag.name = 'привет'
Expand All @@ -82,7 +82,7 @@
expect(ActsAsTaggableOn::Tag.find_or_create_with_like_by_name('ПРИВЕТ')).to eq(@tag)
end

if ActsAsTaggableOn::Tag.using_case_insensitive_collation?
if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
it 'should find by name accent insensitive' do
@tag.name = 'inupiat'
@tag.save
Expand All @@ -107,7 +107,7 @@
end

context 'case sensitive' do
if described_class.using_case_insensitive_collation?
if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
include_context 'without unique index'
end

Expand All @@ -126,7 +126,7 @@
end

context 'case sensitive' do
if described_class.using_case_insensitive_collation?
if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
include_context 'without unique index'
end

Expand Down Expand Up @@ -226,7 +226,7 @@
end

context 'case sensitive' do
if described_class.using_case_insensitive_collation?
if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
include_context 'without unique index'
end

Expand All @@ -240,7 +240,7 @@
end

context 'case sensitive' do
if described_class.using_case_insensitive_collation?
if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
include_context 'without unique index'
end

Expand Down
4 changes: 2 additions & 2 deletions spec/acts_as_taggable_on/taggable_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@
expect(TaggableModel.select('distinct(taggable_models.id), taggable_models.*').joins(:untaggable_models).tagged_with(['rails', 'ruby'], :any => false).to_a.sort).to eq([bob, frank].sort)
end

unless ActsAsTaggableOn::Tag.using_sqlite?
unless ActsAsTaggableOn::Utils.using_sqlite?
it 'should not care about case for unicode names' do
ActsAsTaggableOn.strict_case_match = false
TaggableModel.create(name: 'Anya', tag_list: 'ПРИВЕТ')
Expand Down Expand Up @@ -848,7 +848,7 @@
end


if ActsAsTaggableOn::Tag.using_postgresql?
if ActsAsTaggableOn::Utils.using_postgresql?
describe 'Taggable model with json columns' do
before(:each) do
@taggable = TaggableModelWithJson.new(:name => 'Bob Jones')
Expand Down
5 changes: 5 additions & 0 deletions spec/internal/app/models/cached_model_with_array.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
if ActsAsTaggableOn::Utils.using_postgresql?
class CachedModelWithArray < ActiveRecord::Base
acts_as_taggable
end
end
Loading

0 comments on commit b99502d

Please sign in to comment.