Skip to content
Browse files

Merge branch 'master' into testing

  • Loading branch information...
2 parents 1304b66 + 4f984c9 commit eeea1a26ec7bd5e11caa4630ff7820c1c7f762e3 @jeremy jeremy committed Nov 15, 2008
Showing with 5,181 additions and 2,755 deletions.
  1. +6 −1 actionmailer/CHANGELOG
  2. +1 −1 actionmailer/Rakefile
  3. +10 −7 actionmailer/lib/action_mailer/base.rb
  4. +5 −1 actionmailer/lib/action_mailer/part_container.rb
  5. +1 −1 actionmailer/lib/action_mailer/version.rb
  6. +14 −0 actionmailer/test/mail_service_test.rb
  7. +15 −1 actionpack/CHANGELOG
  8. +1 −1 actionpack/Rakefile
  9. +3 −3 actionpack/lib/action_controller/base.rb
  10. +18 −2 actionpack/lib/action_controller/mime_type.rb
  11. +1 −1 actionpack/lib/action_controller/polymorphic_routes.rb
  12. +1 −1 actionpack/lib/action_controller/request_forgery_protection.rb
  13. +81 −37 actionpack/lib/action_controller/resources.rb
  14. +1 −0 actionpack/lib/action_controller/test_process.rb
  15. +1 −1 actionpack/lib/action_pack/version.rb
  16. +6 −4 actionpack/lib/action_view/helpers/tag_helper.rb
  17. +24 −26 actionpack/lib/action_view/helpers/text_helper.rb
  18. +6 −6 actionpack/test/controller/mime_type_test.rb
  19. +11 −0 actionpack/test/controller/polymorphic_routes_test.rb
  20. +66 −52 actionpack/test/controller/request_forgery_protection_test.rb
  21. +266 −0 actionpack/test/controller/resources_test.rb
  22. +1 −1 actionpack/test/template/form_tag_helper_test.rb
  23. +4 −0 actionpack/test/template/tag_helper_test.rb
  24. +95 −50 actionpack/test/template/text_helper_test.rb
  25. +1 −1 activerecord/CHANGELOG
  26. +1 −1 activerecord/Rakefile
  27. +1 −1 activerecord/lib/active_record/association_preload.rb
  28. +3 −4 activerecord/lib/active_record/associations/has_one_through_association.rb
  29. +9 −1 activerecord/lib/active_record/base.rb
  30. +1 −1 activerecord/lib/active_record/calculations.rb
  31. +1 −1 activerecord/lib/active_record/version.rb
  32. +39 −1 activerecord/test/cases/associations/has_one_through_associations_test.rb
  33. +5 −0 activerecord/test/cases/calculations_test.rb
  34. +1 −1 activerecord/test/cases/pooled_connections_test.rb
  35. +5 −0 activerecord/test/fixtures/organizations.yml
  36. +2 −0 activerecord/test/models/member.rb
  37. +4 −0 activerecord/test/models/member_detail.rb
  38. +4 −0 activerecord/test/models/organization.rb
  39. +10 −0 activerecord/test/schema/schema.rb
  40. +1 −1 activeresource/CHANGELOG
  41. +1 −1 activeresource/Rakefile
  42. +1 −1 activeresource/lib/active_resource/version.rb
  43. +7 −2 activesupport/CHANGELOG
  44. +7 −1 activesupport/lib/active_support/option_merger.rb
  45. +4 −3 activesupport/lib/active_support/values/time_zone.rb
  46. +1 −1 activesupport/lib/active_support/version.rb
  47. +8 −0 activesupport/test/option_merger_test.rb
  48. +1 −1 activesupport/test/time_zone_test.rb
  49. +1 −1 railties/CHANGELOG
  50. +5 −5 railties/Rakefile
  51. +5 −2 railties/doc/README_FOR_APP
  52. +40 −6 railties/doc/guides/html/2_2_release_notes.html
  53. +27 −18 railties/doc/guides/html/actioncontroller_basics.html
  54. +487 −5 railties/doc/guides/html/activerecord_validations_callbacks.html
  55. +39 −33 railties/doc/guides/html/caching_with_rails.html
  56. +434 −0 railties/doc/guides/html/command_line.html
  57. +438 −0 railties/doc/guides/html/configuring.html
  58. +672 −480 railties/doc/guides/html/creating_plugins.html
  59. +2 −2 railties/doc/guides/html/debugging_rails_applications.html
  60. +137 −67 railties/doc/guides/html/finders.html
  61. +2 −2 railties/doc/guides/html/getting_started_with_rails.html
  62. +13 −0 railties/doc/guides/html/layouts_and_rendering.html
  63. +2 −2 railties/doc/guides/html/migrations.html
  64. +39 −9 railties/doc/guides/html/routing_outside_in.html
  65. +335 −206 railties/doc/guides/html/testing_rails_applications.html
  66. +20 −5 railties/doc/guides/source/2_2_release_notes.txt
  67. +2 −2 railties/doc/guides/source/actioncontroller_basics/http_auth.txt
  68. +4 −4 railties/doc/guides/source/actioncontroller_basics/methods.txt
  69. +7 −3 railties/doc/guides/source/actioncontroller_basics/params.txt
  70. +1 −1 railties/doc/guides/source/actioncontroller_basics/request_response_objects.txt
  71. +7 −7 railties/doc/guides/source/actioncontroller_basics/session.txt
  72. +1 −1 railties/doc/guides/source/actioncontroller_basics/streaming.txt
  73. +381 −2 railties/doc/guides/source/activerecord_validations_callbacks.txt
  74. +40 −34 railties/doc/guides/source/caching_with_rails.txt
  75. +147 −0 railties/doc/guides/source/command_line.txt
  76. +69 −71 railties/doc/guides/source/creating_plugins/acts_as_yaffle.txt
  77. +0 −861 railties/doc/guides/source/creating_plugins/basics.markdown
  78. +59 −0 railties/doc/guides/source/creating_plugins/controllers.txt
  79. +123 −0 railties/doc/guides/source/creating_plugins/core_ext.txt
  80. +8 −8 railties/doc/guides/source/creating_plugins/custom_route.txt
  81. +1 −0 railties/doc/guides/source/creating_plugins/gem.txt
  82. +39 −19 railties/doc/guides/source/creating_plugins/{custom_generator.txt → generator_method.txt}
  83. +51 −0 railties/doc/guides/source/creating_plugins/helpers.txt
  84. +38 −70 railties/doc/guides/source/creating_plugins/index.txt
  85. +97 −30 railties/doc/guides/source/creating_plugins/migration_generator.txt
  86. +76 −0 railties/doc/guides/source/creating_plugins/models.txt
  87. +2 −55 railties/doc/guides/source/creating_plugins/odds_and_ends.txt
  88. +0 −169 railties/doc/guides/source/creating_plugins/preparation.txt
  89. +0 −103 railties/doc/guides/source/creating_plugins/string_to_squawk.txt
  90. +230 −0 railties/doc/guides/source/creating_plugins/test_setup.txt
  91. +0 −61 railties/doc/guides/source/creating_plugins/view_helper.txt
  92. +2 −2 railties/doc/guides/source/debugging_rails_applications.txt
  93. +55 −29 railties/doc/guides/source/finders.txt
  94. +2 −2 railties/doc/guides/source/getting_started_with_rails.txt
  95. +3 −0 railties/doc/guides/source/layouts_and_rendering.txt
  96. +1 −1 railties/doc/guides/source/migrations/foreign_keys.txt
  97. +1 −1 railties/doc/guides/source/migrations/scheming.txt
  98. +27 −11 railties/doc/guides/source/routing_outside_in.txt
  99. +249 −141 railties/doc/guides/source/testing_rails_applications.txt
  100. +1 −1 railties/environments/boot.rb
  101. +2 −2 railties/lib/rails/vendor_gem_source_index.rb
  102. +1 −1 railties/lib/rails/version.rb
