Update has_many_polymorphs to 421dd0bd60b246652bbbafd64724ebf1efa27607

This commit is contained in:
Eric Allen 2009-12-07 18:20:17 -05:00
parent 804d59c542
commit 144e74682b
49 changed files with 189 additions and 126 deletions

View file

@ -1,3 +1,6 @@
v2.2. Various fixes.
v2.13. Merge various fixes for Rails 2.2.2.
v2.12. Improvements to the test suite; bugfixes for STI children (rsl). Remove fancy dependency system in favor of using Dispatcher::to_prepare every time. v2.12. Improvements to the test suite; bugfixes for STI children (rsl). Remove fancy dependency system in favor of using Dispatcher::to_prepare every time.

View file

@ -22,6 +22,7 @@ lib/has_many_polymorphs/support_methods.rb
lib/has_many_polymorphs.rb lib/has_many_polymorphs.rb
LICENSE LICENSE
Manifest Manifest
Rakefile
README README
test/fixtures/bow_wows.yml test/fixtures/bow_wows.yml
test/fixtures/cats.yml test/fixtures/cats.yml
@ -92,10 +93,8 @@ test/integration/app/db/migrate/006_create_double_sti_parents.rb
test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb
test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb
test/integration/app/db/migrate/009_create_library_model.rb test/integration/app/db/migrate/009_create_library_model.rb
test/integration/app/db/schema.rb
test/integration/app/doc/README_FOR_APP test/integration/app/doc/README_FOR_APP
test/integration/app/generators/commenting_generator_test.rb test/integration/app/generators/commenting_generator_test.rb
test/integration/app/hmp_development
test/integration/app/lib/library_model.rb test/integration/app/lib/library_model.rb
test/integration/app/public/404.html test/integration/app/public/404.html
test/integration/app/public/500.html test/integration/app/public/500.html

View file

@ -29,7 +29,7 @@ The plugin also includes a generator for a tagging system, a common use case (se
== Requirements == Requirements
* Rails 1.2.3 or greater * Rails 2.2.2 or greater
= Usage = Usage

View file

@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
class TagTest < Test::Unit::TestCase class TagTest < ActiveSupport::TestCase
fixtures <%= taggable_models[0..1].join(", ") -%> fixtures <%= taggable_models[0..1].join(", ") -%>
def setup def setup

View file

@ -1,4 +1,3 @@
class ActiveRecord::Base #:nodoc: class ActiveRecord::Base #:nodoc:
# These extensions make models taggable. This file is automatically generated and required by your app if you run the tagging generator included with has_many_polymorphs. # These extensions make models taggable. This file is automatically generated and required by your app if you run the tagging generator included with has_many_polymorphs.
@ -13,7 +12,7 @@ class ActiveRecord::Base #:nodoc:
begin begin
tag = Tag.find_or_create_by_name(tag_name) tag = Tag.find_or_create_by_name(tag_name)
raise Tag::Error, "tag could not be saved: #{tag_name}" if tag.new_record? raise Tag::Error, "tag could not be saved: #{tag_name}" if tag.new_record?
tag.taggables << self tags << tag
rescue ActiveRecord::StatementInvalid => e rescue ActiveRecord::StatementInvalid => e
raise unless e.to_s =~ /duplicate/i raise unless e.to_s =~ /duplicate/i
end end
@ -24,15 +23,17 @@ class ActiveRecord::Base #:nodoc:
def _remove_tags outgoing def _remove_tags outgoing
taggable?(true) taggable?(true)
outgoing = tag_cast_to_string(outgoing) outgoing = tag_cast_to_string(outgoing)
return [] if outgoing.empty?
<% if options[:self_referential] %> <% if options[:self_referential] %>
# because of http://dev.rubyonrails.org/ticket/6466 # because of http://dev.rubyonrails.org/ticket/6466
taggings.destroy(*(taggings.find(:all, :include => :<%= parent_association_name -%>).select do |tagging| taggings.destroy(*(taggings.find(:all, :include => :<%= parent_association_name -%>).select do |tagging|
outgoing.include? tagging.<%= parent_association_name -%>.name outgoing.include? tagging.<%= parent_association_name -%>.name
end)) end))
<% else -%> <% else -%>
<%= parent_association_name -%>s.delete(*(<%= parent_association_name -%>s.select do |tag| outgoing_tags = <%= parent_association_name -%>s.find_all_by_name(outgoing)
outgoing.include? tag.name outgoing_taggings = taggings.find_all_by_<%= parent_association_name -%>_id(outgoing_tags.map(&:id))
end))
taggings.destroy(*outgoing_taggings)
<% end -%> <% end -%>
end end
@ -66,7 +67,11 @@ class ActiveRecord::Base #:nodoc:
<%= parent_association_name -%>s.to_s <%= parent_association_name -%>s.to_s
#:startdoc: #:startdoc:
end end
def tag_list=(value)
tag_with(value)
end
private private
def tag_cast_to_string obj #:nodoc: def tag_cast_to_string obj #:nodoc:
@ -144,6 +149,47 @@ class ActiveRecord::Base #:nodoc:
find_by_sql(sql) find_by_sql(sql)
end end
def self.tagged_with_any(*tag_list)
options = tag_list.last.is_a?(Hash) ? tag_list.pop : {}
tag_list = parse_tags(tag_list)
scope = scope(:find)
options[:select] ||= "#{table_name}.*"
options[:from] ||= "#{table_name}, tags, taggings"
sql = "SELECT #{(scope && scope[:select]) || options[:select]} "
sql << "FROM #{(scope && scope[:from]) || options[:from]} "
add_joins!(sql, options, scope)
sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id "
sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' "
sql << "AND taggings.tag_id = tags.id "
sql << "AND ("
or_options = []
tag_list.each do |name|
or_options << "tags.name = '#{name}'"
end
or_options_joined = or_options.join(" OR ")
sql << "#{or_options_joined}) "
sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions]
columns = column_names.map do |column|
"#{table_name}.#{column}"
end.join(", ")
sql << "GROUP BY #{columns} "
add_order!(sql, options[:order], scope)
add_limit!(sql, options, scope)
add_lock!(sql, options, scope)
find_by_sql(sql)
end
def parse_tags(tags) def parse_tags(tags)
return [] if tags.blank? return [] if tags.blank?

