diff --git a/CHANGELOG b/CHANGELOG
index 38da739..e2a8861 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,5 @@
+* Make sure of use Memcached as test store. Compatibility changes for ActiveRecord 2.2.0
+
* Make sure of require frameworks configured in environment.rb
diff --git a/README b/README
index 46b257d..aa568ba 100644
--- a/README
+++ b/README
@@ -8,7 +8,7 @@ Check for news and tutorials at the {project home page}[http://www.lucaguidi.com
= Usage
-Using Memcached and Rails 2.1.1
+Using Memcached and Rails 2.2.0
Make sure to configure your current environment with:
@@ -77,7 +77,12 @@ Standalone:
require 'cached-models'
ActiveRecord::Base.rails_cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, 'localhost')
-
+
+
+
+= Test
+ Make sure your current store is Memcached
+
= Contribute
diff --git a/lib/activerecord/lib/active_record/associations.rb b/lib/activerecord/lib/active_record/associations.rb
index afe95e6..558e212 100644
--- a/lib/activerecord/lib/active_record/associations.rb
+++ b/lib/activerecord/lib/active_record/associations.rb
@@ -6,107 +6,12 @@
module ActiveRecord
module Associations
module ClassMethods
- # Adds the following methods for retrieval and query of collections of associated objects:
- # +collection+ is replaced with the symbol passed as the first argument, so
- # has_many :clients would add among others clients.empty?.
- # * collection(force_reload = false) - Returns an array of all the associated objects.
- # An empty array is returned if none are found.
- # * collection<<(object, ...) - Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
- # * collection.delete(object, ...) - Removes one or more objects from the collection by setting their foreign keys to +NULL+.
- # This will also destroy the objects if they're declared as +belongs_to+ and dependent on this model.
- # * collection=objects - Replaces the collections content by deleting and adding objects as appropriate.
- # * collection_singular_ids - Returns an array of the associated objects' ids
- # * collection_singular_ids=ids - Replace the collection with the objects identified by the primary keys in +ids+
- # * collection.clear - Removes every object from the collection. This destroys the associated objects if they
- # are associated with :dependent => :destroy, deletes them directly from the database if :dependent => :delete_all,
- # otherwise sets their foreign keys to +NULL+.
- # * collection.empty? - Returns +true+ if there are no associated objects.
- # * collection.size - Returns the number of associated objects.
- # * collection.find - Finds an associated object according to the same rules as Base.find.
- # * collection.build(attributes = {}, ...) - Returns one or more new objects of the collection type that have been instantiated
- # with +attributes+ and linked to this object through a foreign key, but have not yet been saved. *Note:* This only works if an
- # associated object already exists, not if it's +nil+!
- # * collection.create(attributes = {}) - Returns a new object of the collection type that has been instantiated
- # with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation).
- # *Note:* This only works if an associated object already exists, not if it's +nil+!
- #
- # Example: A Firm class declares has_many :clients, which will add:
- # * Firm#clients (similar to Clients.find :all, :conditions => "firm_id = #{id}")
- # * Firm#clients<<
- # * Firm#clients.delete
- # * Firm#clients=
- # * Firm#client_ids
- # * Firm#client_ids=
- # * Firm#clients.clear
- # * Firm#clients.empty? (similar to firm.clients.size == 0)
- # * Firm#clients.size (similar to Client.count "firm_id = #{id}")
- # * Firm#clients.find (similar to Client.find(id, :conditions => "firm_id = #{id}"))
- # * Firm#clients.build (similar to Client.new("firm_id" => id))
- # * Firm#clients.create (similar to c = Client.new("firm_id" => id); c.save; c)
- # The declaration can also include an options hash to specialize the behavior of the association.
- #
- # Options are:
- # * :class_name - Specify the class name of the association. Use it only if that name can't be inferred
- # from the association name. So has_many :products will by default be linked to the Product class, but
- # if the real class name is SpecialProduct, you'll have to specify it with this option.
- # * :conditions - Specify the conditions that the associated objects must meet in order to be included as a +WHERE+
- # SQL fragment, such as price > 5 AND name LIKE 'B%'. Record creations from the association are scoped if a hash
- # is used. has_many :posts, :conditions => {:published => true} will create published posts with @blog.posts.create
- # or @blog.posts.build.
- # * :order - Specify the order in which the associated objects are returned as an ORDER BY SQL fragment,
- # such as last_name, first_name DESC.
- # * :foreign_key - Specify the foreign key used for the association. By default this is guessed to be the name
- # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_many+ association will use "person_id"
- # as the default :foreign_key.
- # * :dependent - If set to :destroy all the associated objects are destroyed
- # alongside this object by calling their +destroy+ method. If set to :delete_all all associated
- # objects are deleted *without* calling their +destroy+ method. If set to :nullify all associated
- # objects' foreign keys are set to +NULL+ *without* calling their +save+ callbacks. *Warning:* This option is ignored when also using
- # the :through option.
- # * :finder_sql - Specify a complete SQL statement to fetch the association. This is a good way to go for complex
- # associations that depend on multiple tables. Note: When this option is used, +find_in_collection+ is _not_ added.
- # * :counter_sql - Specify a complete SQL statement to fetch the size of the association. If :finder_sql is
- # specified but not :counter_sql, :counter_sql will be generated by replacing SELECT ... FROM with SELECT COUNT(*) FROM.
- # * :extend - Specify a named module for extending the proxy. See "Association extensions".
- # * :include - Specify second-order associations that should be eager loaded when the collection is loaded.
- # * :group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
- # * :limit - An integer determining the limit on the number of rows that should be returned.
- # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows.
- # * :select - By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join
- # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will rise an error.
- # * :as - Specifies a polymorphic interface (See belongs_to).
- # * :through - Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key
- # are ignored, as the association uses the source reflection. You can only use a :through query through a belongs_to
- # or has_many association on the join model.
- # * :source - Specifies the source association name used by has_many :through queries. Only use it if the name cannot be
- # inferred from the association. has_many :subscribers, :through => :subscriptions will look for either :subscribers or
- # :subscriber on Subscription, unless a :source is given.
- # * :source_type - Specifies type of the source association used by has_many :through queries where the source
- # association is a polymorphic +belongs_to+.
- # * :uniq - If true, duplicates will be omitted from the collection. Useful in conjunction with :through.
- # * :readonly - If true, all the associated objects are readonly through the association.
- # * :cached - If true, all the associated objects will be cached.
- #
- # Option examples:
- # has_many :comments, :order => "posted_on"
- # has_many :comments, :include => :author
- # has_many :people, :class_name => "Person", :conditions => "deleted = 0", :order => "name"
- # has_many :tracks, :order => "position", :dependent => :destroy
- # has_many :comments, :dependent => :nullify
- # has_many :tags, :as => :taggable
- # has_many :reports, :readonly => true
- # has_many :posts, :cached => true
- # has_many :subscribers, :through => :subscriptions, :source => :user
- # has_many :subscribers, :class_name => "Person", :finder_sql =>
- # 'SELECT DISTINCT people.* ' +
- # 'FROM people p, post_subscriptions ps ' +
- # 'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' +
- # 'ORDER BY p.first_name'
- def has_many(association_id, options = {}, &extension)
+ def has_many(association_id, options = {}, &extension) #:nodoc:
reflection = create_has_many_reflection(association_id, options, &extension)
configure_dependency_for_has_many(reflection)
+ add_multiple_associated_validation_callbacks(reflection.name) unless options[:validate] == false
add_multiple_associated_save_callbacks(reflection.name)
add_association_callbacks(reflection.name, reflection.options)
@@ -116,70 +21,10 @@ def has_many(association_id, options = {}, &extension)
collection_accessor_methods(reflection, HasManyAssociation, options)
end
- add_cache_callbacks if options[:cached]
+ add_has_many_cache_callbacks if options[:cached]
end
- # Adds the following methods for retrieval and query for a single associated object for which this object holds an id:
- # +association+ is replaced with the symbol passed as the first argument, so
- # belongs_to :author would add among others author.nil?.
- # * association(force_reload = false) - Returns the associated object. +nil+ is returned if none is found.
- # * association=(associate) - Assigns the associate object, extracts the primary key, and sets it as the foreign key.
- # * association.nil? - Returns +true+ if there is no associated object.
- # * build_association(attributes = {}) - Returns a new object of the associated type that has been instantiated
- # with +attributes+ and linked to this object through a foreign key, but has not yet been saved.
- # * create_association(attributes = {}) - Returns a new object of the associated type that has been instantiated
- # with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation).
- #
- # Example: A Post class declares belongs_to :author, which will add:
- # * Post#author (similar to Author.find(author_id))
- # * Post#author=(author) (similar to post.author_id = author.id)
- # * Post#author? (similar to post.author == some_author)
- # * Post#author.nil?
- # * Post#build_author (similar to post.author = Author.new)
- # * Post#create_author (similar to post.author = Author.new; post.author.save; post.author)
- # The declaration can also include an options hash to specialize the behavior of the association.
- #
- # Options are:
- # * :class_name - Specify the class name of the association. Use it only if that name can't be inferred
- # from the association name. So has_one :author will by default be linked to the Author class, but
- # if the real class name is Person, you'll have to specify it with this option.
- # * :conditions - Specify the conditions that the associated object must meet in order to be included as a +WHERE+
- # SQL fragment, such as authorized = 1.
- # * :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join
- # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error.
- # * :foreign_key - Specify the foreign key used for the association. By default this is guessed to be the name
- # of the association with an "_id" suffix. So a class that defines a belongs_to :person association will use
- # "person_id" as the default :foreign_key. Similarly, belongs_to :favorite_person, :class_name => "Person"
- # will use a foreign key of "favorite_person_id".
- # * :dependent - If set to :destroy, the associated object is destroyed when this object is. If set to
- # :delete, the associated object is deleted *without* calling its destroy method. This option should not be specified when
- # belongs_to is used in conjunction with a has_many relationship on another class because of the potential to leave
- # orphaned records behind.
- # * :counter_cache - Caches the number of belonging objects on the associate class through the use of +increment_counter+
- # and +decrement_counter+. The counter cache is incremented when an object of this class is created and decremented when it's
- # destroyed. This requires that a column named #{table_name}_count (such as +comments_count+ for a belonging Comment class)
- # is used on the associate class (such as a Post class). You can also specify a custom counter cache column by providing
- # a column name instead of a +true+/+false+ value to this option (e.g., :counter_cache => :my_custom_counter.)
- # When creating a counter cache column, the database statement or migration must specify a default value of 0, failing to do
- # this results in a counter with +NULL+ value, which will never increment.
- # Note: Specifying a counter cache will add it to that model's list of readonly attributes using +attr_readonly+.
- # * :include - Specify second-order associations that should be eager loaded when this object is loaded.
- # * :polymorphic - Specify this association is a polymorphic association by passing +true+.
- # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
- # to the +attr_readonly+ list in the associated classes (e.g. class Post; attr_readonly :comments_count; end).
- # * :readonly - If true, the associated object is readonly through the association.
- # * :validate - If false, don't validate the associated objects when saving the parent object. +false+ by default.
- #
- # Option examples:
- # belongs_to :firm, :foreign_key => "client_of"
- # belongs_to :author, :class_name => "Person", :foreign_key => "author_id"
- # belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id",
- # :conditions => 'discounts > #{payments_count}'
- # belongs_to :attachable, :polymorphic => true
- # belongs_to :project, :readonly => true
- # belongs_to :post, :counter_cache => true
- # belongs_to :blog, :cached => true
- def belongs_to(association_id, options = {})
+ def belongs_to(association_id, options = {}) #:nodoc:
reflection = create_belongs_to_reflection(association_id, options)
ivar = "@#{reflection.name}"
@@ -189,7 +34,7 @@ def belongs_to(association_id, options = {})
method_name = "polymorphic_belongs_to_before_save_for_#{reflection.name}".to_sym
define_method(method_name) do
- association = instance_variable_get("#{ivar}") if instance_variable_defined?("#{ivar}")
+ association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
if association && association.target
if association.new_record?
@@ -197,8 +42,8 @@ def belongs_to(association_id, options = {})
end
if association.updated?
- self["#{reflection.primary_key_name}"] = association.id
- self["#{reflection.options[:foreign_type]}"] = association.class.base_class.name.to_s
+ self[reflection.primary_key_name] = association.id
+ self[reflection.options[:foreign_type]] = association.class.base_class.name.to_s
end
end
end
@@ -210,7 +55,7 @@ def belongs_to(association_id, options = {})
method_name = "belongs_to_before_save_for_#{reflection.name}".to_sym
define_method(method_name) do
- association = instance_variable_get("#{ivar}") if instance_variable_defined?("#{ivar}")
+ association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
if !association.nil?
if association.new_record?
@@ -218,7 +63,7 @@ def belongs_to(association_id, options = {})
end
if association.updated?
- self["#{reflection.primary_key_name}"] = association.id
+ self[reflection.primary_key_name] = association.id
end
end
end
@@ -233,15 +78,15 @@ def belongs_to(association_id, options = {})
method_name = "belongs_to_counter_cache_after_create_for_#{reflection.name}".to_sym
define_method(method_name) do
- association = send("#{reflection.name}")
- association.class.increment_counter("#{cache_column}", send("#{reflection.primary_key_name}")) unless association.nil?
+ association = send(reflection.name)
+ association.class.increment_counter(cache_column, send(reflection.primary_key_name)) unless association.nil?
end
after_create method_name
method_name = "belongs_to_counter_cache_before_destroy_for_#{reflection.name}".to_sym
define_method(method_name) do
- association = send("#{reflection.name}")
- association.class.decrement_counter("#{cache_column}", send("#{reflection.primary_key_name}")) unless association.nil?
+ association = send(reflection.name)
+ association.class.decrement_counter(cache_column, send(reflection.primary_key_name)) unless association.nil?
end
before_destroy method_name
@@ -250,17 +95,7 @@ def belongs_to(association_id, options = {})
)
end
- if options[:cached]
- after_save_method_name = "belongs_to_after_save_for_#{reflection.name}".to_sym
- after_destroy_method_name = "belongs_to_after_destroy_for_#{reflection.name}".to_sym
- define_method(after_save_method_name) do
- send(reflection.name).expire_cache_for(self.class.name)
- end
-
- alias_method after_destroy_method_name, after_save_method_name
- after_save after_save_method_name
- after_destroy after_destroy_method_name
- end
+ add_belongs_to_cache_callbacks(association_id) if options[:cached]
add_single_associated_validation_callbacks(reflection.name) if options[:validate] == true
@@ -300,17 +135,19 @@ def collection_reader_method(reflection, association_proxy_class, options)
define_method(method_name) do
if options[:cached]
cache_fetch("#{cache_key}/#{method_name}", send("calculate_#{method_name}"))
- else
+ elsif send(reflection.name).loaded? || reflection.options[:finder_sql]
send("calculate_#{method_name}")
+ else
+ send(reflection.name).all(:select => "#{reflection.quoted_table_name}.#{reflection.klass.primary_key}").map(&:id)
end
end
-
+
define_method("calculate_#{method_name}") do
- send(reflection.name).map { |record| record.id }
+ send(reflection.name).map(&:id)
end
end
- def has_and_belongs_to_many(association_id, options = {}, &extension)
+ def has_and_belongs_to_many(association_id, options = {}, &extension) #:nodoc:
reflection = create_has_and_belongs_to_many_reflection(association_id, options, &extension)
add_multiple_associated_validation_callbacks(reflection.name) unless options[:validate] == false
@@ -352,42 +189,11 @@ def collection_accessor_methods(reflection, association_proxy_class, options, wr
end
end
- def create_has_many_reflection(association_id, options, &extension)
- options.assert_valid_keys(
- :class_name, :table_name, :foreign_key, :primary_key,
- :dependent,
- :select, :conditions, :include, :order, :group, :limit, :offset,
- :as, :through, :source, :source_type,
- :uniq,
- :finder_sql, :counter_sql,
- :before_add, :after_add, :before_remove, :after_remove,
- :extend, :readonly,
- :validate, :accessible,
- :cached
- )
-
- options[:extend] = create_extension_modules(association_id, extension, options[:extend])
-
- create_reflection(:has_many, association_id, options, self)
- end
-
- def create_belongs_to_reflection(association_id, options)
- options.assert_valid_keys(
- :class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent,
- :counter_cache, :extend, :polymorphic, :readonly, :validate, :cached
- )
+ valid_keys_for_has_many_association << :cached
+ valid_keys_for_belongs_to_association << :cached
- reflection = create_reflection(:belongs_to, association_id, options, self)
-
- if options[:polymorphic]
- reflection.options[:foreign_type] ||= reflection.class_name.underscore + "_type"
- end
-
- reflection
- end
-
- def add_cache_callbacks
- method_name = :after_save_cache_expire
+ def add_has_many_cache_callbacks
+ method_name = :has_many_after_save_cache_expire
return if respond_to? method_name
define_method(method_name) do
@@ -399,6 +205,20 @@ def add_cache_callbacks
end
after_save method_name
end
+
+ def add_belongs_to_cache_callbacks(reflection_name)
+ after_save_method_name = "belongs_to_after_save_for_#{reflection_name}".to_sym
+ after_destroy_method_name = "belongs_to_after_destroy_for_#{reflection_name}".to_sym
+ return if respond_to? after_save_method_name
+
+ define_method(after_save_method_name) do
+ send(reflection_name).expire_cache_for(self.class.name)
+ end
+
+ alias_method after_destroy_method_name, after_save_method_name
+ after_save after_save_method_name
+ after_destroy after_destroy_method_name
+ end
end
end
end
diff --git a/lib/activerecord/lib/active_record/associations/association_collection.rb b/lib/activerecord/lib/active_record/associations/association_collection.rb
index 7d61063..c5c94a0 100644
--- a/lib/activerecord/lib/active_record/associations/association_collection.rb
+++ b/lib/activerecord/lib/active_record/associations/association_collection.rb
@@ -54,7 +54,7 @@ def <<(*records)
result = true
load_target if @owner.new_record?
- @owner.transaction do
+ transaction do
flatten_deeper(records).each do |record|
raise_on_type_mismatch(record)
add_record_to_target_with_callbacks(record) do |r|
@@ -68,12 +68,18 @@ def <<(*records)
result && self
end
- # Remove +records+ from this association. Does not destroy +records+.
+ # Removes +records+ from this association calling +before_remove+ and
+ # +after_remove+ callbacks.
+ #
+ # This method is abstract in the sense that +delete_records+ has to be
+ # provided by descendants. Note this method does not imply the records
+ # are actually removed from the database, that depends precisely on
+ # +delete_records+. They are in any case removed from the collection.
def delete(*records)
records = flatten_deeper(records)
records.each { |record| raise_on_type_mismatch(record) }
- @owner.transaction do
+ transaction do
records.each { |record| callback(:before_remove, record) }
old_records = records.reject {|r| r.new_record? }
@@ -94,7 +100,7 @@ def clear
if @reflection.options[:dependent] && @reflection.options[:dependent] == :destroy
destroy_all
- else
+ else
delete_all
end
@@ -103,9 +109,16 @@ def clear
self
end
- # Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been loaded and
- # calling collection.size if it has. If it's more likely than not that the collection does have a size larger than zero
- # and you need to fetch that collection afterwards, it'll take one less SELECT query if you use length.
+ # Returns the size of the collection by executing a SELECT COUNT(*)
+ # query if the collection hasn't been loaded, and calling
+ # collection.size if it has.
+ #
+ # If the collection has been already loaded +size+ and +length+ are
+ # equivalent. If not and you are going to need the records anyway
+ # +length+ will take one less query. Otherwise +size+ is more efficient.
+ #
+ # This method is abstract in the sense that it relies on
+ # +count_records+, which is a method descendants have to provide.
def size
if @reflection.options[:cached]
returning result = self.to_ary do
@@ -115,6 +128,8 @@ def size
if @owner.new_record? || (loaded? && !@reflection.options[:uniq])
@target.size
+ elsif !loaded? && @reflection.options[:group]
+ load_target.size
elsif !loaded? && !@reflection.options[:uniq] && @target.is_a?(Array)
unsaved_records = @target.select { |r| r.new_record? }
unsaved_records.size + count_records
diff --git a/test/active_record/associations/has_many_association_test.rb b/test/active_record/associations/has_many_association_test.rb
index 3426a9b..1c82dd1 100644
--- a/test/active_record/associations/has_many_association_test.rb
+++ b/test/active_record/associations/has_many_association_test.rb
@@ -216,85 +216,83 @@ def test_should_use_cache_for_collection_include
end
end
- uses_memcached 'HasManyAssociationTest' do
- def test_should_refresh_caches_when_pushing_element_to_association_belonging_to_another_model
- post = authors(:chuck).cached_posts.last
- authors(:luca).cached_posts << post
- assert_equal posts_by_author(:luca), authors(:luca).cached_posts
- assert_equal posts_by_author(:chuck), authors(:chuck).cached_posts
- end
+ def test_should_refresh_caches_when_pushing_element_to_association_belonging_to_another_model
+ post = authors(:chuck).cached_posts.last
+ authors(:luca).cached_posts << post
+ assert_equal posts_by_author(:luca), authors(:luca).cached_posts
+ assert_equal posts_by_author(:chuck), authors(:chuck).cached_posts
+ end
- def test_should_refresh_caches_when_pushing_element_to_polymorphic_association_belonging_to_another_model
- tag = posts(:welcome).cached_tags.last
- posts(:cached_models).cached_tags << tag
+ def test_should_refresh_caches_when_pushing_element_to_polymorphic_association_belonging_to_another_model
+ tag = posts(:welcome).cached_tags.last
+ posts(:cached_models).cached_tags << tag
- # NOTE for some weird reason the assertion fails, even if the collections are equals.
- # I forced the comparision between the ids.
- assert_equal tags_by_post(:cached_models).map(&:id).sort,
- posts(:cached_models).cached_tags.map(&:id).sort
- end
+ # NOTE for some weird reason the assertion fails, even if the collections are equals.
+ # I forced the comparision between the ids.
+ assert_equal tags_by_post(:cached_models).map(&:id).sort,
+ posts(:cached_models).cached_tags.map(&:id).sort
+ end
- def test_should_update_cache_when_pushing_element_with_build
- author = authors(:luca)
- post = author.cached_posts.build post_options
- post.save
- assert_equal posts_by_author(:luca), author.cached_posts
- end
+ def test_should_update_cache_when_pushing_element_with_build
+ author = authors(:luca)
+ post = author.cached_posts.build post_options
+ post.save
+ assert_equal posts_by_author(:luca), author.cached_posts
+ end
- def test_should_update_cache_when_pushing_element_with_create
- author = authors(:luca)
- author.cached_posts.create post_options(:title => "CM Overview")
- assert_equal posts_by_author(:luca), author.cached_posts
- end
+ def test_should_update_cache_when_pushing_element_with_create
+ author = authors(:luca)
+ author.cached_posts.create post_options(:title => "CM Overview")
+ assert_equal posts_by_author(:luca), author.cached_posts
+ end
- def test_should_update_cache_when_pushing_element_with_create_bang_method
- author = authors(:luca)
- author.cached_posts.create! post_options(:title => "CM Overview!!")
- assert_equal posts_by_author(:luca), author.cached_posts
- end
+ def test_should_update_cache_when_pushing_element_with_create_bang_method
+ author = authors(:luca)
+ author.cached_posts.create! post_options(:title => "CM Overview!!")
+ assert_equal posts_by_author(:luca), author.cached_posts
+ end
- def test_should_expire_cache_when_delete_all_elements_from_collection
- authors(:luca).cached_posts.delete_all
- assert_equal posts_by_author(:luca), authors(:luca).cached_posts
- end
+ def test_should_expire_cache_when_delete_all_elements_from_collection
+ authors(:luca).cached_posts.delete_all
+ assert_equal posts_by_author(:luca), authors(:luca).cached_posts
+ end
- def test_should_expire_cache_when_destroy_all_elements_from_collection
- authors(:luca).cached_posts.destroy_all
- assert_equal posts_by_author(:luca), authors(:luca).cached_posts
- end
+ def test_should_expire_cache_when_destroy_all_elements_from_collection
+ authors(:luca).cached_posts.destroy_all
+ assert_equal posts_by_author(:luca), authors(:luca).cached_posts
+ end
- def test_should_update_cache_when_clearing_collection
- authors(:luca).cached_posts.clear
- assert_equal posts_by_author(:luca), authors(:luca).cached_posts
- end
+ def test_should_update_cache_when_clearing_collection
+ authors(:luca).cached_posts.clear
+ assert_equal posts_by_author(:luca), authors(:luca).cached_posts
+ end
- def test_should_update_cache_when_clearing_collection_with_dependent_destroy_option
- authors(:luca).cached_dependent_posts.clear
- assert_equal posts_by_author(:luca), authors(:luca).cached_dependent_posts
- end
+ def test_should_update_cache_when_clearing_collection_with_dependent_destroy_option
+ authors(:luca).cached_dependent_posts.clear
+ assert_equal posts_by_author(:luca), authors(:luca).cached_dependent_posts
+ end
- def test_should_update_cache_when_deleting_element_from_collection
- authors(:luca).cached_posts.delete(posts_by_author(:luca).first)
- assert_equal posts_by_author(:luca), authors(:luca).cached_posts
- end
+ def test_should_update_cache_when_deleting_element_from_collection
+ authors(:luca).cached_posts.delete(posts_by_author(:luca).first)
+ assert_equal posts_by_author(:luca), authors(:luca).cached_posts
+ end
- def test_should_update_cache_when_replace_collection
- post = create_post; post.save
- posts = [ posts_by_author(:luca).first, post ]
- authors(:luca).cached_posts.replace(posts)
- assert_equal posts_by_author(:luca), authors(:luca).cached_posts
- end
+ def test_should_update_cache_when_replace_collection
+ post = create_post; post.save
+ posts = [ posts_by_author(:luca).first, post ]
+ authors(:luca).cached_posts.replace(posts)
+ assert_equal posts_by_author(:luca), authors(:luca).cached_posts
+ end
- def test_should_not_expire_cache_on_update_on_missing_updated_at
- author = authors(:luca)
- old_cache_key = author.cache_key
+ def test_should_not_expire_cache_on_update_on_missing_updated_at
+ author = authors(:luca)
+ old_cache_key = author.cache_key
- author.cached_posts # force cache loading
- author.update_attributes :first_name => author.first_name.upcase
+ author.cached_posts # force cache loading
+ author.update_attributes :first_name => author.first_name.upcase
- # assert_not_equal old_cache_key, author.cache_key
- assert_equal posts_by_author(:luca), authors(:luca).cached_posts
- end
+ # assert_not_equal old_cache_key, author.cache_key
+ assert_equal posts_by_author(:luca), authors(:luca).cached_posts
end
private
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 4558521..261a1eb 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -18,6 +18,18 @@
Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures"
ActionController::IntegrationTest.fixture_path = Test::Unit::TestCase.fixture_path
+silence_warnings do
+ cache = ActiveSupport::Cache.lookup_store :mem_cache_store
+ Object.const_set "RAILS_CACHE", cache
+ ActiveRecord::Base.rails_cache = cache
+end
+
+begin
+ require 'memcache'
+ MemCache.new('localhost').stats
+rescue MemCache::MemCacheError
+ $stderr.puts "[WARNING] Memcache is not running!"
+end
module WillPaginate #:nodoc:
def paginate(*args)
@@ -65,14 +77,6 @@ def uses_mocha(description)
$stderr.puts "Skipping #{description} tests. `gem install mocha` and try again."
end
-def uses_memcached(description)
- require 'memcache'
- MemCache.new('localhost').stats
- yield
-rescue MemCache::MemCacheError
- $stderr.puts "Skipping #{description} tests. Start memcached and try again."
-end
-
if ENV['SKIP_MOCHA'] == 'true'
class Object
def expects(*args)