View
7 actionmailer/CHANGELOG
@@ -1,4 +1,9 @@
-*2.2.1 [RC2 or 2.2 final]*
+*2.3.0/3.0*
+
+* Fixed that no body charset would be set when there are attachments present #740 [Paweł Kondzior]
+
+
+*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]
View
2 actionmailer/Rakefile
@@ -55,7 +55,7 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "actionmailer"
s.homepage = "http://www.rubyonrails.org"
- s.add_dependency('actionpack', '= 2.2.0' + PKG_BUILD)
+ s.add_dependency('actionpack', '= 2.2.1' + PKG_BUILD)
s.has_rdoc = true
s.requirements << 'none'
View
17 actionmailer/lib/action_mailer/base.rb
@@ -386,12 +386,15 @@ def respond_to?(method_symbol, include_private = false) #: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 @@ def template_root=(root)
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
View
6 actionmailer/lib/action_mailer/part_container.rb
@@ -41,7 +41,11 @@ def attachment(params, &block)
private
def parse_content_type(defaults=nil)
- return [defaults && defaults.content_type, {}] if content_type.blank?
+ if content_type.blank?
+ return defaults ?
+ [ defaults.content_type, { 'charset' => defaults.charset } ] :
+ [ nil, {} ]
+ end
ctype, *attrs = content_type.split(/;\s*/)
attrs = attrs.inject({}) { |h,s| k,v = s.split(/=/, 2); h[k] = v; h }
[ctype, {"charset" => charset || defaults && defaults.charset}.merge(attrs)]
View
2 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
View
14 actionmailer/test/mail_service_test.rb
@@ -915,6 +915,8 @@ def test_deliver_with_mail_object
def test_multipart_with_template_path_with_dots
mail = FunkyPathMailer.create_multipart_with_template_path_with_dots(@recipient)
assert_equal 2, mail.parts.length
+ assert_equal 'text/plain', mail.parts[0].content_type
+ assert_equal 'utf-8', mail.parts[0].charset
end
def test_custom_content_type_attributes
@@ -1045,4 +1047,16 @@ def test_should_not_respond_to_create_with_template_suffix_if_it_begins_with_a_d
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
View
16 actionpack/CHANGELOG
@@ -1,4 +1,18 @@
-*2.2.1 [RC2 or 2.2 final]*
+*2.2.1 [RC2] (November 14th, 2008)*
+
+* Restore backwards compatible functionality for setting relative_url_root. Include deprecation
+
+* Switched the CSRF module to use the request content type to decide if the request is forgeable. #1145 [Jeff Cohen]
+
+* Added :only and :except to map.resources to let people cut down on the number of redundant routes in an application. Typically only useful for huge routesets. #1215 [Tom Stuart]
+
+ map.resources :products, :only => :show do |product|
+ product.resources :images, :except => :destroy
+ end
+
+* 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]
View
2 actionpack/Rakefile
@@ -80,7 +80,7 @@ spec = Gem::Specification.new do |s|
s.has_rdoc = true
s.requirements << 'none'
- s.add_dependency('activesupport', '= 2.2.0' + PKG_BUILD)
+ s.add_dependency('activesupport', '= 2.2.1' + PKG_BUILD)
s.require_path = 'lib'
s.autorequire = 'action_controller'
View
6 actionpack/lib/action_controller/base.rb
@@ -1029,10 +1029,10 @@ def default_url_options(options = nil)
#
# * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
# * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
- # * <tt>String starting with protocol:// (like http://)</tt> - Is passed straight through as the target for redirection.
- # * <tt>String not containing a protocol</tt> - The current protocol and host is prepended to the string.
+ # * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
+ # * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
# * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
- # Short-hand for redirect_to(request.env["HTTP_REFERER"])
+ # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
#
# Examples:
# redirect_to :action => "show", :id => 5
View
20 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 @@ def ==(mime_type)
# 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+)\?$/
View
2 actionpack/lib/action_controller/polymorphic_routes.rb
@@ -73,7 +73,7 @@ module PolymorphicRoutes
#
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)
View
2 actionpack/lib/action_controller/request_forgery_protection.rb
@@ -99,7 +99,7 @@ def verified_request?
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
View
118 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 @@ def initialize(entities, options)
arrange_actions
add_default_actions
+ set_allowed_actions
set_prefixes
end
@@ -113,6 +118,10 @@ def uncountable?
@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 @@ def add_default_actions
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 @@ def initialize(entity, options)
#
# 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 @@ def map_resource(entities, options = {}, &block)
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 @@ def map_singleton_resource(entities, options = {}, &block)
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 @@ def map_associations(resource, options)
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 @@ def map_has_many_associations(resource, associations, options)
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 @@ def map_collection_actions(map, resource)
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 @@ def map_member_actions(map, resource)
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)
View
1 actionpack/lib/action_controller/test_process.rb
@@ -394,6 +394,7 @@ def process(action, parameters = nil, session = nil, flash = nil)
@html_document = nil
@request.env['REQUEST_METHOD'] ||= "GET"
+
@request.action = action.to_s
parameters ||= {}
View
2 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
View
10 actionpack/lib/action_view/helpers/tag_helper.rb
@@ -133,10 +133,12 @@ def tag_options(options, escape = true)
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}") }
View
50 actionpack/lib/action_view/helpers/text_helper.rb
@@ -545,38 +545,36 @@ def set_cycle(name, cycle_object)
end
AUTO_LINK_RE = %r{
- ( # leading text
- <\w+.*?>| # leading HTML tag, or
- [^=!:'"/]| # leading punctuation, or
- ^ # beginning of line
- )
- (
- (?:https?://)| # protocol spec, or
- (?:www\.) # www.*
- )
- (
- [-\w]+ # subdomain or domain
- (?:\.[-\w]+)* # remaining subdomains or domain
- (?::\d+)? # port
- (?:/(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$]))*)* # path
- (?:\?[\w\+@%&=.;:-]+)? # query string
- (?:\#[\w\-]*)? # trailing anchor
- )
- ([[:punct:]]|<|$|) # trailing text
- }x unless const_defined?(:AUTO_LINK_RE)
+ ( https?:// | www\. )
+ [^\s<]+
+ }x unless const_defined?(:AUTO_LINK_RE)
+
+ BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
# Turns all urls into clickable links. If a block is given, each url
# is yielded and the result is used as the link text.
def auto_link_urls(text, html_options = {})
- extra_options = tag_options(html_options.stringify_keys) || ""
+ link_attributes = html_options.stringify_keys
text.gsub(AUTO_LINK_RE) do
- all, a, b, c, d = $&, $1, $2, $3, $4
- if a =~ /<a\s/i # don't replace URL's that are already linked
- all
+ href = $&
+ punctuation = ''
+ # detect already linked URLs
+ if $` =~ /<a\s[^>]*href="$/
+ # do not change string; URL is alreay linked
+ href
else
- text = b + c
- text = yield(text) if block_given?
- %(#{a}<a href="#{b=="www."?"http://www.":b}#{c}"#{extra_options}>#{text}</a>#{d})
+ # don't include trailing punctuation character as part of the URL
+ if href.sub!(/[^\w\/-]$/, '') and punctuation = $& and opening = BRACKETS[punctuation]
+ if href.scan(opening).size > href.scan(punctuation).size
+ href << punctuation
+ punctuation = ''
+ end
+ end
+
+ link_text = block_given?? yield(href) : href
+ href = 'http://' + href unless href.index('http') == 0
+
+ content_tag(:a, h(link_text), link_attributes.merge('href' => href)) + punctuation
end
end
end
View
12 actionpack/test/controller/mime_type_test.rb
@@ -61,7 +61,9 @@ def test_type_convenience_methods
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 @@ def test_mime_all_is_html
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
View
11 actionpack/test/controller/polymorphic_routes_test.rb
@@ -168,6 +168,17 @@ def test_nesting_with_array_containing_singleton_resource_and_format_option
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)
View
118 actionpack/test/controller/request_forgery_protection_test.rb
@@ -77,57 +77,61 @@ def teardown
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 @@ def test_should_not_allow_api_formatted_delete_sent_as_multipart_form_without_to
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 < ActionController::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 @@ def session_id() '123' end
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 < ActionController::TestCase
@@ -304,10 +313,15 @@ def setup
@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
View
266 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 @@ def test_with_path_segment_path_prefix_requirements
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 @@ def assert_resource_methods(expected, resource, action_method, method)
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
View
2 actionpack/test/template/form_tag_helper_test.rb
@@ -235,7 +235,7 @@ def test_label_tag_id_sanitized
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)
View
4 actionpack/test/template/tag_helper_test.rb
@@ -19,6 +19,10 @@ def test_tag_options_rejects_nil_option
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
View
145 actionpack/test/template/text_helper_test.rb
@@ -205,56 +205,48 @@ def test_pluralization
end
def test_auto_link_parsing
- urls = %w(http://www.rubyonrails.com
- http://www.rubyonrails.com:80
- http://www.rubyonrails.com/~minam
- https://www.rubyonrails.com/~minam
- http://www.rubyonrails.com/~minam/url%20with%20spaces
- http://www.rubyonrails.com/foo.cgi?something=here
- http://www.rubyonrails.com/foo.cgi?something=here&and=here
- http://www.rubyonrails.com/contact;new
- http://www.rubyonrails.com/contact;new%20with%20spaces
- http://www.rubyonrails.com/contact;new?with=query&string=params
- http://www.rubyonrails.com/~minam/contact;new?with=query&string=params
- http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007
- http://www.mail-archive.com/rails@lists.rubyonrails.org/
- 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 = %w(
+ http://www.rubyonrails.com
+ http://www.rubyonrails.com:80
+ http://www.rubyonrails.com/~minam
+ https://www.rubyonrails.com/~minam
+ http://www.rubyonrails.com/~minam/url%20with%20spaces
+ http://www.rubyonrails.com/foo.cgi?something=here
+ http://www.rubyonrails.com/foo.cgi?something=here&and=here
+ http://www.rubyonrails.com/contact;new
+ http://www.rubyonrails.com/contact;new%20with%20spaces
+ http://www.rubyonrails.com/contact;new?with=query&string=params
+ http://www.rubyonrails.com/~minam/contact;new?with=query&string=params
+ http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007
+ http://www.mail-archive.com/rails@lists.rubyonrails.org/
+ 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/Texas_hold'em
+ https://www.google.com/doku.php?id=gps:resource:scs:start
+ http://connect.oraclecorp.com/search?search[q]=green+france&search[type]=Group
+ http://of.openfoundry.org/projects/492/download#4th.Release.3
+ http://maps.google.co.uk/maps?f=q&q=the+london+eye&ie=UTF8&ll=51.503373,-0.11939&spn=0.007052,0.012767&z=16&iwloc=A
+ )
urls.each do |url|
- assert_equal %(<a href="#{url}">#{url}</a>), auto_link(url)
+ assert_equal generate_result(url), auto_link(url)
end
end
+ def generate_result(link_text, href = nil)
+ href ||= link_text
+ %{<a href="#{CGI::escapeHTML href}">#{CGI::escapeHTML link_text}</a>}
+ end
+
def test_auto_linking
email_raw = 'david@loudthinking.com'
email_result = %{<a href="mailto:#{email_raw}">#{email_raw}</a>}
- email2_raw = '+david@loudthinking.com'
- email2_result = %{<a href="mailto:#{email2_raw}">#{email2_raw}</a>}
link_raw = 'http://www.rubyonrails.com'
- link_result = %{<a href="#{link_raw}">#{link_raw}</a>}
- link_result_with_options = %{<a href="#{link_raw}" target="_blank">#{link_raw}</a>}
- link2_raw = 'www.rubyonrails.com'
- link2_result = %{<a href="http://#{link2_raw}">#{link2_raw}</a>}
- link3_raw = 'http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281'
- link3_result = %{<a href="#{link3_raw}">#{link3_raw}</a>}
- link4_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor123'
- link4_result = %{<a href="#{link4_raw}">#{link4_raw}</a>}
- link5_raw = 'http://foo.example.com:3000/controller/action'
- link5_result = %{<a href="#{link5_raw}">#{link5_raw}</a>}
- link6_raw = 'http://foo.example.com:3000/controller/action+pack'
- link6_result = %{<a href="#{link6_raw}">#{link6_raw}</a>}
- link7_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor-123'
- link7_result = %{<a href="#{link7_raw}">#{link7_raw}</a>}
- link8_raw = 'http://foo.example.com:3000/controller/action.html'
- link8_result = %{<a href="#{link8_raw}">#{link8_raw}</a>}
- link9_raw = 'http://business.timesonline.co.uk/article/0,,9065-2473189,00.html'
- link9_result = %{<a href="#{link9_raw}">#{link9_raw}</a>}
- link10_raw = 'http://www.mail-archive.com/ruby-talk@ruby-lang.org/'
- link10_result = %{<a href="#{link10_raw}">#{link10_raw}</a>}
+ link_result = generate_result(link_raw)
+ link_result_with_options = %{<a href="#{link_raw}" target="_blank">#{link_raw}</a>}
+
+ assert_equal '', auto_link(nil)
+ assert_equal '', auto_link('')
+ assert_equal "#{link_result} #{link_result} #{link_result}", auto_link("#{link_raw} #{link_raw} #{link_raw}")
assert_equal %(hello #{email_result}), auto_link("hello #{email_raw}", :email_addresses)
assert_equal %(Go to #{link_result}), auto_link("Go to #{link_raw}", :urls)
@@ -265,41 +257,94 @@ def test_auto_linking
assert_equal %(<p>Link #{link_result_with_options}</p>), auto_link("<p>Link #{link_raw}</p>", :all, {:target => "_blank"})
assert_equal %(Go to #{link_result}.), auto_link(%(Go to #{link_raw}.))
assert_equal %(<p>Go to #{link_result}, then say hello to #{email_result}.</p>), auto_link(%(<p>Go to #{link_raw}, then say hello to #{email_raw}.</p>))
+
+ email2_raw = '+david@loudthinking.com'
+ email2_result = %{<a href="mailto:#{email2_raw}">#{email2_raw}</a>}
+ assert_equal email2_result, auto_link(email2_raw)
+
+ link2_raw = 'www.rubyonrails.com'
+ link2_result = generate_result(link2_raw, "http://#{link2_raw}")
assert_equal %(Go to #{link2_result}), auto_link("Go to #{link2_raw}", :urls)
assert_equal %(Go to #{link2_raw}), auto_link("Go to #{link2_raw}", :email_addresses)
assert_equal %(<p>Link #{link2_result}</p>), auto_link("<p>Link #{link2_raw}</p>")
assert_equal %(<p>#{link2_result} Link</p>), auto_link("<p>#{link2_raw} Link</p>")
assert_equal %(Go to #{link2_result}.), auto_link(%(Go to #{link2_raw}.))
assert_equal %(<p>Say hello to #{email_result}, then go to #{link2_result}.</p>), auto_link(%(<p>Say hello to #{email_raw}, then go to #{link2_raw}.</p>))
+
+ link3_raw = 'http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281'
+ link3_result = generate_result(link3_raw)
assert_equal %(Go to #{link3_result}), auto_link("Go to #{link3_raw}", :urls)
assert_equal %(Go to #{link3_raw}), auto_link("Go to #{link3_raw}", :email_addresses)
assert_equal %(<p>Link #{link3_result}</p>), auto_link("<p>Link #{link3_raw}</p>")
assert_equal %(<p>#{link3_result} Link</p>), auto_link("<p>#{link3_raw} Link</p>")
assert_equal %(Go to #{link3_result}.), auto_link(%(Go to #{link3_raw}.))
- assert_equal %(<p>Go to #{link3_result}. seriously, #{link3_result}? i think I'll say hello to #{email_result}. instead.</p>), auto_link(%(<p>Go to #{link3_raw}. seriously, #{link3_raw}? i think I'll say hello to #{email_raw}. instead.</p>))
+ assert_equal %(<p>Go to #{link3_result}. Seriously, #{link3_result}? I think I'll say hello to #{email_result}. Instead.</p>),
+ auto_link(%(<p>Go to #{link3_raw}. Seriously, #{link3_raw}? I think I'll say hello to #{email_raw}. Instead.</p>))
+
+ link4_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor123'
+ link4_result = generate_result(link4_raw)
assert_equal %(<p>Link #{link4_result}</p>), auto_link("<p>Link #{link4_raw}</p>")
assert_equal %(<p>#{link4_result} Link</p>), auto_link("<p>#{link4_raw} Link</p>")
+
+ link5_raw = 'http://foo.example.com:3000/controller/action'
+ link5_result = generate_result(link5_raw)
assert_equal %(<p>#{link5_result} Link</p>), auto_link("<p>#{link5_raw} Link</p>")
+
+ link6_raw = 'http://foo.example.com:3000/controller/action+pack'
+ link6_result = generate_result(link6_raw)
assert_equal %(<p>#{link6_result} Link</p>), auto_link("<p>#{link6_raw} Link</p>")
+
+ link7_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor-123'
+ link7_result = generate_result(link7_raw)
assert_equal %(<p>#{link7_result} Link</p>), auto_link("<p>#{link7_raw} Link</p>")
+
+ link8_raw = 'http://foo.example.com:3000/controller/action.html'
+ link8_result = generate_result(link8_raw)
assert_equal %(Go to #{link8_result}), auto_link("Go to #{link8_raw}", :urls)
assert_equal %(Go to #{link8_raw}), auto_link("Go to #{link8_raw}", :email_addresses)
assert_equal %(<p>Link #{link8_result}</p>), auto_link("<p>Link #{link8_raw}</p>")
assert_equal %(<p>#{link8_result} Link</p>), auto_link("<p>#{link8_raw} Link</p>")
assert_equal %(Go to #{link8_result}.), auto_link(%(Go to #{link8_raw}.))
- assert_equal %(<p>Go to #{link8_result}. seriously, #{link8_result}? i think I'll say hello to #{email_result}. instead.</p>), auto_link(%(<p>Go to #{link8_raw}. seriously, #{link8_raw}? i think I'll say hello to #{email_raw}. instead.</p>))
+ assert_equal %(<p>Go to #{link8_result}. Seriously, #{link8_result}? I think I'll say hello to #{email_result}. Instead.</p>),
+ auto_link(%(<p>Go to #{link8_raw}. Seriously, #{link8_raw}? I think I'll say hello to #{email_raw}. Instead.</p>))
+
+ link9_raw = 'http://business.timesonline.co.uk/article/0,,9065-2473189,00.html'
+ link9_result = generate_result(link9_raw)
assert_equal %(Go to #{link9_result}), auto_link("Go to #{link9_raw}", :urls)
assert_equal %(Go to #{link9_raw}), auto_link("Go to #{link9_raw}", :email_addresses)
assert_equal %(<p>Link #{link9_result}</p>), auto_link("<p>Link #{link9_raw}</p>")
assert_equal %(<p>#{link9_result} Link</p>), auto_link("<p>#{link9_raw} Link</p>")
assert_equal %(Go to #{link9_result}.), auto_link(%(Go to #{link9_raw}.))
- assert_equal %(<p>Go to #{link9_result}. seriously, #{link9_result}? i think I'll say hello to #{email_result}. instead.</p>), auto_link(%(<p>Go to #{link9_raw}. seriously, #{link9_raw}? i think I'll say hello to #{email_raw}. instead.</p>))
+ assert_equal %(<p>Go to #{link9_result}. Seriously, #{link9_result}? I think I'll say hello to #{email_result}. Instead.</p>),
+ auto_link(%(<p>Go to #{link9_raw}. Seriously, #{link9_raw}? I think I'll say hello to #{email_raw}. Instead.</p>))
+
+ link10_raw = 'http://www.mail-archive.com/ruby-talk@ruby-lang.org/'
+ link10_result = generate_result(link10_raw)
assert_equal %(<p>#{link10_result} Link</p>), auto_link("<p>#{link10_raw} Link</p>")
- assert_equal email2_result, auto_link(email2_raw)
- assert_equal '', auto_link(nil)
- assert_equal '', auto_link('')
- assert_equal "#{link_result} #{link_result} #{link_result}", auto_link("#{link_raw} #{link_raw} #{link_raw}")
- assert_equal '<a href="http://www.rubyonrails.com">Ruby On Rails</a>', auto_link('<a href="http://www.rubyonrails.com">Ruby On Rails</a>')
+ end
+
+ def test_auto_link_already_linked
+ linked1 = generate_result('Ruby On Rails', 'http://www.rubyonrails.com')
+ linked2 = generate_result('www.rubyonrails.com', 'http://www.rubyonrails.com')
+ assert_equal linked1, auto_link(linked1)
+ assert_equal linked2, auto_link(linked2)
+ end
+
+ def test_auto_link_with_brackets
+ link1_raw = 'http://en.wikipedia.org/wiki/Sprite_(computer_graphics)'
+ link1_result = generate_result(link1_raw)
+ assert_equal link1_result, auto_link(link1_raw)
+ assert_equal "(link: #{link1_result})", auto_link("(link: #{link1_raw})")
+
+ link2_raw = 'http://en.wikipedia.org/wiki/Sprite_[computer_graphics]'
+ link2_result = generate_result(link2_raw)
+ assert_equal link2_result, auto_link(link2_raw)
+ assert_equal "[link: #{link2_result}]", auto_link("[link: #{link2_raw}]")
+
+ link3_raw = 'http://en.wikipedia.org/wiki/Sprite_{computer_graphics}'
+ link3_result = generate_result(link3_raw)
+ assert_equal link3_result, auto_link(link3_raw)
+ assert_equal "{link: #{link3_result}}", auto_link("{link: #{link3_raw}}")
end
def test_auto_link_at_eol
@@ -317,7 +362,7 @@ def test_auto_link_with_block
end
def test_auto_link_with_options_hash
- assert_equal 'Welcome to my new blog at <a href="http://www.myblog.com/" class="menu" target="_blank">http://www.myblog.com/</a>. Please e-mail me at <a href="mailto:me@email.com">me@email.com</a>.',
+ assert_dom_equal 'Welcome to my new blog at <a href="http://www.myblog.com/" class="menu" target="_blank">http://www.myblog.com/</a>. Please e-mail me at <a href="mailto:me@email.com">me@email.com</a>.',
auto_link("Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com.",
:link => :all, :html => { :class => "menu", :target => "_blank" })
end
View
2 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]
View
2 activerecord/Rakefile
@@ -171,7 +171,7 @@ spec = Gem::Specification.new do |s|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
end
- s.add_dependency('activesupport', '= 2.2.0' + PKG_BUILD)
+ s.add_dependency('activesupport', '= 2.2.1' + PKG_BUILD)
s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite"
s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite"
View
2 activerecord/lib/active_record/association_preload.rb
@@ -312,7 +312,7 @@ def preload_belongs_to_association(records, reflection, preload_options={})
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
View
7 activerecord/lib/active_record/associations/has_one_through_association.rb
@@ -8,11 +8,10 @@ def create_through_record(new_value) #nodoc:
current_object = @owner.send(@reflection.through_reflection.name)
if current_object
- klass.destroy(current_object)
- @owner.clear_association_cache
+ current_object.update_attributes(construct_join_attributes(new_value))
+ else
+ @owner.send(@reflection.through_reflection.name, klass.send(:create, construct_join_attributes(new_value)))
end
-
- @owner.send(@reflection.through_reflection.name, klass.send(:create, construct_join_attributes(new_value)))
end
private
View
10 activerecord/lib/active_record/base.rb
@@ -1612,9 +1612,17 @@ def type_name_with_module(type_name)
end
end
+ def default_select(qualified)
+ if qualified
+ quoted_table_name + '.*'
+ else
+ '*'
+ end
+ end
+
def construct_finder_sql(options)
scope = scope(:find)
- sql = "SELECT #{options[:select] || (scope && scope[:select]) || ((options[:joins] || (scope && scope[:joins])) && quoted_table_name + '.*') || '*'} "
+ sql = "SELECT #{options[:select] || (scope && scope[:select]) || default_select(options[:joins] || (scope && scope[:joins]))} "
sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
add_joins!(sql, options[:joins], scope)
View
2 activerecord/lib/active_record/calculations.rb
@@ -286,7 +286,7 @@ def type_cast_calculated_value(value, column, operation = nil)
case operation
when 'count' then value.to_i
when 'sum' then type_cast_using_column(value || '0', column)
- when 'avg' then value && (value == 0 ? 0.0.to_d : 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
View
2 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
View
40 activerecord/test/cases/associations/has_one_through_associations_test.rb
@@ -3,9 +3,11 @@
require 'models/member'
require 'models/membership'
require 'models/sponsor'
+require 'models/organization'
+require 'models/member_detail'
class HasOneThroughAssociationsTest < ActiveRecord::TestCase
- fixtures :members, :clubs, :memberships, :sponsors
+ fixtures :members, :clubs, :memberships, :sponsors, :organizations
def setup
@member = members(:groucho)
@@ -120,4 +122,40 @@ def test_has_one_through_proxy_should_respond_to_private_methods_via_send
clubs(:moustache_club).send(:private_method)
@member.club.send(:private_method)
end
+
+ def test_assigning_to_has_one_through_preserves_decorated_join_record
+ @organization = organizations(:nsa)
+ assert_difference 'MemberDetail.count', 1 do
+ @member_detail = MemberDetail.new(:extra_data => 'Extra')
+ @member.member_detail = @member_detail
+ @member.organization = @organization
+ end
+ assert_equal @organization, @member.organization
+ assert @organization.members.include?(@member)
+ assert_equal 'Extra', @member.member_detail.extra_data
+ end
+
+ def test_reassigning_has_one_through
+ @organization = organizations(:nsa)
+ @new_organization = organizations(:discordians)
+
+ assert_difference 'MemberDetail.count', 1 do
+ @member_detail = MemberDetail.new(:extra_data => 'Extra')
+ @member.member_detail = @member_detail
+ @member.organization = @organization
+ end
+ assert_equal @organization, @member.organization
+ assert_equal 'Extra', @member.member_detail.extra_data
+ assert @organization.members.include?(@member)
+ assert !@new_organization.members.include?(@member)
+
+ assert_no_difference 'MemberDetail.count' do
+ @member.organization = @new_organization
+ end
+ assert_equal @new_organization, @member.organization
+ assert_equal 'Extra', @member.member_detail.extra_data
+ assert !@organization.members.include?(@member)
+ assert @new_organization.members.include?(@member)
+ end
+
end
View
5 activerecord/test/cases/calculations_test.rb
@@ -25,6 +25,11 @@ def test_should_average_field
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)
View
2 activerecord/test/cases/pooled_connections_test.rb
@@ -77,7 +77,7 @@ def test_pooled_connection_checkout_existing_first
conn_pool.checkin(conn)
end
- def test_not_connected_defined_connection_reutnrs_false
+ def test_not_connected_defined_connection_returns_false
ActiveRecord::Base.establish_connection(@connection)
assert ! ActiveRecord::Base.connected?
end
View
5 activerecord/test/fixtures/organizations.yml
@@ -0,0 +1,5 @@
+nsa:
+ name: No Such Agency
+discordians:
+ name: Discordians
+
View
2 activerecord/test/models/member.rb
@@ -6,4 +6,6 @@ class Member < ActiveRecord::Base
has_one :favourite_club, :through => :memberships, :conditions => ["memberships.favourite = ?", true], :source => :club
has_one :sponsor, :as => :sponsorable
has_one :sponsor_club, :through => :sponsor
+ has_one :member_detail
+ has_one :organization, :through => :member_detail
end
View
4 activerecord/test/models/member_detail.rb
@@ -0,0 +1,4 @@
+class MemberDetail < ActiveRecord::Base
+ belongs_to :member
+ belongs_to :organization
+end
View
4 activerecord/test/models/organization.rb
@@ -0,0 +1,4 @@
+class Organization < ActiveRecord::Base
+ has_many :member_details
+ has_many :members, :through => :member_details
+end
View
10 activerecord/test/schema/schema.rb
@@ -197,6 +197,12 @@ def create_table(*args, &block)
t.string :name
end
+ create_table :member_details, :force => true do |t|
+ t.integer :member_id
+ t.integer :organization_id
+ t.string :extra_data
+ end
+
create_table :memberships, :force => true do |t|
t.datetime :joined_on
t.integer :club_id, :member_id
@@ -249,6 +255,10 @@ def create_table(*args, &block)
t.integer :shipping_customer_id
end
+ create_table :organizations, :force => true do |t|
+ t.string :name
+ end
+
create_table :owners, :primary_key => :owner_id ,:force => true do |t|
t.string :name
end
View
2 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]
View
2 activeresource/Rakefile
@@ -65,7 +65,7 @@ spec = Gem::Specification.new do |s|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
end
- s.add_dependency('activesupport', '= 2.2.0' + PKG_BUILD)
+ s.add_dependency('activesupport', '= 2.2.1' + PKG_BUILD)
s.require_path = 'lib'
s.autorequire = 'active_resource'
View
2 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
View
9 activesupport/CHANGELOG
@@ -1,6 +1,11 @@
-*2.2.1 [RC2 or 2.2 final]*
+*2.3.0/3.0*
-* Added render :js for people who want to render inline JavaScript replies without using RJS [DHH]
+* Added lambda merging to OptionMerger (especially useful with named_scope and with_options) #726 [Paweł Kondzior]
+
+
+*2.2.1 [RC2] (November 14th, 2008)*
+
+* Increment the version of our altered memcache-client to prevent confusion caused when the 1.5.0 gem is installed.
* Fixed the option merging in Array#to_xml #1126 [Rudolf Gavlas]
View
8 activesupport/lib/active_support/option_merger.rb
@@ -10,7 +10,13 @@ def initialize(context, options)
private
def method_missing(method, *arguments, &block)
- arguments << (arguments.last.respond_to?(:to_hash) ? @options.deep_merge(arguments.pop) : @options.dup)
+ if arguments.last.is_a?(Proc)
+ proc = arguments.pop
+ arguments << lambda { |*args| @options.deep_merge(proc.call(*args)) }
+ else
+ arguments << (arguments.last.respond_to?(:to_hash) ? @options.deep_merge(arguments.pop) : @options.dup)
+ end
+
@context.__send__(method, *arguments, &block)
end
end
View
7 activesupport/lib/active_support/values/time_zone.rb
@@ -304,7 +304,8 @@ def tzinfo
"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 @@ def tzinfo
[ 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" ],
View
2 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
View
8 activesupport/test/option_merger_test.rb