View file

@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
class TaggingTest < Test::Unit::TestCase class TaggingTest < ActiveSupport::TestCase
fixtures :tags, :taggings, <%= taggable_models[0..1].join(", ") -%> fixtures :tags, :taggings, <%= taggable_models[0..1].join(", ") -%>
def setup def setup
@ -45,15 +45,15 @@ class TaggingTest < Test::Unit::TestCase
<% if options[:self_referential] -%> <% if options[:self_referential] -%>
def test_self_referential_tag_with def test_self_referential_tag_with
@tag1.tag_with [1, 2] @tag1.tag_with [1, 2]
assert @tag1.tags.include?(@tag1) assert @tag1.tags.any? {|obj| obj == @tag1}
assert !@tag2.tags.include?(@tag1) assert !@tag2.tags.any? {|obj| obj == @tag1}
end end
<% end -%> <% end -%>
def test__add_tags def test__add_tags
@obj1._add_tags "porter longneck" @obj1._add_tags "porter longneck"
assert Tag.find_by_name("porter").taggables.include?(@obj1) assert Tag.find_by_name("porter").taggables.any? {|obj| obj == @obj1}
assert Tag.find_by_name("longneck").taggables.include?(@obj1) assert Tag.find_by_name("longneck").taggables.any? {|obj| obj == @obj1}
assert_equal "longneck pale porter", @obj1.tag_list assert_equal "longneck pale porter", @obj1.tag_list
@obj1._add_tags [2] @obj1._add_tags [2]

View file

@ -14,7 +14,7 @@ class ActiveRecord::Base
extend ActiveRecord::Associations::PolymorphicClassMethods extend ActiveRecord::Associations::PolymorphicClassMethods
end end
if ENV['HMP_DEBUG'] or ENV['RAILS_ENV'] =~ /development|test/ and ENV['USER'] == 'eweaver' if ENV['HMP_DEBUG'] || ENV['RAILS_ENV'] =~ /development|test/ && ENV['USER'] == 'eweaver'
require 'has_many_polymorphs/debugging_tools' require 'has_many_polymorphs/debugging_tools'
end end

View file

@ -88,18 +88,19 @@ module ActiveRecord #:nodoc:
def construct_quoted_owner_attributes(*args) #:nodoc: def construct_quoted_owner_attributes(*args) #:nodoc:
# no access to returning() here? why not? # no access to returning() here? why not?
type_key = @reflection.options[:foreign_type_key] type_key = @reflection.options[:foreign_type_key]
{@reflection.primary_key_name => @owner.id, h = {@reflection.primary_key_name => @owner.id}
type_key=> (@owner.class.base_class.name if type_key)} h[type_key] = @owner.class.base_class.name if type_key
h
end end
def construct_from #:nodoc: def construct_from #:nodoc:
# build the FROM part of the query, in this case, the polymorphic join table # build the FROM part of the query, in this case, the polymorphic join table
@reflection.klass.table_name @reflection.klass.quoted_table_name
end end
def construct_owner #:nodoc: def construct_owner #:nodoc:
# the table name for the owner object's class # the table name for the owner object's class
@owner.class.table_name @owner.class.quoted_table_name
end end
def construct_owner_key #:nodoc: def construct_owner_key #:nodoc:
@ -114,10 +115,10 @@ module ActiveRecord #:nodoc:
def construct_joins(custom_joins = nil) #:nodoc: def construct_joins(custom_joins = nil) #:nodoc:
# build the string of default joins # build the string of default joins
"JOIN #{construct_owner} polymorphic_parent ON #{construct_from}.#{@reflection.options[:foreign_key]} = polymorphic_parent.#{construct_owner_key} " + "JOIN #{construct_owner} AS polymorphic_parent ON #{construct_from}.#{@reflection.options[:foreign_key]} = polymorphic_parent.#{construct_owner_key} " +
@reflection.options[:from].map do |plural| @reflection.options[:from].map do |plural|
klass = plural._as_class klass = plural._as_class
"LEFT JOIN #{klass.table_name} ON #{construct_from}.#{@reflection.options[:polymorphic_key]} = #{klass.table_name}.#{klass.primary_key} AND #{construct_from}.#{@reflection.options[:polymorphic_type_key]} = #{@reflection.klass.quote_value(klass.base_class.name)}" "LEFT JOIN #{klass.quoted_table_name} ON #{construct_from}.#{@reflection.options[:polymorphic_key]} = #{klass.quoted_table_name}.#{klass.primary_key} AND #{construct_from}.#{@reflection.options[:polymorphic_type_key]} = #{@reflection.klass.quote_value(klass.base_class.name)}"
end.uniq.join(" ") + " #{custom_joins}" end.uniq.join(" ") + " #{custom_joins}"
end end

