aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionmailer/CHANGELOG5
-rw-r--r--actionmailer/lib/action_mailer/base.rb23
-rw-r--r--actionmailer/lib/action_mailer/version.rb2
-rw-r--r--actionmailer/test/abstract_unit.rb8
-rw-r--r--actionmailer/test/mail_service_test.rb26
-rw-r--r--actionpack/CHANGELOG8
-rw-r--r--actionpack/lib/action_controller/base.rb2
-rw-r--r--actionpack/lib/action_controller/dispatcher.rb1
-rw-r--r--actionpack/lib/action_controller/mime_type.rb20
-rw-r--r--actionpack/lib/action_controller/polymorphic_routes.rb2
-rwxr-xr-xactionpack/lib/action_controller/request.rb2
-rw-r--r--actionpack/lib/action_controller/request_forgery_protection.rb2
-rw-r--r--actionpack/lib/action_controller/resources.rb118
-rw-r--r--actionpack/lib/action_controller/routing/builder.rb53
-rw-r--r--actionpack/lib/action_controller/routing/recognition_optimisation.rb2
-rw-r--r--actionpack/lib/action_controller/routing/route.rb2
-rw-r--r--actionpack/lib/action_controller/routing/routing_ext.rb4
-rw-r--r--actionpack/lib/action_controller/routing/segments.rb28
-rw-r--r--actionpack/lib/action_controller/test_process.rb1
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb2
-rw-r--r--actionpack/lib/action_pack/version.rb2
-rw-r--r--actionpack/lib/action_view/helpers/atom_feed_helper.rb13
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb10
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb4
-rw-r--r--actionpack/test/controller/html-scanner/sanitizer_test.rb4
-rw-r--r--actionpack/test/controller/logging_test.rb46
-rw-r--r--actionpack/test/controller/mime_type_test.rb12
-rw-r--r--actionpack/test/controller/polymorphic_routes_test.rb11
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb118
-rw-r--r--actionpack/test/controller/resources_test.rb266
-rw-r--r--actionpack/test/controller/session/cookie_store_test.rb1
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb6
-rw-r--r--actionpack/test/template/atom_feed_helper_test.rb3
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb2
-rw-r--r--actionpack/test/template/tag_helper_test.rb4
-rw-r--r--actionpack/test/template/text_helper_test.rb1
-rw-r--r--activerecord/CHANGELOG2
-rw-r--r--activerecord/lib/active_record/association_preload.rb2
-rwxr-xr-xactiverecord/lib/active_record/associations.rb2
-rwxr-xr-xactiverecord/lib/active_record/base.rb3
-rw-r--r--activerecord/lib/active_record/calculations.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb22
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/abstract_adapter.rb3
-rw-r--r--activerecord/lib/active_record/version.rb2
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb23
-rw-r--r--activerecord/test/cases/calculations_test.rb5
-rw-r--r--activerecord/test/cases/pooled_connections_test.rb16
-rw-r--r--activeresource/CHANGELOG2
-rw-r--r--activeresource/lib/active_resource/version.rb2
-rw-r--r--activesupport/CHANGELOG4
-rw-r--r--activesupport/Rakefile3
-rw-r--r--activesupport/lib/active_support/dependencies.rb12
-rw-r--r--activesupport/lib/active_support/inflector.rb1
-rw-r--r--activesupport/lib/active_support/rescuable.rb8
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb7
-rw-r--r--activesupport/lib/active_support/vendor.rb4
-rw-r--r--activesupport/lib/active_support/vendor/memcache-client-1.5.1/memcache.rb (renamed from activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb)6
-rw-r--r--activesupport/lib/active_support/version.rb2
-rw-r--r--activesupport/test/caching_test.rb6
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb2
-rw-r--r--activesupport/test/dependencies_test.rb10
-rw-r--r--activesupport/test/time_zone_test.rb2
-rw-r--r--railties/CHANGELOG2
-rw-r--r--railties/environments/boot.rb2
-rw-r--r--railties/lib/rails/vendor_gem_source_index.rb4
-rw-r--r--railties/lib/rails/version.rb2
66 files changed, 758 insertions, 219 deletions
diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG
index d8636fd83d..de5aeab07e 100644
--- a/actionmailer/CHANGELOG
+++ b/actionmailer/CHANGELOG
@@ -1,3 +1,8 @@
+*2.2.1 [RC2] (November 14th, 2008)*
+
+* Turn on STARTTLS if it is available in Net::SMTP (added in Ruby 1.8.7) and the SMTP server supports it (This is required for Gmail's SMTP server) #1336 [Grant Hollingworth]
+
+
*2.2.0 [RC1] (October 24th, 2008)*
* Add layout functionality to mailers [Pratik]
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 043f56ba17..19ce77ea5a 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -386,12 +386,15 @@ module ActionMailer #:nodoc:
end
def method_missing(method_symbol, *parameters) #:nodoc:
- match = matches_dynamic_method?(method_symbol)
- case match[1]
- when 'create' then new(match[2], *parameters).mail
- when 'deliver' then new(match[2], *parameters).deliver!
- when 'new' then nil
- else super
+ if match = matches_dynamic_method?(method_symbol)
+ case match[1]
+ when 'create' then new(match[2], *parameters).mail
+ when 'deliver' then new(match[2], *parameters).deliver!
+ when 'new' then nil
+ else super
+ end
+ else
+ super
end
end
@@ -440,7 +443,7 @@ module ActionMailer #:nodoc:
private
def matches_dynamic_method?(method_name) #:nodoc:
method_name = method_name.to_s
- /(create|deliver)_([_a-z]\w*)/.match(method_name) || /^(new)$/.match(method_name)
+ /^(create|deliver)_([_a-z]\w*)/.match(method_name) || /^(new)$/.match(method_name)
end
end
@@ -663,8 +666,10 @@ module ActionMailer #:nodoc:
mail.ready_to_send
sender = mail['return-path'] || mail.from
- Net::SMTP.start(smtp_settings[:address], smtp_settings[:port], smtp_settings[:domain],
- smtp_settings[:user_name], smtp_settings[:password], smtp_settings[:authentication]) do |smtp|
+ smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port])
+ smtp.enable_starttls_auto if smtp.respond_to?(:enable_starttls_auto)
+ smtp.start(smtp_settings[:domain], smtp_settings[:user_name], smtp_settings[:password],
+ smtp_settings[:authentication]) do |smtp|
smtp.sendmail(mail.encoded, sender, destinations)
end
end
diff --git a/actionmailer/lib/action_mailer/version.rb b/actionmailer/lib/action_mailer/version.rb
index 9728d1b4db..7ba13c7df8 100644
--- a/actionmailer/lib/action_mailer/version.rb
+++ b/actionmailer/lib/action_mailer/version.rb
@@ -2,7 +2,7 @@ module ActionMailer
module VERSION #:nodoc:
MAJOR = 2
MINOR = 2
- TINY = 0
+ TINY = 1
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index 905f25c9f7..1617b88c8e 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -24,11 +24,15 @@ class MockSMTP
def sendmail(mail, from, to)
@@deliveries << [mail, from, to]
end
+
+ def start(*args)
+ yield self
+ end
end
class Net::SMTP
- def self.start(*args)
- yield MockSMTP.new
+ def self.new(*args)
+ MockSMTP.new
end
end
diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb
index 7f9540c44b..b88beb3314 100644
--- a/actionmailer/test/mail_service_test.rb
+++ b/actionmailer/test/mail_service_test.rb
@@ -938,6 +938,20 @@ EOF
mail = TestMailer.create_body_ivar(@recipient)
assert_equal "body: foo\nbar: baz", mail.body
end
+
+ def test_starttls_is_enabled_if_supported
+ MockSMTP.any_instance.expects(:respond_to?).with(:enable_starttls_auto).returns(true)
+ MockSMTP.any_instance.expects(:enable_starttls_auto)
+ ActionMailer::Base.delivery_method = :smtp
+ TestMailer.deliver_signed_up(@recipient)
+ end
+
+ def test_starttls_is_disabled_if_not_supported
+ MockSMTP.any_instance.expects(:respond_to?).with(:enable_starttls_auto).returns(false)
+ MockSMTP.any_instance.expects(:enable_starttls_auto).never
+ ActionMailer::Base.delivery_method = :smtp
+ TestMailer.deliver_signed_up(@recipient)
+ end
end
end # uses_mocha
@@ -1031,4 +1045,16 @@ class RespondToTest < Test::Unit::TestCase
def test_should_not_respond_to_deliver_with_template_suffix_if_it_begins_with_a_digit
assert !RespondToMailer.respond_to?(:deliver_1_template)
end
+
+ def test_should_not_respond_to_method_where_deliver_is_not_a_suffix
+ assert !RespondToMailer.respond_to?(:foo_deliver_template)
+ end
+
+ def test_should_still_raise_exception_with_expected_message_when_calling_an_undefined_method
+ error = assert_raises NoMethodError do
+ RespondToMailer.not_a_method
+ end
+
+ assert_match /undefined method.*not_a_method/, error.message
+ end
end
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 3ce6522535..dc7ee64358 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,4 +1,10 @@
-*2.2.1 [RC2 or 2.2 final]*
+*2.2.1 [RC2] (November 14th, 2008)*
+
+* Added render :js for people who want to render inline JavaScript replies without using RJS [DHH]
+
+* Fixed that polymorphic_url should compact given array #1317 [hiroshi]
+
+* Fixed the sanitize helper to avoid double escaping already properly escaped entities #683 [antonmos/Ryan McGeary]
* Fixed that FormTagHelper generated illegal html if name contained square brackets #1238 [Vladimir Dobriakov]
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 389ade425b..f35c42f929 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -1241,7 +1241,7 @@ module ActionController #:nodoc:
parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup
parameters = parameters.except!(:controller, :action, :format, :_method)
- logger.info " Parameters: #{parameters.inspect}"
+ logger.info " Parameters: #{parameters.inspect}" unless parameters.empty?
end
def default_render #:nodoc:
diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb
index f3e173004a..2d5e80f0bb 100644
--- a/actionpack/lib/action_controller/dispatcher.rb
+++ b/actionpack/lib/action_controller/dispatcher.rb
@@ -23,7 +23,6 @@ module ActionController
if defined?(ActiveRecord)
after_dispatch :checkin_connections
- before_dispatch { ActiveRecord::Base.verify_active_connections! }
to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers }
end
diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb
index 26edca3b69..8ca3a70341 100644
--- a/actionpack/lib/action_controller/mime_type.rb
+++ b/actionpack/lib/action_controller/mime_type.rb
@@ -20,8 +20,20 @@ module Mime
# end
class Type
@@html_types = Set.new [:html, :all]
+ cattr_reader :html_types
+
+ # These are the content types which browsers can generate without using ajax, flash, etc
+ # i.e. following a link, getting an image or posting a form. CSRF protection
+ # only needs to protect against these types.
+ @@browser_generated_types = Set.new [:html, :url_encoded_form, :multipart_form]
+ cattr_reader :browser_generated_types
+
+
@@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml]
- cattr_reader :html_types, :unverifiable_types
+ def self.unverifiable_types
+ ActiveSupport::Deprecation.warn("unverifiable_types is deprecated and has no effect", caller)
+ @@unverifiable_types
+ end
# A simple helper class used in parsing the accept header
class AcceptItem #:nodoc:
@@ -167,13 +179,17 @@ module Mime
# Returns true if Action Pack should check requests using this Mime Type for possible request forgery. See
# ActionController::RequestForgerProtection.
def verify_request?
- !@@unverifiable_types.include?(to_sym)
+ browser_generated?
end
def html?
@@html_types.include?(to_sym) || @string =~ /html/
end
+ def browser_generated?
+ @@browser_generated_types.include?(to_sym)
+ end
+
private
def method_missing(method, *args)
if method.to_s =~ /(\w+)\?$/
diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb
index cc228c4230..2644c7f7c7 100644
--- a/actionpack/lib/action_controller/polymorphic_routes.rb
+++ b/actionpack/lib/action_controller/polymorphic_routes.rb
@@ -73,7 +73,7 @@ module ActionController
#
def polymorphic_url(record_or_hash_or_array, options = {})
if record_or_hash_or_array.kind_of?(Array)
- record_or_hash_or_array = record_or_hash_or_array.dup
+ record_or_hash_or_array = record_or_hash_or_array.compact
end
record = extract_record(record_or_hash_or_array)
diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb
index a6d4abf029..c079895683 100755
--- a/actionpack/lib/action_controller/request.rb
+++ b/actionpack/lib/action_controller/request.rb
@@ -13,7 +13,7 @@ module ActionController
ActiveSupport::Deprecation.warn(
"ActionController::AbstractRequest.relative_url_root= has been renamed." +
"You can now set it with config.action_controller.relative_url_root=", caller)
- ActionController::base.relative_url_root=relative_url_root
+ ActionController::Base.relative_url_root=relative_url_root
end
HTTP_METHODS = %w(get head put post delete options)
diff --git a/actionpack/lib/action_controller/request_forgery_protection.rb b/actionpack/lib/action_controller/request_forgery_protection.rb
index 05a6d8bb79..3e0e94a06b 100644
--- a/actionpack/lib/action_controller/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/request_forgery_protection.rb
@@ -99,7 +99,7 @@ module ActionController #:nodoc:
end
def verifiable_request_format?
- request.content_type.nil? || request.content_type.verify_request?
+ !request.content_type.nil? && request.content_type.verify_request?
end
# Sets the token value for the current session. Pass a <tt>:secret</tt> option
diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb
index 872b0dab3d..7700b9d4d0 100644
--- a/actionpack/lib/action_controller/resources.rb
+++ b/actionpack/lib/action_controller/resources.rb
@@ -42,7 +42,11 @@ module ActionController
#
# Read more about REST at http://en.wikipedia.org/wiki/Representational_State_Transfer
module Resources
+ INHERITABLE_OPTIONS = :namespace, :shallow, :actions
+
class Resource #:nodoc:
+ DEFAULT_ACTIONS = :index, :create, :new, :edit, :show, :update, :destroy
+
attr_reader :collection_methods, :member_methods, :new_methods
attr_reader :path_prefix, :name_prefix, :path_segment
attr_reader :plural, :singular
@@ -57,6 +61,7 @@ module ActionController
arrange_actions
add_default_actions
+ set_allowed_actions
set_prefixes
end
@@ -113,6 +118,10 @@ module ActionController
@singular.to_s == @plural.to_s
end
+ def has_action?(action)
+ !DEFAULT_ACTIONS.include?(action) || @options[:actions].nil? || @options[:actions].include?(action)
+ end
+
protected
def arrange_actions
@collection_methods = arrange_actions_by_methods(options.delete(:collection))
@@ -125,6 +134,25 @@ module ActionController
add_default_action(new_methods, :get, :new)
end
+ def set_allowed_actions
+ only = @options.delete(:only)
+ except = @options.delete(:except)
+
+ if only && except
+ raise ArgumentError, 'Please supply either :only or :except, not both.'
+ elsif only == :all || except == :none
+ options[:actions] = DEFAULT_ACTIONS
+ elsif only == :none || except == :all
+ options[:actions] = []
+ elsif only
+ options[:actions] = DEFAULT_ACTIONS & Array(only).map(&:to_sym)
+ elsif except
+ options[:actions] = DEFAULT_ACTIONS - Array(except).map(&:to_sym)
+ else
+ # leave options[:actions] alone
+ end
+ end
+
def set_prefixes
@path_prefix = options.delete(:path_prefix)
@name_prefix = options.delete(:name_prefix)
@@ -353,6 +381,25 @@ module ActionController
#
# map.resources :users, :has_many => { :posts => :comments }, :shallow => true
#
+ # * <tt>:only</tt> and <tt>:except</tt> - Specify which of the seven default actions should be routed to.
+ #
+ # <tt>:only</tt> and <tt>:except</tt> may be set to <tt>:all</tt>, <tt>:none</tt>, an action name or a
+ # list of action names. By default, routes are generated for all seven actions.
+ #
+ # For example:
+ #
+ # map.resources :posts, :only => [:index, :show] do |post|
+ # post.resources :comments, :except => [:update, :destroy]
+ # end
+ # # --> GET /posts (maps to the PostsController#index action)
+ # # --> POST /posts (fails)
+ # # --> GET /posts/1 (maps to the PostsController#show action)
+ # # --> DELETE /posts/1 (fails)
+ # # --> POST /posts/1/comments (maps to the CommentsController#create action)
+ # # --> PUT /posts/1/comments/1 (fails)
+ #
+ # The <tt>:only</tt> and <tt>:except</tt> options are inherited by any nested resource(s).
+ #
# If <tt>map.resources</tt> is called with multiple resources, they all get the same options applied.
#
# Examples:
@@ -478,7 +525,7 @@ module ActionController
map_associations(resource, options)
if block_given?
- with_options(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], :shallow => options[:shallow], &block)
+ with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
end
end
end
@@ -495,7 +542,7 @@ module ActionController
map_associations(resource, options)
if block_given?
- with_options(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], :shallow => options[:shallow], &block)
+ with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
end
end
end
@@ -507,7 +554,7 @@ module ActionController
name_prefix = "#{options.delete(:name_prefix)}#{resource.nesting_name_prefix}"
Array(options[:has_one]).each do |association|
- resource(association, :path_prefix => path_prefix, :name_prefix => name_prefix, :namespace => options[:namespace], :shallow => options[:shallow])
+ resource(association, options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => path_prefix, :name_prefix => name_prefix))
end
end
@@ -522,7 +569,7 @@ module ActionController
map_has_many_associations(resource, association, options)
end
when Symbol, String
- resources(associations, :path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], :shallow => options[:shallow], :has_many => options[:has_many])
+ resources(associations, options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :has_many => options[:has_many]))
else
end
end
@@ -531,41 +578,39 @@ module ActionController
resource.collection_methods.each do |method, actions|
actions.each do |action|
[method].flatten.each do |m|
- action_options = action_options_for(action, resource, m)
- map_named_routes(map, "#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}", action_options)
+ map_resource_routes(map, resource, action, "#{resource.path}#{resource.action_separator}#{action}", "#{action}_#{resource.name_prefix}#{resource.plural}", m)
end
end
end
end
def map_default_collection_actions(map, resource)
- index_action_options = action_options_for("index", resource)
index_route_name = "#{resource.name_prefix}#{resource.plural}"
if resource.uncountable?
index_route_name << "_index"
end
- map_named_routes(map, index_route_name, resource.path, index_action_options)
-
- create_action_options = action_options_for("create", resource)
- map_unnamed_routes(map, resource.path, create_action_options)
+ map_resource_routes(map, resource, :index, resource.path, index_route_name)
+ map_resource_routes(map, resource, :create, resource.path, index_route_name)
end
def map_default_singleton_actions(map, resource)
- create_action_options = action_options_for("create", resource)
- map_unnamed_routes(map, resource.path, create_action_options)
+ map_resource_routes(map, resource, :create, resource.path, "#{resource.shallow_name_prefix}#{resource.singular}")
end
def map_new_actions(map, resource)
resource.new_methods.each do |method, actions|
actions.each do |action|
- action_options = action_options_for(action, resource, method)
- if action == :new
- map_named_routes(map, "new_#{resource.name_prefix}#{resource.singular}", resource.new_path, action_options)
- else
- map_named_routes(map, "#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}#{resource.action_separator}#{action}", action_options)
+ route_path = resource.new_path
+ route_name = "new_#{resource.name_prefix}#{resource.singular}"
+
+ unless action == :new
+ route_path = "#{route_path}#{resource.action_separator}#{action}"
+ route_name = "#{action}_#{route_name}"
end
+
+ map_resource_routes(map, resource, action, route_path, route_name, method)
end
end
end
@@ -574,34 +619,33 @@ module ActionController
resource.member_methods.each do |method, actions|
actions.each do |action|
[method].flatten.each do |m|
- action_options = action_options_for(action, resource, m)
-
action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
action_path ||= Base.resources_path_names[action] || action
- map_named_routes(map, "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action_path}", action_options)
+ map_resource_routes(map, resource, action, "#{resource.member_path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", m)
end
end
end
- show_action_options = action_options_for("show", resource)
- map_named_routes(map, "#{resource.shallow_name_prefix}#{resource.singular}", resource.member_path, show_action_options)
-
- update_action_options = action_options_for("update", resource)
- map_unnamed_routes(map, resource.member_path, update_action_options)
-
- destroy_action_options = action_options_for("destroy", resource)
- map_unnamed_routes(map, resource.member_path, destroy_action_options)
- end
-
- def map_unnamed_routes(map, path_without_format, options)
- map.connect(path_without_format, options)
- map.connect("#{path_without_format}.:format", options)
+ route_path = "#{resource.shallow_name_prefix}#{resource.singular}"
+ map_resource_routes(map, resource, :show, resource.member_path, route_path)
+ map_resource_routes(map, resource, :update, resource.member_path, route_path)
+ map_resource_routes(map, resource, :destroy, resource.member_path, route_path)
end
- def map_named_routes(map, name, path_without_format, options)
- map.named_route(name, path_without_format, options)
- map.named_route("formatted_#{name}", "#{path_without_format}.:format", options)
+ def map_resource_routes(map, resource, action, route_path, route_name = nil, method = nil)
+ if resource.has_action?(action)
+ action_options = action_options_for(action, resource, method)
+ formatted_route_path = "#{route_path}.:format"
+
+ if route_name && @set.named_routes[route_name.to_sym].nil?
+ map.named_route(route_name, route_path, action_options)
+ map.named_route("formatted_#{route_name}", formatted_route_path, action_options)
+ else
+ map.connect(route_path, action_options)
+ map.connect(formatted_route_path, action_options)
+ end
+ end
end
def add_conditions_for(conditions, method)
diff --git a/actionpack/lib/action_controller/routing/builder.rb b/actionpack/lib/action_controller/routing/builder.rb
index 7b888fa8d2..d4e501e780 100644
--- a/actionpack/lib/action_controller/routing/builder.rb
+++ b/actionpack/lib/action_controller/routing/builder.rb
@@ -1,23 +1,16 @@
module ActionController
module Routing
class RouteBuilder #:nodoc:
- attr_accessor :separators, :optional_separators
+ attr_reader :separators, :optional_separators
+ attr_reader :separator_regexp, :nonseparator_regexp, :interval_regexp
def initialize
- self.separators = Routing::SEPARATORS
- self.optional_separators = %w( / )
- end
-
- def separator_pattern(inverted = false)
- "[#{'^' if inverted}#{Regexp.escape(separators.join)}]"
- end
-
- def interval_regexp
- Regexp.new "(.*?)(#{separators.source}|$)"
- end
+ @separators = Routing::SEPARATORS
+ @optional_separators = %w( / )
- def multiline_regexp?(expression)
- expression.options & Regexp::MULTILINE == Regexp::MULTILINE
+ @separator_regexp = /[#{Regexp.escape(separators.join)}]/
+ @nonseparator_regexp = /\A([^#{Regexp.escape(separators.join)}]+)/
+ @interval_regexp = /(.*?)(#{separator_regexp}|$)/
end
# Accepts a "route path" (a string defining a route), and returns the array
@@ -30,7 +23,7 @@ module ActionController
rest, segments = path, []
until rest.empty?
- segment, rest = segment_for rest
+ segment, rest = segment_for(rest)
segments << segment
end
segments
@@ -39,20 +32,20 @@ module ActionController
# A factory method that returns a new segment instance appropriate for the
# format of the given string.
def segment_for(string)
- segment = case string
- when /\A:(\w+)/
- key = $1.to_sym
- case key
- when :controller then ControllerSegment.new(key)
- else DynamicSegment.new key
- end
- when /\A\*(\w+)/ then PathSegment.new($1.to_sym, :optional => true)
- when /\A\?(.*?)\?/
- StaticSegment.new($1, :optional => true)
- when /\A(#{separator_pattern(:inverted)}+)/ then StaticSegment.new($1)
- when Regexp.new(separator_pattern) then
- DividerSegment.new($&, :optional => (optional_separators.include? $&))
- end
+ segment =
+ case string
+ when /\A:(\w+)/
+ key = $1.to_sym
+ key == :controller ? ControllerSegment.new(key) : DynamicSegment.new(key)
+ when /\A\*(\w+)/
+ PathSegment.new($1.to_sym, :optional => true)
+ when /\A\?(.*?)\?/
+ StaticSegment.new($1, :optional => true)
+ when nonseparator_regexp
+ StaticSegment.new($1)
+ when separator_regexp
+ DividerSegment.new($&, :optional => optional_separators.include?($&))
+ end
[segment, $~.post_match]
end
@@ -98,7 +91,7 @@ module ActionController
if requirement.source =~ %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
end
- if multiline_regexp?(requirement)
+ if requirement.multiline?
raise ArgumentError, "Regexp multiline option not allowed in routing requirements: #{requirement.inspect}"
end
segment.regexp = requirement
diff --git a/actionpack/lib/action_controller/routing/recognition_optimisation.rb b/actionpack/lib/action_controller/routing/recognition_optimisation.rb
index 6c47ced6d1..3b98b16683 100644
--- a/actionpack/lib/action_controller/routing/recognition_optimisation.rb
+++ b/actionpack/lib/action_controller/routing/recognition_optimisation.rb
@@ -148,7 +148,7 @@ module ActionController
end
nil
end
- }, __FILE__, __LINE__
+ }, '(recognize_optimized)', 1
end
def clear_recognize_optimized!
diff --git a/actionpack/lib/action_controller/routing/route.rb b/actionpack/lib/action_controller/routing/route.rb
index 3b2cb28545..a610ec7e84 100644
--- a/actionpack/lib/action_controller/routing/route.rb
+++ b/actionpack/lib/action_controller/routing/route.rb
@@ -219,7 +219,7 @@ module ActionController
next_capture = 1
extraction = segments.collect do |segment|
x = segment.match_extraction(next_capture)
- next_capture += Regexp.new(segment.regexp_chunk).number_of_captures
+ next_capture += segment.number_of_captures
x
end
extraction.compact
diff --git a/actionpack/lib/action_controller/routing/routing_ext.rb b/actionpack/lib/action_controller/routing/routing_ext.rb
index 5f4ba90d0c..4a82b2af5f 100644
--- a/actionpack/lib/action_controller/routing/routing_ext.rb
+++ b/actionpack/lib/action_controller/routing/routing_ext.rb
@@ -27,6 +27,10 @@ class Regexp #:nodoc:
Regexp.new("|#{source}").match('').captures.length
end
+ def multiline?
+ options & MULTILINE == MULTILINE
+ end
+
class << self
def optionalize(pattern)
case unoptionalize(pattern)
diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb
index e5f174ae2c..f6b03edcca 100644
--- a/actionpack/lib/action_controller/routing/segments.rb
+++ b/actionpack/lib/action_controller/routing/segments.rb
@@ -13,6 +13,10 @@ module ActionController
@is_optional = false
end
+ def number_of_captures
+ Regexp.new(regexp_chunk).number_of_captures
+ end
+
def extraction_code
nil
end
@@ -84,6 +88,10 @@ module ActionController
optional? ? Regexp.optionalize(chunk) : chunk
end
+ def number_of_captures
+ 0
+ end
+
def build_pattern(pattern)
escaped = Regexp.escape(value)
if optional? && ! pattern.empty?
@@ -194,10 +202,16 @@ module ActionController
end
end
+ def number_of_captures
+ if regexp
+ regexp.number_of_captures + 1
+ else
+ 1
+ end
+ end
+
def build_pattern(pattern)
- chunk = regexp_chunk
- chunk = "(#{chunk})" if Regexp.new(chunk).number_of_captures == 0
- pattern = "#{chunk}#{pattern}"
+ pattern = "#{regexp_chunk}#{pattern}"
optional? ? Regexp.optionalize(pattern) : pattern
end
@@ -230,6 +244,10 @@ module ActionController
"(?i-:(#{(regexp || Regexp.union(*possible_names)).source}))"
end
+ def number_of_captures
+ 1
+ end
+
# Don't URI.escape the controller name since it may contain slashes.
def interpolation_chunk(value_code = local_name)
"\#{#{value_code}.to_s}"
@@ -275,6 +293,10 @@ module ActionController
regexp || "(.*)"
end
+ def number_of_captures
+ regexp ? regexp.number_of_captures : 1
+ end
+
def optionality_implied?
true
end
diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb
index 7a31f0e8d5..1e3a646bc9 100644
--- a/actionpack/lib/action_controller/test_process.rb
+++ b/actionpack/lib/action_controller/test_process.rb
@@ -395,6 +395,7 @@ module ActionController #:nodoc:
@html_document = nil
@request.env['REQUEST_METHOD'] ||= "GET"
+
@request.action = action.to_s
parameters ||= {}
diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
index 12c8405101..ae20f9947c 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
@@ -160,7 +160,7 @@ module HTML
if !options[:attributes].include?(attr_name) || contains_bad_protocols?(attr_name, value)
node.attributes.delete(attr_name)
else
- node.attributes[attr_name] = attr_name == 'style' ? sanitize_css(value) : CGI::escapeHTML(value)
+ node.attributes[attr_name] = attr_name == 'style' ? sanitize_css(value) : CGI::escapeHTML(CGI::unescapeHTML(value))
end
end
end
diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb
index 288b62778e..126d16e5f4 100644
--- a/actionpack/lib/action_pack/version.rb
+++ b/actionpack/lib/action_pack/version.rb
@@ -2,7 +2,7 @@ module ActionPack #:nodoc:
module VERSION #:nodoc:
MAJOR = 2
MINOR = 2
- TINY = 0
+ TINY = 1
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
index ccb7df212a..cd25684940 100644
--- a/actionpack/lib/action_view/helpers/atom_feed_helper.rb
+++ b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
@@ -1,3 +1,5 @@
+require 'set'
+
# Adds easy defaults to writing Atom feeds with the Builder template engine (this does not work on ERb or any other
# template languages).
module ActionView
@@ -121,6 +123,8 @@ module ActionView
end
class AtomBuilder
+ XHTML_TAG_NAMES = %w(content rights title subtitle summary).to_set
+
def initialize(xml)
@xml = xml
end
@@ -140,14 +144,15 @@ module ActionView
@xml.__send__(method, *arguments, &block)
end
end
-
+
# True if the method name matches one of the five elements defined
# in the Atom spec as potentially containing XHTML content and
# if :type => 'xhtml' is, in fact, specified.
def xhtml_block?(method, arguments)
- %w( content rights title subtitle summary ).include?(method.to_s) &&
- arguments.last.respond_to?(:[]) &&
- arguments.last[:type].to_s == 'xhtml'
+ if XHTML_TAG_NAMES.include?(method.to_s)
+ last = arguments.last
+ last.is_a?(Hash) && last[:type].to_s == 'xhtml'
+ end
end
end
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index de08672d2d..d37ca766af 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -133,10 +133,12 @@ module ActionView
unless options.blank?
attrs = []
if escape
- options.each do |key, value|
- next unless value
- value = BOOLEAN_ATTRIBUTES.include?(key) ? key : escape_once(value)
- attrs << %(#{key}="#{value}")
+ options.each_pair do |key, value|
+ if BOOLEAN_ATTRIBUTES.include?(key)
+ attrs << %(#{key}="#{key}") if value
+ else
+ attrs << %(#{key}="#{escape_once(value)}") if !value.nil?
+ end
end
else
attrs = options.map { |key, value| %(#{key}="#{value}") }
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index d80e7c6e57..36f7575652 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -559,7 +559,7 @@ module ActionView
(?:\.[-\w]+)* # remaining subdomains or domain
(?::\d+)? # port
(?:/(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$]))*)* # path
- (?:\?[\w\+@%&=.;-]+)? # query string
+ (?:\?[\w\+@%&=.;:-]+)? # query string
(?:\#[\w\-]*)? # trailing anchor
)
([[:punct:]]|<|$|) # trailing text
@@ -598,4 +598,4 @@ module ActionView
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/test/controller/html-scanner/sanitizer_test.rb b/actionpack/test/controller/html-scanner/sanitizer_test.rb
index a9e8447e32..bae0f5c9fd 100644
--- a/actionpack/test/controller/html-scanner/sanitizer_test.rb
+++ b/actionpack/test/controller/html-scanner/sanitizer_test.rb
@@ -253,6 +253,10 @@ class SanitizerTest < Test::Unit::TestCase
assert_sanitized "<![CDATA[<span>neverending...", "&lt;![CDATA[&lt;span>neverending...]]>"
end
+ def test_should_not_mangle_urls_with_ampersand
+ assert_sanitized %{<a href=\"http://www.domain.com?var1=1&amp;var2=2\">my link</a>}
+ end
+
protected
def assert_sanitized(input, expected = nil)
@sanitizer ||= HTML::WhiteListSanitizer.new
diff --git a/actionpack/test/controller/logging_test.rb b/actionpack/test/controller/logging_test.rb
new file mode 100644
index 0000000000..3c936854dd
--- /dev/null
+++ b/actionpack/test/controller/logging_test.rb
@@ -0,0 +1,46 @@
+require 'abstract_unit'
+
+class LoggingController < ActionController::Base
+ def show
+ render :nothing => true
+ end
+end
+
+class LoggingTest < ActionController::TestCase
+ tests LoggingController
+
+ class MockLogger
+ attr_reader :logged
+
+ def method_missing(method, *args)
+ @logged ||= []
+ @logged << args.first
+ end
+ end
+
+ setup :set_logger
+
+ def test_logging_without_parameters
+ get :show
+ assert_equal 2, logs.size
+ assert_nil logs.detect {|l| l =~ /Parameters/ }
+ end
+
+ def test_logging_with_parameters
+ get :show, :id => 10
+ assert_equal 3, logs.size
+
+ params = logs.detect {|l| l =~ /Parameters/ }
+ assert_equal 'Parameters: {"id"=>"10"}', params
+ end
+
+ private
+
+ def set_logger
+ @controller.logger = MockLogger.new
+ end
+
+ def logs
+ @logs ||= @controller.logger.logged.compact.map {|l| l.strip}
+ end
+end
diff --git a/actionpack/test/controller/mime_type_test.rb b/actionpack/test/controller/mime_type_test.rb
index f16a3c68b4..21ae0419f1 100644
--- a/actionpack/test/controller/mime_type_test.rb
+++ b/actionpack/test/controller/mime_type_test.rb
@@ -61,7 +61,9 @@ class MimeTypeTest < Test::Unit::TestCase
types.each do |type|
mime = Mime.const_get(type.to_s.upcase)
assert mime.send("#{type}?"), "#{mime.inspect} is not #{type}?"
- (types - [type]).each { |other_type| assert !mime.send("#{other_type}?"), "#{mime.inspect} is #{other_type}?" }
+ invalid_types = types - [type]
+ invalid_types.delete(:html) if Mime::Type.html_types.include?(type)
+ invalid_types.each { |other_type| assert !mime.send("#{other_type}?"), "#{mime.inspect} is #{other_type}?" }
end
end
@@ -71,14 +73,12 @@ class MimeTypeTest < Test::Unit::TestCase
end
def test_verifiable_mime_types
- unverified_types = Mime::Type.unverifiable_types
all_types = Mime::SET.to_a.map(&:to_sym)
all_types.uniq!
# Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE
all_types.delete_if { |type| !Mime.const_defined?(type.to_s.upcase) }
-
- unverified, verified = all_types.partition { |type| Mime::Type.unverifiable_types.include? type }
- assert verified.all? { |type| Mime.const_get(type.to_s.upcase).verify_request? }, "Not all Mime Types are verified: #{verified.inspect}"
- assert unverified.all? { |type| !Mime.const_get(type.to_s.upcase).verify_request? }, "Some Mime Types are verified: #{unverified.inspect}"
+ verified, unverified = all_types.partition { |type| Mime::Type.browser_generated_types.include? type }
+ assert verified.each { |type| assert Mime.const_get(type.to_s.upcase).verify_request?, "Verifiable Mime Type is not verified: #{type.inspect}" }
+ assert unverified.each { |type| assert !Mime.const_get(type.to_s.upcase).verify_request?, "Nonverifiable Mime Type is verified: #{type.inspect}" }
end
end
diff --git a/actionpack/test/controller/polymorphic_routes_test.rb b/actionpack/test/controller/polymorphic_routes_test.rb
index 6ddf2826cd..620f2b3ab5 100644
--- a/actionpack/test/controller/polymorphic_routes_test.rb
+++ b/actionpack/test/controller/polymorphic_routes_test.rb
@@ -169,6 +169,17 @@ uses_mocha 'polymorphic URL helpers' do
polymorphic_url([@article, :response, @tag], :format => :pdf)
end
+ def test_nesting_with_array_containing_nil
+ expects(:article_response_url).with(@article)
+ polymorphic_url([@article, nil, :response])
+ end
+
+ def test_with_array_containing_single_object
+ @article.save
+ expects(:article_url).with(@article)
+ polymorphic_url([nil, @article])
+ end
+
# TODO: Needs to be updated to correctly know about whether the object is in a hash or not
def xtest_with_hash
expects(:article_url).with(@article)
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index f7adaa7d4e..5669b8f358 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -77,57 +77,61 @@ module RequestForgeryProtectionTests
ActionController::Base.request_forgery_protection_token = nil
end
+
def test_should_render_form_with_token_tag
- get :index
- assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
+ get :index
+ assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
+ end
+
+ def test_should_render_button_to_with_token_tag
+ get :show_button
+ assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
+ end
+
+ def test_should_render_remote_form_with_only_one_token_parameter
+ get :remote_form
+ assert_equal 1, @response.body.scan(@token).size
+ end
+
+ def test_should_allow_get
+ get :index
+ assert_response :success
+ end
+
+ def test_should_allow_post_without_token_on_unsafe_action
+ post :unsafe
+ assert_response :success
+ end
+
+ def test_should_not_allow_html_post_without_token
+ @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
+ assert_raises(ActionController::InvalidAuthenticityToken) { post :index, :format => :html }
end
- def test_should_render_button_to_with_token_tag
- get :show_button
- assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
- end
-
- def test_should_render_remote_form_with_only_one_token_parameter
- get :remote_form
- assert_equal 1, @response.body.scan(@token).size
- end
-
- def test_should_allow_get
- get :index
- assert_response :success
+ def test_should_not_allow_html_put_without_token
+ @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
+ assert_raises(ActionController::InvalidAuthenticityToken) { put :index, :format => :html }
end
- def test_should_allow_post_without_token_on_unsafe_action
- post :unsafe
- assert_response :success
+ def test_should_not_allow_html_delete_without_token
+ @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
+ assert_raises(ActionController::InvalidAuthenticityToken) { delete :index, :format => :html }
end
- def test_should_not_allow_post_without_token
- assert_raises(ActionController::InvalidAuthenticityToken) { post :index }
- end
-
- def test_should_not_allow_put_without_token
- assert_raises(ActionController::InvalidAuthenticityToken) { put :index }
- end
-
- def test_should_not_allow_delete_without_token
- assert_raises(ActionController::InvalidAuthenticityToken) { delete :index }
- end
-
- def test_should_not_allow_api_formatted_post_without_token
- assert_raises(ActionController::InvalidAuthenticityToken) do
+ def test_should_allow_api_formatted_post_without_token
+ assert_nothing_raised do
post :index, :format => 'xml'
end
end
def test_should_not_allow_api_formatted_put_without_token
- assert_raises(ActionController::InvalidAuthenticityToken) do
+ assert_nothing_raised do
put :index, :format => 'xml'
end
end
- def test_should_not_allow_api_formatted_delete_without_token
- assert_raises(ActionController::InvalidAuthenticityToken) do
+ def test_should_allow_api_formatted_delete_without_token
+ assert_nothing_raised do
delete :index, :format => 'xml'
end
end
@@ -174,16 +178,20 @@ module RequestForgeryProtectionTests
end
end
- def test_should_not_allow_xhr_post_without_token
- assert_raises(ActionController::InvalidAuthenticityToken) { xhr :post, :index }
+ def test_should_allow_xhr_post_without_token
+ assert_nothing_raised { xhr :post, :index }
+ end
+ def test_should_not_allow_xhr_post_with_html_without_token
+ @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
+ assert_raise(ActionController::InvalidAuthenticityToken) { xhr :post, :index }
end
- def test_should_not_allow_xhr_put_without_token
- assert_raises(ActionController::InvalidAuthenticityToken) { xhr :put, :index }
+ def test_should_allow_xhr_put_without_token
+ assert_nothing_raised { xhr :put, :index }
end
- def test_should_not_allow_xhr_delete_without_token
- assert_raises(ActionController::InvalidAuthenticityToken) { xhr :delete, :index }
+ def test_should_allow_xhr_delete_without_token
+ assert_nothing_raised { xhr :delete, :index }
end
def test_should_allow_post_with_token
@@ -227,6 +235,7 @@ class RequestForgeryProtectionControllerTest < Test::Unit::TestCase
def setup
@controller = RequestForgeryProtectionController.new
@request = ActionController::TestRequest.new
+ @request.format = :html
@response = ActionController::TestResponse.new
class << @request.session
def session_id() '123' end
@@ -248,11 +257,11 @@ class RequestForgeryProtectionWithoutSecretControllerTest < Test::Unit::TestCase
ActionController::Base.request_forgery_protection_token = :authenticity_token
end
- def test_should_raise_error_without_secret
- assert_raises ActionController::InvalidAuthenticityToken do
- get :index
- end
- end
+ # def test_should_raise_error_without_secret
+ # assert_raises ActionController::InvalidAuthenticityToken do
+ # get :index
+ # end
+ # end
end
class CsrfCookieMonsterControllerTest < Test::Unit::TestCase
@@ -304,10 +313,15 @@ class SessionOffControllerTest < Test::Unit::TestCase
@token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123')
end
- def test_should_raise_correct_exception
- @request.session = {} # session(:off) doesn't appear to work with controller tests
- assert_raises(ActionController::InvalidAuthenticityToken) do
- post :index, :authenticity_token => @token
- end
- end
+ # TODO: Rewrite this test.
+ # This test was passing but for the wrong reason.
+ # Sessions aren't really being turned off, so an exception was raised
+ # because sessions weren't on - not because the token didn't match.
+ #
+ # def test_should_raise_correct_exception
+ # @request.session = {} # session(:off) doesn't appear to work with controller tests
+ # assert_raises(ActionController::InvalidAuthenticityToken) do
+ # post :index, :authenticity_token => @token, :format => :html
+ # end
+ # end
end
diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb
index 1fea82e564..04f7a0a528 100644
--- a/actionpack/test/controller/resources_test.rb
+++ b/actionpack/test/controller/resources_test.rb
@@ -14,6 +14,8 @@ class LogosController < ResourcesController; end
class AccountsController < ResourcesController; end
class AdminController < ResourcesController; end
+class ProductsController < ResourcesController; end
+class ImagesController < ResourcesController; end
module Backoffice
class ProductsController < ResourcesController; end
@@ -776,6 +778,225 @@ class ResourcesTest < Test::Unit::TestCase
end
end
+ def test_resource_has_only_show_action
+ with_routing do |set|
+ set.draw do |map|
+ map.resources :products, :only => :show
+ end
+
+ assert_resource_allowed_routes('products', {}, { :id => '1' }, :show, [:index, :new, :create, :edit, :update, :destroy])
+ assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, :show, [:index, :new, :create, :edit, :update, :destroy])
+ end
+ end
+
+ def test_singleton_resource_has_only_show_action
+ with_routing do |set|
+ set.draw do |map|
+ map.resource :account, :only => :show
+ end
+
+ assert_singleton_resource_allowed_routes('accounts', {}, :show, [:index, :new, :create, :edit, :update, :destroy])
+ assert_singleton_resource_allowed_routes('accounts', { :format => 'xml' }, :show, [:index, :new, :create, :edit, :update, :destroy])
+ end
+ end
+
+ def test_resource_does_not_have_destroy_action
+ with_routing do |set|
+ set.draw do |map|
+ map.resources :products, :except => :destroy
+ end
+
+ assert_resource_allowed_routes('products', {}, { :id => '1' }, [:index, :new, :create, :show, :edit, :update], :destroy)
+ assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, [:index, :new, :create, :show, :edit, :update], :destroy)
+ end
+ end
+
+ def test_singleton_resource_does_not_have_destroy_action
+ with_routing do |set|
+ set.draw do |map|
+ map.resource :account, :except => :destroy
+ end
+
+ assert_singleton_resource_allowed_routes('accounts', {}, [:new, :create, :show, :edit, :update], :destroy)
+ assert_singleton_resource_allowed_routes('accounts', { :format => 'xml' }, [:new, :create, :show, :edit, :update], :destroy)
+ end
+ end
+
+ def test_resource_has_only_create_action_and_named_route
+ with_routing do |set|
+ set.draw do |map|
+ map.resources :products, :only => :create
+ end
+
+ assert_resource_allowed_routes('products', {}, { :id => '1' }, :create, [:index, :new, :show, :edit, :update, :destroy])
+ assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, :create, [:index, :new, :show, :edit, :update, :destroy])
+
+ assert_not_nil set.named_routes[:products]
+ end
+ end
+
+ def test_resource_has_only_update_action_and_named_route
+ with_routing do |set|
+ set.draw do |map|
+ map.resources :products, :only => :update
+ end
+
+ assert_resource_allowed_routes('products', {}, { :id => '1' }, :update, [:index, :new, :create, :show, :edit, :destroy])
+ assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, :update, [:index, :new, :create, :show, :edit, :destroy])
+
+ assert_not_nil set.named_routes[:product]
+ end
+ end
+
+ def test_resource_has_only_destroy_action_and_named_route
+ with_routing do |set|
+ set.draw do |map|
+ map.resources :products, :only => :destroy
+ end
+
+ assert_resource_allowed_routes('products', {}, { :id => '1' }, :destroy, [:index, :new, :create, :show, :edit, :update])
+ assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, :destroy, [:index, :new, :create, :show, :edit, :update])
+
+ assert_not_nil set.named_routes[:product]
+ end
+ end
+
+ def test_singleton_resource_has_only_create_action_and_named_route
+ with_routing do |set|
+ set.draw do |map|
+ map.resource :account, :only => :create
+ end
+
+ assert_singleton_resource_allowed_routes('accounts', {}, :create, [:new, :show, :edit, :update, :destroy])
+ assert_singleton_resource_allowed_routes('accounts', { :format => 'xml' }, :create, [:new, :show, :edit, :update, :destroy])
+
+ assert_not_nil set.named_routes[:account]
+ end
+ end
+
+ def test_singleton_resource_has_only_update_action_and_named_route
+ with_routing do |set|
+ set.draw do |map|
+ map.resource :account, :only => :update
+ end
+
+ assert_singleton_resource_allowed_routes('accounts', {}, :update, [:new, :create, :show, :edit, :destroy])
+ assert_singleton_resource_allowed_routes('accounts', { :format => 'xml' }, :update, [:new, :create, :show, :edit, :destroy])
+
+ assert_not_nil set.named_routes[:account]
+ end
+ end
+
+ def test_singleton_resource_has_only_destroy_action_and_named_route
+ with_routing do |set|
+ set.draw do |map|
+ map.resource :account, :only => :destroy
+ end
+
+ assert_singleton_resource_allowed_routes('accounts', {}, :destroy, [:new, :create, :show, :edit, :update])
+ assert_singleton_resource_allowed_routes('accounts', { :format => 'xml' }, :destroy, [:new, :create, :show, :edit, :update])
+
+ assert_not_nil set.named_routes[:account]
+ end
+ end
+
+ def test_resource_has_only_collection_action
+ with_routing do |set|
+ set.draw do |map|
+ map.resources :products, :except => :all, :collection => { :sale => :get }
+ end
+
+ assert_resource_allowed_routes('products', {}, { :id => '1' }, [], [:index, :new, :create, :show, :edit, :update, :destroy])
+ assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, [], [:index, :new, :create, :show, :edit, :update, :destroy])
+
+ assert_recognizes({ :controller => 'products', :action => 'sale' }, :path => 'products/sale', :method => :get)
+ assert_recognizes({ :controller => 'products', :action => 'sale', :format => 'xml' }, :path => 'products/sale.xml', :method => :get)
+ end
+ end
+
+ def test_resource_has_only_member_action
+ with_routing do |set|
+ set.draw do |map|
+ map.resources :products, :except => :all, :member => { :preview => :get }
+ end
+
+ assert_resource_allowed_routes('products', {}, { :id => '1' }, [], [:index, :new, :create, :show, :edit, :update, :destroy])
+ assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, [], [:index, :new, :create, :show, :edit, :update, :destroy])
+
+ assert_recognizes({ :controller => 'products', :action => 'preview', :id => '1' }, :path => 'products/1/preview', :method => :get)
+ assert_recognizes({ :controller => 'products', :action => 'preview', :id => '1', :format => 'xml' }, :path => 'products/1/preview.xml', :method => :get)
+ end
+ end
+
+ def test_singleton_resource_has_only_member_action
+ with_routing do |set|
+ set.draw do |map|
+ map.resource :account, :except => :all, :member => { :signup => :get }
+ end
+
+ assert_singleton_resource_allowed_routes('accounts', {}, [], [:new, :create, :show, :edit, :update, :destroy])
+ assert_singleton_resource_allowed_routes('accounts', { :format => 'xml' }, [], [:new, :create, :show, :edit, :update, :destroy])
+
+ assert_recognizes({ :controller => 'accounts', :action => 'signup' }, :path => 'account/signup', :method => :get)
+ assert_recognizes({ :controller => 'accounts', :action => 'signup', :format => 'xml' }, :path => 'account/signup.xml', :method => :get)
+ end
+ end
+
+ def test_nested_resource_inherits_only_show_action
+ with_routing do |set|
+ set.draw do |map|
+ map.resources :products, :only => :show do |product|
+ product.resources :images
+ end
+ end
+
+ assert_resource_allowed_routes('images', { :product_id => '1' }, { :id => '2' }, :show, [:index, :new, :create, :edit, :update, :destroy], 'products/1/images')
+ assert_resource_allowed_routes('images', { :product_id => '1', :format => 'xml' }, { :id => '2' }, :show, [:index, :new, :create, :edit, :update, :destroy], 'products/1/images')
+ end
+ end
+
+ def test_nested_resource_has_only_show_and_member_action
+ with_routing do |set|
+ set.draw do |map|
+ map.resources :products, :only => [:index, :show] do |product|
+ product.resources :images, :member => { :thumbnail => :get }, :only => :show
+ end
+ end
+
+ assert_resource_allowed_routes('images', { :product_id => '1' }, { :id => '2' }, :show, [:index, :new, :create, :edit, :update, :destroy], 'products/1/images')
+ assert_resource_allowed_routes('images', { :product_id => '1', :format => 'xml' }, { :id => '2' }, :show, [:index, :new, :create, :edit, :update, :destroy], 'products/1/images')
+
+ assert_recognizes({ :controller => 'images', :action => 'thumbnail', :product_id => '1', :id => '2' }, :path => 'products/1/images/2/thumbnail', :method => :get)
+ assert_recognizes({ :controller => 'images', :action => 'thumbnail', :product_id => '1', :id => '2', :format => 'jpg' }, :path => 'products/1/images/2/thumbnail.jpg', :method => :get)
+ end
+ end
+
+ def test_nested_resource_ignores_only_option
+ with_routing do |set|
+ set.draw do |map|
+ map.resources :products, :only => :show do |product|
+ product.resources :images, :except => :destroy
+ end
+ end
+
+ assert_resource_allowed_routes('images', { :product_id => '1' }, { :id => '2' }, [:index, :new, :create, :show, :edit, :update], :destroy, 'products/1/images')
+ assert_resource_allowed_routes('images', { :product_id => '1', :format => 'xml' }, { :id => '2' }, [:index, :new, :create, :show, :edit, :update], :destroy, 'products/1/images')
+ end
+ end
+
+ def test_nested_resource_ignores_except_option
+ with_routing do |set|
+ set.draw do |map|
+ map.resources :products, :except => :show do |product|
+ product.resources :images, :only => :destroy
+ end
+ end
+
+ assert_resource_allowed_routes('images', { :product_id => '1' }, { :id => '2' }, :destroy, [:index, :new, :create, :show, :edit, :update], 'products/1/images')
+ assert_resource_allowed_routes('images', { :product_id => '1', :format => 'xml' }, { :id => '2' }, :destroy, [:index, :new, :create, :show, :edit, :update], 'products/1/images')
+ end
+ end
+
protected
def with_restful_routing(*args)
with_routing do |set|
@@ -979,6 +1200,51 @@ class ResourcesTest < Test::Unit::TestCase
end
end
+ def assert_resource_allowed_routes(controller, options, shallow_options, allowed, not_allowed, path = controller)
+ shallow_path = "#{path}/#{shallow_options[:id]}"
+ format = options[:format] && ".#{options[:format]}"
+ options.merge!(:controller => controller)
+ shallow_options.merge!(options)
+
+ assert_whether_allowed(allowed, not_allowed, options, 'index', "#{path}#{format}", :get)
+ assert_whether_allowed(allowed, not_allowed, options, 'new', "#{path}/new#{format}", :get)
+ assert_whether_allowed(allowed, not_allowed, options, 'create', "#{path}#{format}", :post)
+ assert_whether_allowed(allowed, not_allowed, shallow_options, 'show', "#{shallow_path}#{format}", :get)
+ assert_whether_allowed(allowed, not_allowed, shallow_options, 'edit', "#{shallow_path}/edit#{format}", :get)
+ assert_whether_allowed(allowed, not_allowed, shallow_options, 'update', "#{shallow_path}#{format}", :put)
+ assert_whether_allowed(allowed, not_allowed, shallow_options, 'destroy', "#{shallow_path}#{format}", :delete)
+ end
+
+ def assert_singleton_resource_allowed_routes(controller, options, allowed, not_allowed, path = controller.singularize)
+ format = options[:format] && ".#{options[:format]}"
+ options.merge!(:controller => controller)
+
+ assert_whether_allowed(allowed, not_allowed, options, 'new', "#{path}/new#{format}", :get)
+ assert_whether_allowed(allowed, not_allowed, options, 'create', "#{path}#{format}", :post)
+ assert_whether_allowed(allowed, not_allowed, options, 'show', "#{path}#{format}", :get)
+ assert_whether_allowed(allowed, not_allowed, options, 'edit', "#{path}/edit#{format}", :get)
+ assert_whether_allowed(allowed, not_allowed, options, 'update', "#{path}#{format}", :put)
+ assert_whether_allowed(allowed, not_allowed, options, 'destroy', "#{path}#{format}", :delete)
+ end
+
+ def assert_whether_allowed(allowed, not_allowed, options, action, path, method)
+ action = action.to_sym
+ options = options.merge(:action => action.to_s)
+ path_options = { :path => path, :method => method }
+
+ if Array(allowed).include?(action)
+ assert_recognizes options, path_options
+ elsif Array(not_allowed).include?(action)
+ assert_not_recognizes options, path_options
+ end
+ end
+
+ def assert_not_recognizes(expected_options, path)
+ assert_raise ActionController::RoutingError, ActionController::MethodNotAllowed, Test::Unit::AssertionFailedError do
+ assert_recognizes(expected_options, path)
+ end
+ end
+
def distinct_routes? (r1, r2)
if r1.conditions == r2.conditions and r1.requirements == r2.requirements then
if r1.segments.collect(&:to_s) == r2.segments.collect(&:to_s) then
diff --git a/actionpack/test/controller/session/cookie_store_test.rb b/actionpack/test/controller/session/cookie_store_test.rb
index 010c00fa14..30422314a1 100644
--- a/actionpack/test/controller/session/cookie_store_test.rb
+++ b/actionpack/test/controller/session/cookie_store_test.rb
@@ -266,6 +266,7 @@ class CookieStoreTest < Test::Unit::TestCase
@options = self.class.default_session_options.merge(options)
session = CGI::Session.new(cgi, @options)
+ ObjectSpace.undefine_finalizer(session)
assert_nil cgi.output_hidden, "Output hidden params should be empty: #{cgi.output_hidden.inspect}"
assert_nil cgi.output_cookies, "Output cookies should be empty: #{cgi.output_cookies.inspect}"
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index bade96fe17..1a3a6e86fa 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -239,7 +239,11 @@ class AssetTagHelperTest < ActionView::TestCase
File.stubs(:exist?).with('template/../fixtures/public/images/rails.png.').returns(true)
assert_equal '<img alt="Rails" src="/images/rails.png?1" />', image_tag('rails.png')
ensure
- ENV["RAILS_ASSET_ID"] = old_asset_id
+ if old_asset_id
+ ENV["RAILS_ASSET_ID"] = old_asset_id
+ else
+ ENV.delete("RAILS_ASSET_ID")
+ end
end
end
diff --git a/actionpack/test/template/atom_feed_helper_test.rb b/actionpack/test/template/atom_feed_helper_test.rb
index 9247a42d33..06af8d1d6a 100644
--- a/actionpack/test/template/atom_feed_helper_test.rb
+++ b/actionpack/test/template/atom_feed_helper_test.rb
@@ -255,7 +255,8 @@ class AtomFeedTest < Test::Unit::TestCase
def test_feed_xml_processing_instructions
with_restful_routing(:scrolls) do
get :index, :id => 'feed_with_xml_processing_instructions'
- assert_match %r{<\?xml-stylesheet type="text/css" href="t.css"\?>}, @response.body
+ assert_match %r{<\?xml-stylesheet [^\?]*type="text/css"}, @response.body
+ assert_match %r{<\?xml-stylesheet [^\?]*href="t.css"}, @response.body
end
end
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index de82647813..f8add0bab1 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -235,7 +235,7 @@ class FormTagHelperTest < ActionView::TestCase
assert_match VALID_HTML_ID, label_elem['for']
end
- def test_boolean_optios
+ def test_boolean_options
assert_dom_equal %(<input checked="checked" disabled="disabled" id="admin" name="admin" readonly="readonly" type="checkbox" value="1" />), check_box_tag("admin", 1, true, 'disabled' => true, :readonly => "yes")
assert_dom_equal %(<input checked="checked" id="admin" name="admin" type="checkbox" value="1" />), check_box_tag("admin", 1, true, :disabled => false, :readonly => nil)
assert_dom_equal %(<select id="people" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people", "<option>david</option>", :multiple => true)
diff --git a/actionpack/test/template/tag_helper_test.rb b/actionpack/test/template/tag_helper_test.rb
index fc49d340ef..ef88cae5b8 100644
--- a/actionpack/test/template/tag_helper_test.rb
+++ b/actionpack/test/template/tag_helper_test.rb
@@ -19,6 +19,10 @@ class TagHelperTest < ActionView::TestCase
assert_equal "<p />", tag("p", :ignored => nil)
end
+ def test_tag_options_accepts_false_option
+ assert_equal "<p value=\"false\" />", tag("p", :value => false)
+ end
+
def test_tag_options_accepts_blank_option
assert_equal "<p included=\"\" />", tag("p", :included => '')
end
diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb
index 5f9f715819..095c952d67 100644
--- a/actionpack/test/template/text_helper_test.rb
+++ b/actionpack/test/template/text_helper_test.rb
@@ -221,6 +221,7 @@ class TextHelperTest < ActionView::TestCase
http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1
http://en.wikipedia.org/wiki/Sprite_(computer_graphics)
http://en.wikipedia.org/wiki/Texas_hold'em
+ https://www.google.com/doku.php?id=gps:resource:scs:start
)
urls.each do |url|
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 4ca062b535..c2299b56ad 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,4 +1,4 @@
-*2.2.1 [RC2 or 2.2 final]*
+*2.2.1 [RC2] (November 14th, 2008)*
* Ensure indices don't flip order in schema.rb #1266 [Jordi Bunster]
diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb
index 6e194ab9b4..69300e5ce5 100644
--- a/activerecord/lib/active_record/association_preload.rb
+++ b/activerecord/lib/active_record/association_preload.rb
@@ -312,7 +312,7 @@ module ActiveRecord
table_name = klass.quoted_table_name
primary_key = klass.primary_key
column_type = klass.columns.detect{|c| c.name == primary_key}.type
- ids = id_map.keys.uniq.map do |id|
+ ids = id_map.keys.map do |id|
if column_type == :integer
id.to_i
elsif column_type == :float
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index c7cb6eb966..7f7819115c 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1609,7 +1609,7 @@ module ActiveRecord
:class_name, :table_name, :join_table, :foreign_key, :association_foreign_key,
:select, :conditions, :include, :order, :group, :limit, :offset,
:uniq,
- :finder_sql, :delete_sql, :insert_sql,
+ :finder_sql, :counter_sql, :delete_sql, :insert_sql,
:before_add, :after_add, :before_remove, :after_remove,
:extend, :readonly,
:validate
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index a36a137f0d..757102eb6b 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -2023,8 +2023,7 @@ module ActiveRecord #:nodoc:
end
def scoped_methods #:nodoc:
- scoped_methods = (Thread.current[:scoped_methods] ||= {})
- scoped_methods[self] ||= []
+ Thread.current[:"#{self}_scoped_methods"] ||= []
end
def current_scoped_methods #:nodoc:
diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb
index 5e33cf1bd4..65512d534a 100644
--- a/activerecord/lib/active_record/calculations.rb
+++ b/activerecord/lib/active_record/calculations.rb
@@ -286,7 +286,7 @@ module ActiveRecord
case operation
when 'count' then value.to_i
when 'sum' then type_cast_using_column(value || '0', column)
- when 'avg' then value && value.to_d
+ when 'avg' then value && (value.is_a?(Fixnum) ? value.to_f : value).to_d
else type_cast_using_column(value, column)
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index 3016c329bd..901b17124c 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -65,15 +65,23 @@ module ActiveRecord
# The default ConnectionPool maximum size is 5.
def initialize(spec)
@spec = spec
+
# The cache of reserved connections mapped to threads
@reserved_connections = {}
+
# The mutex used to synchronize pool access
@connection_mutex = Monitor.new
@queue = @connection_mutex.new_cond
- # default 5 second timeout
- @timeout = spec.config[:wait_timeout] || 5
+
+ # default 5 second timeout unless on ruby 1.9
+ @timeout =
+ if RUBY_VERSION < '1.9'
+ spec.config[:wait_timeout] || 5
+ end
+
# default max pool size to 5
@size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
+
@connections = []
@checked_out = []
end
@@ -187,7 +195,7 @@ module ActiveRecord
# try looting dead threads
clear_stale_cached_connections!
if @size == @checked_out.size
- raise ConnectionTimeoutError, "could not obtain a database connection within #{@timeout} seconds. The pool size is currently #{@size}, perhaps you need to increase it?"
+ raise ConnectionTimeoutError, "could not obtain a database connection#{" within #{@timeout} seconds" if @timeout}. The max pool size is currently #{@size}; consider increasing it."
end
end
end
@@ -292,10 +300,7 @@ module ActiveRecord
# and also returns connections to the pool cached by threads that are no
# longer alive.
def clear_active_connections!
- @connection_pools.each_value do |pool|
- pool.release_connection
- pool.clear_stale_cached_connections!
- end
+ @connection_pools.each_value {|pool| pool.release_connection }
end
# Clears the cache which maps classes
@@ -324,7 +329,8 @@ module ActiveRecord
# Returns true if a connection that's accessible to this class has
# already been opened.
def connected?(klass)
- conn = retrieve_connection_pool(klass) ? conn.connected? : false
+ conn = retrieve_connection_pool(klass)
+ conn ? conn.connected? : false
end
# Remove the connection for this class. This will close the active
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index c5183357a1..f8fa969dc3 100755
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -125,9 +125,8 @@ module ActiveRecord
end
# Returns true if its safe to reload the connection between requests for development mode.
- # This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite.
def requires_reloading?
- false
+ true
end
# Checks whether the connection to the database is still active (i.e. not stale).
diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb
index 2479b75789..3c5a9b7df8 100644
--- a/activerecord/lib/active_record/version.rb
+++ b/activerecord/lib/active_record/version.rb
@@ -2,7 +2,7 @@ module ActiveRecord
module VERSION #:nodoc:
MAJOR = 2
MINOR = 2
- TINY = 0
+ TINY = 1
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index 2949f1d304..b5bedf3704 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -68,6 +68,16 @@ class DeveloperWithSymbolsForKeys < ActiveRecord::Base
:foreign_key => "developer_id"
end
+class DeveloperWithCounterSQL < ActiveRecord::Base
+ set_table_name 'developers'
+ has_and_belongs_to_many :projects,
+ :class_name => "DeveloperWithCounterSQL",
+ :join_table => "developers_projects",
+ :association_foreign_key => "project_id",
+ :foreign_key => "developer_id",
+ :counter_sql => 'SELECT COUNT(*) AS count_all FROM projects INNER JOIN developers_projects ON projects.id = developers_projects.project_id WHERE developers_projects.developer_id =#{id}'
+end
+
class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
:parrots, :pirates, :treasures, :price_estimates, :tags, :taggings
@@ -739,6 +749,19 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_nothing_raised { david.projects.count(:all, :conditions => '1=1') }
end
+ def test_count
+ david = Developer.find(1)
+ assert_equal 2, david.projects.count
+ end
+
+ def test_count_with_counter_sql
+ developer = DeveloperWithCounterSQL.create(:name => 'tekin')
+ developer.project_ids = [projects(:active_record).id]
+ developer.save
+ developer.reload
+ assert_equal 1, developer.projects.count
+ end
+
uses_mocha 'mocking Post.transaction' do
def test_association_proxy_transaction_method_starts_transaction_in_association_class
Post.expects(:transaction)
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index 0fa61500c0..8bd0dd0f6e 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -25,6 +25,11 @@ class CalculationsTest < ActiveRecord::TestCase
def test_should_return_nil_as_average
assert_nil NumericData.average(:bank_balance)
end
+
+ def test_type_cast_calculated_value_should_convert_db_averages_of_fixnum_class_to_decimal
+ assert_equal 0, NumericData.send(:type_cast_calculated_value, 0, nil, 'avg')
+ assert_equal 53.0, NumericData.send(:type_cast_calculated_value, 53, nil, 'avg')
+ end
def test_should_get_maximum_of_field
assert_equal 60, Account.maximum(:credit_limit)
diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb
index 3e8c617a89..2649a9358a 100644
--- a/activerecord/test/cases/pooled_connections_test.rb
+++ b/activerecord/test/cases/pooled_connections_test.rb
@@ -28,10 +28,13 @@ class PooledConnectionsTest < ActiveRecord::TestCase
end
end
- def test_pooled_connection_checkout
- checkout_connections
- assert_equal @connections.length, 2
- assert_equal @timed_out, 2
+ # Will deadlock due to lack of Monitor timeouts in 1.9
+ if RUBY_VERSION < '1.9'
+ def test_pooled_connection_checkout
+ checkout_connections
+ assert_equal @connections.length, 2
+ assert_equal @timed_out, 2
+ end
end
def checkout_checkin_connections(pool_size, threads)
@@ -74,6 +77,11 @@ class PooledConnectionsTest < ActiveRecord::TestCase
conn_pool.checkin(conn)
end
+ def test_not_connected_defined_connection_returns_false
+ ActiveRecord::Base.establish_connection(@connection)
+ assert ! ActiveRecord::Base.connected?
+ end
+
def test_undefined_connection_returns_false
old_handler = ActiveRecord::Base.connection_handler
ActiveRecord::Base.connection_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
diff --git a/activeresource/CHANGELOG b/activeresource/CHANGELOG
index 114a63c415..e05a634a12 100644
--- a/activeresource/CHANGELOG
+++ b/activeresource/CHANGELOG
@@ -1,4 +1,4 @@
-*2.2.1 [RC2 or 2.2 final]*
+*2.2.1 [RC2] (November 14th, 2008)*
* Fixed that ActiveResource#post would post an empty string when it shouldn't be posting anything #525 [Paolo Angelini]
diff --git a/activeresource/lib/active_resource/version.rb b/activeresource/lib/active_resource/version.rb
index d56f4cf17e..3747ffc63c 100644
--- a/activeresource/lib/active_resource/version.rb
+++ b/activeresource/lib/active_resource/version.rb
@@ -2,7 +2,7 @@ module ActiveResource
module VERSION #:nodoc:
MAJOR = 2
MINOR = 2
- TINY = 0
+ TINY = 1
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index e77affc315..3526c2e8fc 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,6 +1,4 @@
-*2.2.1 [RC2 or 2.2 final]*
-
-* Added render :js for people who want to render inline JavaScript replies without using RJS [DHH]
+*2.2.1 [RC2] (November 14th, 2008)*
* Fixed the option merging in Array#to_xml #1126 [Rudolf Gavlas]
diff --git a/activesupport/Rakefile b/activesupport/Rakefile
index 1961fb43cf..ccbab525ba 100644
--- a/activesupport/Rakefile
+++ b/activesupport/Rakefile
@@ -1,7 +1,6 @@
require 'rake/testtask'
require 'rake/rdoctask'
require 'rake/gempackagetask'
-require 'rake/contrib/sshpublisher'
require File.join(File.dirname(__FILE__), 'lib', 'active_support', 'version')
@@ -65,12 +64,14 @@ end
desc "Publish the beta gem"
task :pgem => [:package] do
+ require 'rake/contrib/sshpublisher'
Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
`ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
+ require 'rake/contrib/sshpublisher'
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/as", "doc").upload
end
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 3d871eec11..fe568d6127 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -138,14 +138,22 @@ module ActiveSupport #:nodoc:
end
def load_with_new_constant_marking(file, *extras) #:nodoc:
- Dependencies.new_constants_in(Object) { load_without_new_constant_marking(file, *extras) }
+ if Dependencies.load?
+ Dependencies.new_constants_in(Object) { load_without_new_constant_marking(file, *extras) }
+ else
+ load_without_new_constant_marking(file, *extras)
+ end
rescue Exception => exception # errors from loading file
exception.blame_file! file
raise
end
def require(file, *extras) #:nodoc:
- Dependencies.new_constants_in(Object) { super }
+ if Dependencies.load?
+ Dependencies.new_constants_in(Object) { super }
+ else
+ super
+ end
rescue Exception => exception # errors from required file
exception.blame_file! file
raise
diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb
index 1ccfec4000..ba52e41c08 100644
--- a/activesupport/lib/active_support/inflector.rb
+++ b/activesupport/lib/active_support/inflector.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
require 'singleton'
require 'iconv'
diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb
index f2bc12e832..c27c4ddb1a 100644
--- a/activesupport/lib/active_support/rescuable.rb
+++ b/activesupport/lib/active_support/rescuable.rb
@@ -78,7 +78,7 @@ module ActiveSupport
def handler_for_rescue(exception)
# We go from right to left because pairs are pushed onto rescue_handlers
# as rescue_from declarations are found.
- _, handler = Array(rescue_handlers).reverse.detect do |klass_name, handler|
+ _, rescuer = Array(rescue_handlers).reverse.detect do |klass_name, handler|
# The purpose of allowing strings in rescue_from is to support the
# declaration of handler associations for exception classes whose
# definition is yet unknown.
@@ -97,11 +97,11 @@ module ActiveSupport
exception.is_a?(klass) if klass
end
- case handler
+ case rescuer
when Symbol
- method(handler)
+ method(rescuer)
when Proc
- handler.bind(self)
+ rescuer.bind(self)
end
end
end
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 4991f71683..1d87fa64b5 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -304,7 +304,8 @@ module ActiveSupport
"Mexico City", "Monterrey", "Central America" ],
[-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota",
"Lima", "Quito" ],
- [-14_400, "Atlantic Time (Canada)", "Caracas", "La Paz", "Santiago" ],
+ [-16_200, "Caracas" ],
+ [-14_400, "Atlantic Time (Canada)", "La Paz", "Santiago" ],
[-12_600, "Newfoundland" ],
[-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ],
[ -7_200, "Mid-Atlantic" ],
@@ -325,9 +326,9 @@ module ActiveSupport
[ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ],
[ 16_200, "Kabul" ],
[ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ],
- [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi" ],
+ [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi", "Sri Jayawardenepura" ],
[ 20_700, "Kathmandu" ],
- [ 21_600, "Astana", "Dhaka", "Sri Jayawardenepura", "Almaty",
+ [ 21_600, "Astana", "Dhaka", "Almaty",
"Novosibirsk" ],
[ 23_400, "Rangoon" ],
[ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ],
diff --git a/activesupport/lib/active_support/vendor.rb b/activesupport/lib/active_support/vendor.rb
index 633eb2ef08..dc98936525 100644
--- a/activesupport/lib/active_support/vendor.rb
+++ b/activesupport/lib/active_support/vendor.rb
@@ -14,9 +14,9 @@ rescue Gem::LoadError
end
begin
- gem 'memcache-client', '~> 1.5.0'
+ gem 'memcache-client', '~> 1.5.1'
rescue Gem::LoadError
- $:.unshift "#{File.dirname(__FILE__)}/vendor/memcache-client-1.5.0"
+ $:.unshift "#{File.dirname(__FILE__)}/vendor/memcache-client-1.5.1"
end
begin
diff --git a/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb b/activesupport/lib/active_support/vendor/memcache-client-1.5.1/memcache.rb
index 30113201a6..99c9af0398 100644
--- a/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb
+++ b/activesupport/lib/active_support/vendor/memcache-client-1.5.1/memcache.rb
@@ -1,10 +1,10 @@
# All original code copyright 2005, 2006, 2007 Bob Cottrell, Eric Hodel,
# The Robot Co-op. All rights reserved.
-#
+#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
-#
+#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
@@ -13,7 +13,7 @@
# 3. Neither the names of the authors nor the names of their contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
-#
+#
# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
diff --git a/activesupport/lib/active_support/version.rb b/activesupport/lib/active_support/version.rb
index 8f5395fca6..6631f233f1 100644
--- a/activesupport/lib/active_support/version.rb
+++ b/activesupport/lib/active_support/version.rb
@@ -2,7 +2,7 @@ module ActiveSupport
module VERSION #:nodoc:
MAJOR = 2
MINOR = 2
- TINY = 0
+ TINY = 1
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index cc371b3a7b..e7dac4cc6b 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -160,6 +160,12 @@ uses_memcached 'memcached backed store' do
@cache.read('foo').gsub!(/.*/, 'baz')
assert_equal 'bar', @cache.read('foo')
end
+
+ def test_write_should_return_true_on_success
+ result = @cache.write('foo', 'bar')
+ assert_equal 'bar', @cache.read('foo') # make sure 'foo' was written
+ assert result
+ end
end
class CompressedMemCacheStore < Test::Unit::TestCase
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index 11ec1c6cd6..fd17f7a812 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -123,7 +123,7 @@ class TimeExtCalculationsTest < Test::Unit::TestCase
def test_end_of_year
assert_equal Time.local(2007,12,31,23,59,59), Time.local(2007,2,22,10,10,10).end_of_year
assert_equal Time.local(2007,12,31,23,59,59), Time.local(2007,12,31,10,10,10).end_of_year
- end
+ end
def test_beginning_of_year
assert_equal Time.local(2005,1,1,0,0,0), Time.local(2005,2,22,10,10,10).beginning_of_year
diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index 6c3bd1a4fd..fe04b91f2b 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -694,17 +694,17 @@ class DependenciesTest < Test::Unit::TestCase
with_loading 'autoloading_fixtures' do
ActiveSupport::Dependencies.mechanism = :require
2.times do
- assert_raise(NameError) {"RaisesNameError".constantize}
+ assert_raise(NameError) { assert_equal 123, ::RaisesNameError::FooBarBaz }
end
end
end
def test_autoload_doesnt_shadow_name_error
with_loading 'autoloading_fixtures' do
- assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it hasn't been referenced yet!"
+ Object.send(:remove_const, :RaisesNameError) if defined?(::RaisesNameError)
2.times do
begin
- ::RaisesNameError.object_id
+ ::RaisesNameError::FooBarBaz.object_id
flunk 'should have raised NameError when autoloaded file referenced FooBarBaz'
rescue NameError => e
assert_equal 'uninitialized constant RaisesNameError::FooBarBaz', e.message
@@ -712,9 +712,9 @@ class DependenciesTest < Test::Unit::TestCase
assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
end
- assert !defined?(RaisesNameError)
+ assert !defined?(::RaisesNameError)
2.times do
- assert_raise(NameError) { RaisesNameError }
+ assert_raise(NameError) { ::RaisesNameError }
assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
end
end
diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb
index 515ffcf0bf..d999b9f2a8 100644
--- a/activesupport/test/time_zone_test.rb
+++ b/activesupport/test/time_zone_test.rb
@@ -51,7 +51,7 @@ class TimeZoneTest < Test::Unit::TestCase
define_method("test_utc_offset_for_#{name}") do
silence_warnings do # silence warnings raised by tzinfo gem
- period = zone.tzinfo.period_for_utc(Time.utc(2006,1,1,0,0,0))
+ period = zone.tzinfo.period_for_utc(Time.utc(2009,1,1,0,0,0))
assert_equal period.utc_offset, zone.utc_offset
end
end
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 058afddbde..ae20cb50da 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,4 +1,4 @@
-*2.2.1 [RC2 or 2.2 final]*
+*2.2.1 [RC2] (November 14th, 2008)*
* Fixed plugin generator so that generated unit tests would subclass ActiveSupport::TestCase, also introduced a helper script to reduce the needed require statements #1137 [Mathias Meyer]
diff --git a/railties/environments/boot.rb b/railties/environments/boot.rb
index 6a30b54973..57c256e438 100644
--- a/railties/environments/boot.rb
+++ b/railties/environments/boot.rb
@@ -82,7 +82,7 @@ module Rails
def load_rubygems
require 'rubygems'
- min_version = '1.1.1'
+ min_version = '1.3.1'
unless rubygems_version >= min_version
$stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
exit 1
diff --git a/railties/lib/rails/vendor_gem_source_index.rb b/railties/lib/rails/vendor_gem_source_index.rb
index dc821693ac..5b7721f303 100644
--- a/railties/lib/rails/vendor_gem_source_index.rb
+++ b/railties/lib/rails/vendor_gem_source_index.rb
@@ -81,7 +81,7 @@ module Rails
spec.files = files
else
$stderr.puts("config.gem: Unpacked gem #{dir_name} in vendor/gems not in a versioned directory."+
- " Giving up.") unless @silence_spec_warnings
+ " Giving up.") unless @@silence_spec_warnings
next
end
end
@@ -137,4 +137,4 @@ module Rails
end
end
-end \ No newline at end of file
+end
diff --git a/railties/lib/rails/version.rb b/railties/lib/rails/version.rb
index a0986a2e05..bd835fba26 100644
--- a/railties/lib/rails/version.rb
+++ b/railties/lib/rails/version.rb
@@ -2,7 +2,7 @@ module Rails
module VERSION #:nodoc:
MAJOR = 2
MINOR = 2
- TINY = 0
+ TINY = 1
STRING = [MAJOR, MINOR, TINY].join('.')
end