View file

@ -1,6 +1,5 @@
require 'initializer' unless defined? ::Rails::Initializer require 'initializer' unless defined? ::Rails::Initializer
require 'dispatcher' unless defined? ::ActionController::Dispatcher require 'action_controller/dispatcher' unless defined? ::ActionController::Dispatcher
module HasManyPolymorphs module HasManyPolymorphs
@ -17,9 +16,11 @@ Note that you can override DEFAULT_OPTIONS via Rails::Configuration#has_many_pol
end end
=end =end
MODELS_ROOT = "#{RAILS_ROOT}/app/models/"
DEFAULT_OPTIONS = { DEFAULT_OPTIONS = {
:file_pattern => "#{RAILS_ROOT}/app/models/**/*.rb", :file_pattern => "#{MODELS_ROOT}**/*.rb",
:file_exclusions => ['svn', 'CVS', 'bzr'], :file_exclusions => ['svn', 'CVS', 'bzr'],
:methods => ['has_many_polymorphs', 'acts_as_double_polymorphic_join'], :methods => ['has_many_polymorphs', 'acts_as_double_polymorphic_join'],
:requirements => []} :requirements => []}
@ -27,6 +28,7 @@ Note that you can override DEFAULT_OPTIONS via Rails::Configuration#has_many_pol
mattr_accessor :options mattr_accessor :options
@@options = HashWithIndifferentAccess.new(DEFAULT_OPTIONS) @@options = HashWithIndifferentAccess.new(DEFAULT_OPTIONS)
# Dispatcher callback to load polymorphic relationships from the top down. # Dispatcher callback to load polymorphic relationships from the top down.
def self.autoload def self.autoload
@ -37,12 +39,14 @@ Note that you can override DEFAULT_OPTIONS via Rails::Configuration#has_many_pol
require requirement require requirement
end end
Dir[options[:file_pattern]].each do |filename| Dir.glob(options[:file_pattern]).each do |filename|
next if filename =~ /#{options[:file_exclusions].join("|")}/ next if filename =~ /#{options[:file_exclusions].join("|")}/
open filename do |file| open(filename) do |file|
if file.grep(/#{options[:methods].join("|")}/).any? if file.grep(/#{options[:methods].join("|")}/).any?
begin begin
model = File.basename(filename)[0..-4].camelize modelname = filename[0..-4]
modelname.slice!(MODELS_ROOT)
model = modelname.camelize
_logger_warn "preloading parent model #{model}" _logger_warn "preloading parent model #{model}"
model.constantize model.constantize
rescue Object => e rescue Object => e
@ -64,7 +68,7 @@ class Rails::Initializer #:nodoc:
alias_method_chain :after_initialize, :autoload alias_method_chain :after_initialize, :autoload
end end
Dispatcher.to_prepare(:has_many_polymorphs_autoload) do ActionController::Dispatcher.to_prepare(:has_many_polymorphs_autoload) do
# Make sure it gets loaded in the app # Make sure it gets loaded in the app
HasManyPolymorphs.autoload HasManyPolymorphs.autoload
end end

View file

@ -398,7 +398,7 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
} }
if reflection.options[:foreign_type_key] if reflection.options[:foreign_type_key]
type_check = "#{reflection.options[:foreign_type_key]} = #{quote_value(self.base_class.name)}" type_check = "#{reflection.options[:join_class_name].constantize.quoted_table_name}.#{reflection.options[:foreign_type_key]} = #{quote_value(self.base_class.name)}"
conjunction = options[:conditions] ? " AND " : nil conjunction = options[:conditions] ? " AND " : nil
options[:conditions] = "#{options[:conditions]}#{conjunction}#{type_check}" options[:conditions] = "#{options[:conditions]}#{conjunction}#{type_check}"
options[:as] = reflection.options[:as] options[:as] = reflection.options[:as]

View file

@ -45,9 +45,13 @@ class Hash
# An implementation of select that returns a Hash. # An implementation of select that returns a Hash.
def _select def _select
Hash[*self.select do |key, value| if RUBY_VERSION >= "1.9"
yield key, value Hash[*self.select {|k, v| yield k, v }.flatten]
end._flatten_once] else
Hash[*self.select do |key, value|
yield key, value
end._flatten_once]
end
end end
end end

View file

@ -1,7 +1,7 @@
require 'fileutils' require 'fileutils'
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
class TaggingGeneratorTest < Test::Unit::TestCase class TaggingGeneratorTest < ActiveSupport::TestCase
def setup def setup
Dir.chdir RAILS_ROOT do Dir.chdir RAILS_ROOT do

View file

@ -0,0 +1,7 @@
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
# Pick a unique cookie name to distinguish our session data from others'
session :session_key => '_testapp_session_id'
end

View file

@ -3,6 +3,7 @@ config.cache_classes = ENV['PRODUCTION']
config.whiny_nils = true config.whiny_nils = true
config.action_controller.consider_all_requests_local = !ENV['PRODUCTION'] config.action_controller.consider_all_requests_local = !ENV['PRODUCTION']
config.action_controller.perform_caching = ENV['PRODUCTION'] config.action_controller.perform_caching = ENV['PRODUCTION']
config.action_view.cache_template_extensions = ENV['PRODUCTION'] # The following has been deprecated in Rails 2.1 and removed in 2.2
config.action_view.cache_template_extensions = ENV['PRODUCTION'] if Rails::VERSION::MAJOR < 2 or Rails::VERSION::MAJOR == 2 && Rails::VERSION::MINOR < 1
config.action_view.debug_rjs = !ENV['PRODUCTION'] config.action_view.debug_rjs = !ENV['PRODUCTION']
config.action_mailer.raise_delivery_errors = false config.action_mailer.raise_delivery_errors = false

View file

@ -1,7 +1,7 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
require 'fileutils' require 'fileutils'
class CommentingGeneratorTest < Test::Unit::TestCase class CommentingGeneratorTest < ActiveSupport::TestCase
def test_ensure_comments_dont_exist def test_ensure_comments_dont_exist
# make sure the comments are already defined # make sure the comments are already defined

View file

View file

View file

View file

View file

View file

View file

View file

View file

View file

View file

View file

View file

View file

View file

View file

@ -4,7 +4,7 @@ require 'addresses_controller'
# Re-raise errors caught by the controller. # Re-raise errors caught by the controller.
class AddressesController; def rescue_action(e) raise e end; end class AddressesController; def rescue_action(e) raise e end; end
class AddressesControllerTest < Test::Unit::TestCase class AddressesControllerTest < ActiveSupport::TestCase
fixtures :addresses fixtures :addresses
def setup def setup

View file

@ -4,7 +4,7 @@ require 'sellers_controller'
# Re-raise errors caught by the controller. # Re-raise errors caught by the controller.
class SellersController; def rescue_action(e) raise e end; end class SellersController; def rescue_action(e) raise e end; end
class SellersControllerTest < Test::Unit::TestCase class SellersControllerTest < ActiveSupport::TestCase
fixtures :sellers fixtures :sellers
def setup def setup

View file

@ -4,7 +4,7 @@ require 'states_controller'
# Re-raise errors caught by the controller. # Re-raise errors caught by the controller.
class StatesController; def rescue_action(e) raise e end; end class StatesController; def rescue_action(e) raise e end; end
class StatesControllerTest < Test::Unit::TestCase class StatesControllerTest < ActiveSupport::TestCase
fixtures :states fixtures :states
def setup def setup

View file

@ -4,7 +4,7 @@ require 'users_controller'
# Re-raise errors caught by the controller. # Re-raise errors caught by the controller.
class UsersController; def rescue_action(e) raise e end; end class UsersController; def rescue_action(e) raise e end; end
class UsersControllerTest < Test::Unit::TestCase class UsersControllerTest < ActiveSupport::TestCase
fixtures :users fixtures :users
def setup def setup

View file

@ -2,7 +2,7 @@ ENV["RAILS_ENV"] = "development"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment") require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'test_help' require 'test_help'
class Test::Unit::TestCase class ActiveSupport::TestCase
self.use_transactional_fixtures = true self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false self.use_instantiated_fixtures = false
end end

View file

@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
class BoneTest < Test::Unit::TestCase class BoneTest < ActiveSupport::TestCase
# Replace this with your real tests. # Replace this with your real tests.
def test_truth def test_truth
assert true assert true

View file

@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
class DoubleStiParentRelationshipTest < Test::Unit::TestCase class DoubleStiParentRelationshipTest < ActiveSupport::TestCase
# Replace this with your real tests. # Replace this with your real tests.
def test_truth def test_truth
assert true assert true

View file

@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
class DoubleStiParentTest < Test::Unit::TestCase class DoubleStiParentTest < ActiveSupport::TestCase
# Replace this with your real tests. # Replace this with your real tests.
def test_truth def test_truth
assert true assert true

View file

@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
class OrganicSubstanceTest < Test::Unit::TestCase class OrganicSubstanceTest < ActiveSupport::TestCase
# Replace this with your real tests. # Replace this with your real tests.
def test_truth def test_truth
assert true assert true

View file

@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
class SingleStiParentRelationshipTest < Test::Unit::TestCase class SingleStiParentRelationshipTest < ActiveSupport::TestCase
# Replace this with your real tests. # Replace this with your real tests.
def test_truth def test_truth
assert true assert true

View file

@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
class SingleStiParentTest < Test::Unit::TestCase class SingleStiParentTest < ActiveSupport::TestCase
# Replace this with your real tests. # Replace this with your real tests.
def test_truth def test_truth
assert true assert true

View file

@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
class StickTest < Test::Unit::TestCase class StickTest < ActiveSupport::TestCase
# Replace this with your real tests. # Replace this with your real tests.
def test_truth def test_truth
assert true assert true

View file

@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
class StoneTest < Test::Unit::TestCase class StoneTest < ActiveSupport::TestCase
# Replace this with your real tests. # Replace this with your real tests.
def test_truth def test_truth
assert true assert true

View file

@ -4,7 +4,7 @@ require 'open-uri'
# Start the server # Start the server
class ServerTest < Test::Unit::TestCase class ServerTest < ActiveSupport::TestCase
PORT = 43040 PORT = 43040
URL = "http://localhost:#{PORT}/" URL = "http://localhost:#{PORT}/"
@ -40,4 +40,4 @@ class ServerTest < Test::Unit::TestCase
# XXX Probably can use script/runner to test this # XXX Probably can use script/runner to test this
end end
end end

View file

@ -3,8 +3,6 @@ class EatersFoodstuff < ActiveRecord::Base
belongs_to :foodstuff, :class_name => "Petfood", :foreign_key => "foodstuff_id" belongs_to :foodstuff, :class_name => "Petfood", :foreign_key => "foodstuff_id"
belongs_to :eater, :polymorphic => true belongs_to :eater, :polymorphic => true
def before_save before_save { |record| record.some_attribute = 3 }
self.some_attribute = 3
end
end end

View file

@ -6,8 +6,8 @@ Dir.chdir "#{File.dirname(__FILE__)}/integration/app/" do
system("rm has_many_polymorphs; ln -s ../../../../../ has_many_polymorphs") system("rm has_many_polymorphs; ln -s ../../../../../ has_many_polymorphs")
end end
system "rake db:drop --trace RAILS_GEM_VERSION=2.0.2 " system "rake db:drop --trace RAILS_GEM_VERSION=2.2.2 "
system "rake db:create --trace RAILS_GEM_VERSION=2.0.2 " system "rake db:create --trace RAILS_GEM_VERSION=2.2.2 "
system "rake db:migrate --trace" system "rake db:migrate --trace"
system "rake db:fixtures:load --trace" system "rake db:fixtures:load --trace"
end end

View file

@ -1,10 +1,11 @@
$VERBOSE = nil $VERBOSE = nil
require 'rubygems' require 'rubygems'
require 'rake' # echoe relies on Rake being present but doesn't require it itself
require 'echoe' require 'echoe'
require 'test/unit' require 'test/unit'
require 'multi_rails_init' require 'multi_rails_init'
require 'ruby-debug' #require 'ruby-debug' # uncomment if needed (for Ruby >= 1.9 use require 'debug' where needed)
if defined? ENV['MULTIRAILS_RAILS_VERSION'] if defined? ENV['MULTIRAILS_RAILS_VERSION']
ENV['RAILS_GEM_VERSION'] = ENV['MULTIRAILS_RAILS_VERSION'] ENV['RAILS_GEM_VERSION'] = ENV['MULTIRAILS_RAILS_VERSION']
@ -23,13 +24,13 @@ LOG = "#{HERE}/integration/app/log/development.log"
require 'integration/app/config/environment' require 'integration/app/config/environment'
require 'test_help' require 'test_help'
Inflector.inflections {|i| i.irregular 'fish', 'fish' } ActiveSupport::Inflector.inflections {|i| i.irregular 'fish', 'fish' }
$LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path = HERE + "/fixtures") $LOAD_PATH.unshift(ActiveSupport::TestCase.fixture_path = HERE + "/fixtures")
$LOAD_PATH.unshift(HERE + "/models") $LOAD_PATH.unshift(HERE + "/models")
$LOAD_PATH.unshift(HERE + "/modules") $LOAD_PATH.unshift(HERE + "/modules")
class Test::Unit::TestCase class ActiveSupport::TestCase
self.use_transactional_fixtures = !(ActiveRecord::Base.connection.is_a? ActiveRecord::ConnectionAdapters::MysqlAdapter rescue false) self.use_transactional_fixtures = !(ActiveRecord::Base.connection.is_a? ActiveRecord::ConnectionAdapters::MysqlAdapter rescue false)
self.use_instantiated_fixtures = false self.use_instantiated_fixtures = false
end end

View file

@ -10,7 +10,7 @@ require 'aquatic/fish'
require 'aquatic/pupils_whale' require 'aquatic/pupils_whale'
require 'beautiful_fight_relationship' require 'beautiful_fight_relationship'
class PolymorphTest < Test::Unit::TestCase class PolymorphTest < ActiveSupport::TestCase
set_fixture_class :bow_wows => Dog set_fixture_class :bow_wows => Dog
set_fixture_class :keep_your_enemies_close => BeautifulFightRelationship set_fixture_class :keep_your_enemies_close => BeautifulFightRelationship
@ -76,7 +76,7 @@ class PolymorphTest < Test::Unit::TestCase
def test_duplicate_assignment def test_duplicate_assignment
# try to add a duplicate item when :ignore_duplicates is false # try to add a duplicate item when :ignore_duplicates is false
@kibbles.eaters.push(@alice) @kibbles.eaters.push(@alice)
assert @kibbles.eaters.include?(@alice) assert @kibbles.eaters.any? {|obj| obj == @alice}
@kibbles.eaters.push(@alice) @kibbles.eaters.push(@alice)
assert_equal @kibbles_eaters_count + 2, @kibbles.eaters.count assert_equal @kibbles_eaters_count + 2, @kibbles.eaters.count
assert_equal @join_count + 2, EatersFoodstuff.count assert_equal @join_count + 2, EatersFoodstuff.count
@ -114,7 +114,7 @@ class PolymorphTest < Test::Unit::TestCase
# reload; is the new association there? # reload; is the new association there?
assert @bits.eaters.reload assert @bits.eaters.reload
assert @bits.eaters.include?(@chloe) assert @bits.eaters.any? {|obj| obj == @chloe}
end end
def test_build_join_record_on_association def test_build_join_record_on_association
@ -126,7 +126,7 @@ class PolymorphTest < Test::Unit::TestCase
assert_equal @join_count + 1, EatersFoodstuff.count assert_equal @join_count + 1, EatersFoodstuff.count
assert @bits.eaters.reload assert @bits.eaters.reload
assert @bits.eaters.include?(@chloe) assert @bits.eaters.any? {|obj| obj == @chloe}
end end
# not supporting this, since has_many :through doesn't support it either # not supporting this, since has_many :through doesn't support it either
@ -145,12 +145,12 @@ class PolymorphTest < Test::Unit::TestCase
def test_self_reference def test_self_reference
assert @kibbles.eaters << @bits assert @kibbles.eaters << @bits
assert_equal @kibbles_eaters_count += 1, @kibbles.eaters.count assert_equal @kibbles_eaters_count += 1, @kibbles.eaters.count
assert @kibbles.eaters.include?(@bits) assert @kibbles.eaters.any? {|obj| obj == @bits}
@kibbles.reload @kibbles.reload
assert @kibbles.foodstuffs_of_eaters.blank? assert @kibbles.foodstuffs_of_eaters.blank?
@bits.reload @bits.reload
assert @bits.foodstuffs_of_eaters.include?(@kibbles) assert @bits.foodstuffs_of_eaters.any? {|obj| obj == @kibbles}
assert_equal [@kibbles], @bits.foodstuffs_of_eaters assert_equal [@kibbles], @bits.foodstuffs_of_eaters
end end
@ -190,9 +190,9 @@ class PolymorphTest < Test::Unit::TestCase
def test_individual_collections_push def test_individual_collections_push
assert_equal [@chloe], (@kibbles.eater_kittens << @chloe) assert_equal [@chloe], (@kibbles.eater_kittens << @chloe)
@kibbles.reload @kibbles.reload
assert @kibbles.eaters.include?(@chloe) assert @kibbles.eaters.any? {|obj| obj == @chloe}
assert @kibbles.eater_kittens.include?(@chloe) assert @kibbles.eater_kittens.any? {|obj| obj == @chloe}
assert !@kibbles.eater_dogs.include?(@chloe) assert !@kibbles.eater_dogs.any? {|obj| obj == @chloe}
end end
def test_individual_collections_delete def test_individual_collections_delete
@ -204,7 +204,7 @@ class PolymorphTest < Test::Unit::TestCase
@kibbles.reload @kibbles.reload
assert @kibbles.eater_kittens.empty? assert @kibbles.eater_kittens.empty?
assert @kibbles.eater_dogs.include?(@spot) assert @kibbles.eater_dogs.any? {|obj| obj == @spot}
end end
def test_individual_collections_clear def test_individual_collections_clear
@ -217,14 +217,14 @@ class PolymorphTest < Test::Unit::TestCase
assert @kibbles.eater_kittens.empty? assert @kibbles.eater_kittens.empty?
assert_equal 2, @kibbles.eaters.size assert_equal 2, @kibbles.eaters.size
assert !@kibbles.eater_kittens.include?(@chloe) assert !@kibbles.eater_kittens.any? {|obj| obj == @chloe}
assert !@kibbles.eaters.include?(@chloe) assert !@kibbles.eaters.any? {|obj| obj == @chloe}
@kibbles.reload @kibbles.reload
assert @kibbles.eater_kittens.empty? assert @kibbles.eater_kittens.empty?
assert_equal 2, @kibbles.eaters.size assert_equal 2, @kibbles.eaters.size
assert !@kibbles.eater_kittens.include?(@chloe) assert !@kibbles.eater_kittens.any? {|obj| obj == @chloe}
assert !@kibbles.eaters.include?(@chloe) assert !@kibbles.eaters.any? {|obj| obj == @chloe}
end end
def test_childrens_individual_collections def test_childrens_individual_collections
@ -316,13 +316,13 @@ class PolymorphTest < Test::Unit::TestCase
def test_namespaced_polymorphic_collection def test_namespaced_polymorphic_collection
@shamu.aquatic_pupils << @swimmy @shamu.aquatic_pupils << @swimmy
assert @shamu.aquatic_pupils.include?(@swimmy) assert @shamu.aquatic_pupils.any? {|obj| obj == @swimmy}
@shamu.reload @shamu.reload
assert @shamu.aquatic_pupils.include?(@swimmy) assert @shamu.aquatic_pupils.any? {|obj| obj == @swimmy}
@shamu.aquatic_pupils << @spot @shamu.aquatic_pupils << @spot
assert @shamu.dogs.include?(@spot) assert @shamu.dogs.any? {|obj| obj == @spot}
assert @shamu.aquatic_pupils.include?(@swimmy) assert @shamu.aquatic_pupils.any? {|obj| obj == @swimmy}
assert_equal @swimmy, @shamu.aquatic_fish.first assert_equal @swimmy, @shamu.aquatic_fish.first
assert_equal 10, @shamu.aquatic_fish.first.speed assert_equal 10, @shamu.aquatic_fish.first.speed
end end
@ -333,8 +333,8 @@ class PolymorphTest < Test::Unit::TestCase
@shamu.reload @shamu.reload
@shamu.aquatic_pupils.delete @spot @shamu.aquatic_pupils.delete @spot
assert !@shamu.dogs.include?(@spot) assert !@shamu.dogs.any? {|obj| obj == @spot}
assert !@shamu.aquatic_pupils.include?(@spot) assert !@shamu.aquatic_pupils.any? {|obj| obj == @spot}
assert_equal 1, @shamu.aquatic_pupils.length assert_equal 1, @shamu.aquatic_pupils.length
end end
@ -357,9 +357,9 @@ class PolymorphTest < Test::Unit::TestCase
@alice.enemies << @spot @alice.enemies << @spot
@alice.reload @alice.reload
@spot.reload @spot.reload
assert @spot.protectors.include?(@alice) assert @spot.protectors.any? {|obj| obj == @alice}
assert @alice.enemies.include?(@spot) assert @alice.enemies.any? {|obj| obj == @spot}
assert !@alice.protectors.include?(@alice) assert !@alice.protectors.any? {|obj| obj == @alice}
assert_equal 1, @alice.beautiful_fight_relationships_as_protector.size assert_equal 1, @alice.beautiful_fight_relationships_as_protector.size
assert_equal 0, @alice.beautiful_fight_relationships_as_enemy.size assert_equal 0, @alice.beautiful_fight_relationships_as_enemy.size
assert_equal 1, @alice.beautiful_fight_relationships.size assert_equal 1, @alice.beautiful_fight_relationships.size
@ -367,7 +367,7 @@ class PolymorphTest < Test::Unit::TestCase
# self reference # self reference
assert_equal 1, @alice.enemies.length assert_equal 1, @alice.enemies.length
@alice.enemies.push @alice @alice.enemies.push @alice
assert @alice.enemies.include?(@alice) assert @alice.enemies.any? {|obj| obj == @alice}
assert_equal 2, @alice.enemies.length assert_equal 2, @alice.enemies.length
@alice.reload @alice.reload
assert_equal 2, @alice.beautiful_fight_relationships_as_protector.size assert_equal 2, @alice.beautiful_fight_relationships_as_protector.size
@ -386,7 +386,7 @@ class PolymorphTest < Test::Unit::TestCase
assert_equal @double_join_count + 1, BeautifulFightRelationship.count assert_equal @double_join_count + 1, BeautifulFightRelationship.count
assert @alice.enemies.reload assert @alice.enemies.reload
assert @alice.enemies.include?(@spot) assert @alice.enemies.any? {|obj| obj == @spot}
end end
def test_double_dependency_injection def test_double_dependency_injection
@ -396,12 +396,12 @@ class PolymorphTest < Test::Unit::TestCase
def test_double_collection_deletion def test_double_collection_deletion
@alice.enemies << @spot @alice.enemies << @spot
@alice.reload @alice.reload
assert @alice.enemies.include?(@spot) assert @alice.enemies.any? {|obj| obj == @spot}
@alice.enemies.delete(@spot) @alice.enemies.delete(@spot)
assert !@alice.enemies.include?(@spot) assert !@alice.enemies.any? {|obj| obj == @spot}
assert @alice.enemies.empty? assert @alice.enemies.empty?
@alice.reload @alice.reload
assert !@alice.enemies.include?(@spot) assert !@alice.enemies.any? {|obj| obj == @spot}
assert @alice.enemies.empty? assert @alice.enemies.empty?
assert_equal 0, @alice.beautiful_fight_relationships.size assert_equal 0, @alice.beautiful_fight_relationships.size
end end
@ -409,12 +409,12 @@ class PolymorphTest < Test::Unit::TestCase
def test_double_collection_deletion_from_opposite_side def test_double_collection_deletion_from_opposite_side
@alice.protectors << @puma @alice.protectors << @puma
@alice.reload @alice.reload
assert @alice.protectors.include?(@puma) assert @alice.protectors.any? {|obj| obj == @puma}
@alice.protectors.delete(@puma) @alice.protectors.delete(@puma)
assert !@alice.protectors.include?(@puma) assert !@alice.protectors.any? {|obj| obj == @puma}
assert @alice.protectors.empty? assert @alice.protectors.empty?
@alice.reload @alice.reload
assert !@alice.protectors.include?(@puma) assert !@alice.protectors.any? {|obj| obj == @puma}
assert @alice.protectors.empty? assert @alice.protectors.empty?
assert_equal 0, @alice.beautiful_fight_relationships.size assert_equal 0, @alice.beautiful_fight_relationships.size
end end
@ -423,59 +423,58 @@ class PolymorphTest < Test::Unit::TestCase
assert @alice.dogs.empty? assert @alice.dogs.empty?
@alice.enemies << @spot @alice.enemies << @spot
assert @alice.enemies.include?(@spot) assert @alice.enemies.any? {|obj| obj == @spot}
assert !@alice.kittens.include?(@alice) assert !@alice.kittens.any? {|obj| obj == @alice}
assert !@alice.dogs.include?(@spot) assert !@alice.dogs.any? {|obj| obj == @spot}
@alice.reload @alice.reload
assert @alice.dogs.include?(@spot) assert @alice.dogs.any? {|obj| obj == @spot}
assert !WildBoar.find(@alice.id).dogs.include?(@spot) # make sure the parent type is checked assert !WildBoar.find(@alice.id).dogs.any? {|obj| obj == @spot} # make sure the parent type is checked
end end
def test_individual_collections_created_for_double_relationship_from_opposite_side def test_individual_collections_created_for_double_relationship_from_opposite_side
assert @alice.wild_boars.empty? assert @alice.wild_boars.empty?
@alice.protectors << @puma @alice.protectors << @puma
assert @alice.protectors.include?(@puma)
assert !@alice.wild_boars.include?(@puma)
@alice.reload @alice.reload
assert @alice.wild_boars.include?(@puma)
assert @alice.protectors.any? {|obj| obj == @puma}
assert @alice.wild_boars.any? {|obj| obj == @puma}
assert !Dog.find(@alice.id).wild_boars.include?(@puma) # make sure the parent type is checked assert !Dog.find(@alice.id).wild_boars.any? {|obj| obj == @puma} # make sure the parent type is checked
end end
def test_self_referential_individual_collections_created_for_double_relationship def test_self_referential_individual_collections_created_for_double_relationship
@alice.enemies << @alice @alice.enemies << @alice
@alice.reload @alice.reload
assert @alice.enemy_kittens.include?(@alice) assert @alice.enemy_kittens.any? {|obj| obj == @alice}
assert @alice.protector_kittens.include?(@alice) assert @alice.protector_kittens.any? {|obj| obj == @alice}
assert @alice.kittens.include?(@alice) assert @alice.kittens.any? {|obj| obj == @alice}
assert_equal 2, @alice.kittens.size assert_equal 2, @alice.kittens.size
@alice.enemies << (@chloe = Kitten.find_by_name('Chloe')) @alice.enemies << (@chloe = Kitten.find_by_name('Chloe'))
@alice.reload @alice.reload
assert @alice.enemy_kittens.include?(@chloe) assert @alice.enemy_kittens.any? {|obj| obj == @chloe}
assert !@alice.protector_kittens.include?(@chloe) assert !@alice.protector_kittens.any? {|obj| obj == @chloe}
assert @alice.kittens.include?(@chloe) assert @alice.kittens.any? {|obj| obj == @chloe}
assert_equal 3, @alice.kittens.size assert_equal 3, @alice.kittens.size
end end
def test_child_of_polymorphic_join_can_reach_parent def test_child_of_polymorphic_join_can_reach_parent
@alice.enemies << @spot @alice.enemies << @spot
@alice.reload @alice.reload
assert @spot.protectors.include?(@alice) assert @spot.protectors.any? {|obj| obj == @alice}
end end
def test_double_collection_deletion_from_child_polymorphic_join def test_double_collection_deletion_from_child_polymorphic_join
@alice.enemies << @spot @alice.enemies << @spot
@spot.protectors.delete(@alice) @spot.protectors.delete(@alice)
assert !@spot.protectors.include?(@alice) assert !@spot.protectors.any? {|obj| obj == @alice}
@alice.reload @alice.reload
assert !@alice.enemies.include?(@spot) assert !@alice.enemies.any? {|obj| obj == @spot}
BeautifulFightRelationship.create(:protector_id => 2, :protector_type => "Dog", :enemy_id => @spot.id, :enemy_type => @spot.class.name) BeautifulFightRelationship.create(:protector_id => 2, :protector_type => "Dog", :enemy_id => @spot.id, :enemy_type => @spot.class.name)
@alice.enemies << @spot @alice.enemies << @spot
@spot.protectors.delete(@alice) @spot.protectors.delete(@alice)
assert !@spot.protectors.include?(@alice) assert !@spot.protectors.any? {|obj| obj == @alice}
end end
def test_collection_query_on_unsaved_record def test_collection_query_on_unsaved_record
@ -486,15 +485,15 @@ class PolymorphTest < Test::Unit::TestCase
def test_double_individual_collections_push def test_double_individual_collections_push
assert_equal [@chloe], (@spot.protector_kittens << @chloe) assert_equal [@chloe], (@spot.protector_kittens << @chloe)
@spot.reload @spot.reload
assert @spot.protectors.include?(@chloe) assert @spot.protectors.any? {|obj| obj == @chloe}
assert @spot.protector_kittens.include?(@chloe) assert @spot.protector_kittens.any? {|obj| obj == @chloe}
assert !@spot.protector_dogs.include?(@chloe) assert !@spot.protector_dogs.any? {|obj| obj == @chloe}
assert_equal [@froggy], (@spot.frogs << @froggy) assert_equal [@froggy], (@spot.frogs << @froggy)
@spot.reload @spot.reload
assert @spot.enemies.include?(@froggy) assert @spot.enemies.any? {|obj| obj == @froggy}
assert @spot.frogs.include?(@froggy) assert @spot.frogs.any? {|obj| obj == @froggy}
assert !@spot.enemy_dogs.include?(@froggy) assert !@spot.enemy_dogs.any? {|obj| obj == @froggy}
end end
def test_double_individual_collections_delete def test_double_individual_collections_delete
@ -506,7 +505,7 @@ class PolymorphTest < Test::Unit::TestCase
@spot.reload @spot.reload
assert @spot.protector_kittens.empty? assert @spot.protector_kittens.empty?
assert @spot.wild_boars.include?(@puma) assert @spot.wild_boars.any? {|obj| obj == @puma}
end end
def test_double_individual_collections_clear def test_double_individual_collections_clear
@ -518,12 +517,12 @@ class PolymorphTest < Test::Unit::TestCase
@spot.reload @spot.reload
assert @spot.protector_kittens.empty? assert @spot.protector_kittens.empty?
assert_equal 1, @spot.protectors.size assert_equal 1, @spot.protectors.size
assert !@spot.protector_kittens.include?(@chloe) assert !@spot.protector_kittens.any? {|obj| obj == @chloe}
assert !@spot.protectors.include?(@chloe) assert !@spot.protectors.any? {|obj| obj == @chloe}
assert !@spot.protector_kittens.include?(@alice) assert !@spot.protector_kittens.any? {|obj| obj == @alice}
assert !@spot.protectors.include?(@alice) assert !@spot.protectors.any? {|obj| obj == @alice}
assert @spot.protectors.include?(@puma) assert @spot.protectors.any? {|obj| obj == @puma}
assert @spot.wild_boars.include?(@puma) assert @spot.wild_boars.any? {|obj| obj == @puma}
end end
def test_single_extensions def test_single_extensions