From 44a3009ff068bf080de6764a8c884fbf0ceb920e Mon Sep 17 00:00:00 2001 From: Tom Stuart Date: Wed, 12 Nov 2008 11:00:17 +0000 Subject: Add :only/:except options to map.resources This allows people with huge numbers of resource routes to cut down on the memory consumption caused by the generated code. Signed-off-by: Michael Koziarski [#1215 state:committed] --- actionpack/lib/action_controller/resources.rb | 122 +++++++++++++------ actionpack/test/controller/resources_test.rb | 162 ++++++++++++++++++++++++++ 2 files changed, 247 insertions(+), 37 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index 872b0dab3d..de529e23ff 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, :only, :except + 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) || action_allowed?(action) + end + protected def arrange_actions @collection_methods = arrange_actions_by_methods(options.delete(:collection)) @@ -125,6 +134,30 @@ module ActionController add_default_action(new_methods, :get, :new) end + def set_allowed_actions + only, except = @options.values_at(:only, :except) + @allowed_actions ||= {} + + if only == :all || except == :none + only = nil + except = [] + elsif only == :none || except == :all + only = [] + except = nil + end + + if only + @allowed_actions[:only] = Array(only).map(&:to_sym) + elsif except + @allowed_actions[:except] = Array(except).map(&:to_sym) + end + end + + def action_allowed?(action) + only, except = @allowed_actions.values_at(:only, :except) + (!only || only.include?(action)) && (!except || !except.include?(action)) + end + def set_prefixes @path_prefix = options.delete(:path_prefix) @name_prefix = options.delete(:name_prefix) @@ -353,6 +386,25 @@ module ActionController # # map.resources :users, :has_many => { :posts => :comments }, :shallow => true # + # * :only and :except - Specify which of the seven default actions should be routed to. + # + # :only and :except may be set to :all, :none, 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 :only and :except options are inherited by any nested resource(s). + # # If map.resources is called with multiple resources, they all get the same options applied. # # Examples: @@ -478,7 +530,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 +547,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 +559,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 +574,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 +583,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) 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) 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 +624,32 @@ 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) + map_resource_routes(map, resource, :show, resource.member_path, "#{resource.shallow_name_prefix}#{resource.singular}") + map_resource_routes(map, resource, :update, resource.member_path) + map_resource_routes(map, resource, :destroy, resource.member_path) end - def map_unnamed_routes(map, path_without_format, options) - map.connect(path_without_format, options) - map.connect("#{path_without_format}.:format", options) - 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 + 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/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index 1fea82e564..2a86577d8c 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,121 @@ 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_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 + protected def with_restful_routing(*args) with_routing do |set| @@ -979,6 +1096,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 -- cgit v1.2.3 From fbbcd6f29aeccc938b97b5c01717365f8b67912c Mon Sep 17 00:00:00 2001 From: Jeff Cohen Date: Fri, 31 Oct 2008 23:10:44 -0500 Subject: Changed request forgery protection to only worry about HTML-formatted content requests. Signed-off-by: Michael Koziarski --- actionpack/lib/action_controller/mime_type.rb | 4 +- .../request_forgery_protection.rb | 2 +- actionpack/lib/action_controller/test_process.rb | 1 + .../controller/request_forgery_protection_test.rb | 118 ++++++++++++--------- 4 files changed, 70 insertions(+), 55 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb index 26edca3b69..f43ae721c6 100644 --- a/actionpack/lib/action_controller/mime_type.rb +++ b/actionpack/lib/action_controller/mime_type.rb @@ -19,7 +19,7 @@ module Mime # end # end class Type - @@html_types = Set.new [:html, :all] + @@html_types = Set.new [:html, :url_encoded_form, :multipart_form, :all] @@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml] cattr_reader :html_types, :unverifiable_types @@ -167,7 +167,7 @@ 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) + html? end def html? 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 :secret option 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/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 -- cgit v1.2.3 From 00c46b5eeb858629ef1c7ab50f022aecccca42c3 Mon Sep 17 00:00:00 2001 From: rick Date: Wed, 12 Nov 2008 13:34:29 -0800 Subject: fix two MimeType failing test cases Signed-off-by: Michael Koziarski --- actionpack/lib/action_controller/mime_type.rb | 5 ++++- actionpack/test/controller/mime_type_test.rb | 12 ++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb index f43ae721c6..48c4c1ee1e 100644 --- a/actionpack/lib/action_controller/mime_type.rb +++ b/actionpack/lib/action_controller/mime_type.rb @@ -20,8 +20,11 @@ module Mime # end class Type @@html_types = Set.new [:html, :url_encoded_form, :multipart_form, :all] + cattr_reader :html_types + + # UNUSED, deprecate? @@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml] - cattr_reader :html_types, :unverifiable_types + cattr_reader :unverifiable_types # A simple helper class used in parsing the accept header class AcceptItem #:nodoc: diff --git a/actionpack/test/controller/mime_type_test.rb b/actionpack/test/controller/mime_type_test.rb index f16a3c68b4..4cfaf38ac7 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.html_types.include? type } + assert verified.each { |type| assert Mime.const_get(type.to_s.upcase).verify_request?, "Mime Type is not verified: #{type.inspect}" } + assert unverified.each { |type| assert !Mime.const_get(type.to_s.upcase).verify_request?, "Mime Type is verified: #{type.inspect}" } end end -- cgit v1.2.3 From f1ad8b48aae3ee26613b3e77bc0056e120096846 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Thu, 13 Nov 2008 11:19:53 +0100 Subject: Instead of overriding html_types, base the verification on browser_generated_types. Also Deprecate the old unverifiable types. [#1145 state:committed] --- actionpack/lib/action_controller/mime_type.rb | 21 +++++++++++++++++---- actionpack/test/controller/mime_type_test.rb | 6 +++--- 2 files changed, 20 insertions(+), 7 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb index 48c4c1ee1e..8ca3a70341 100644 --- a/actionpack/lib/action_controller/mime_type.rb +++ b/actionpack/lib/action_controller/mime_type.rb @@ -19,12 +19,21 @@ module Mime # end # end class Type - @@html_types = Set.new [:html, :url_encoded_form, :multipart_form, :all] + @@html_types = Set.new [:html, :all] cattr_reader :html_types - # UNUSED, deprecate? + # 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 :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: @@ -170,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? - html? + 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/test/controller/mime_type_test.rb b/actionpack/test/controller/mime_type_test.rb index 4cfaf38ac7..21ae0419f1 100644 --- a/actionpack/test/controller/mime_type_test.rb +++ b/actionpack/test/controller/mime_type_test.rb @@ -77,8 +77,8 @@ class MimeTypeTest < Test::Unit::TestCase 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) } - verified, unverified = all_types.partition { |type| Mime::Type.html_types.include? type } - assert verified.each { |type| assert Mime.const_get(type.to_s.upcase).verify_request?, "Mime Type is not verified: #{type.inspect}" } - assert unverified.each { |type| assert !Mime.const_get(type.to_s.upcase).verify_request?, "Mime Type is verified: #{type.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 -- cgit v1.2.3 From 4c0921024471c0463d67f8b8fb6a115a94d343aa Mon Sep 17 00:00:00 2001 From: Tom Stuart Date: Thu, 13 Nov 2008 14:31:36 +0000 Subject: Fix map.resources to always generate named routes if they're needed Signed-off-by: Michael Koziarski --- actionpack/lib/action_controller/resources.rb | 13 ++--- actionpack/test/controller/resources_test.rb | 78 +++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index de529e23ff..d6cc4aa418 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -597,11 +597,11 @@ module ActionController end map_resource_routes(map, resource, :index, resource.path, index_route_name) - map_resource_routes(map, resource, :create, resource.path) + map_resource_routes(map, resource, :create, resource.path, index_route_name) end def map_default_singleton_actions(map, resource) - map_resource_routes(map, resource, :create, resource.path) + map_resource_routes(map, resource, :create, resource.path, "#{resource.shallow_name_prefix}#{resource.singular}") end def map_new_actions(map, resource) @@ -632,9 +632,10 @@ module ActionController end end - map_resource_routes(map, resource, :show, resource.member_path, "#{resource.shallow_name_prefix}#{resource.singular}") - map_resource_routes(map, resource, :update, resource.member_path) - map_resource_routes(map, resource, :destroy, resource.member_path) + 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_resource_routes(map, resource, action, route_path, route_name = nil, method = nil) @@ -642,7 +643,7 @@ module ActionController action_options = action_options_for(action, resource, method) formatted_route_path = "#{route_path}.:format" - if route_name + 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 diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index 2a86577d8c..1f1f7b8a2c 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -822,6 +822,84 @@ class ResourcesTest < Test::Unit::TestCase 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| -- cgit v1.2.3 From 4e9abdd7f1b4e05f8d1b50ddaa080b3ff63b92d9 Mon Sep 17 00:00:00 2001 From: "Hongli Lai (Phusion)" Date: Thu, 13 Nov 2008 21:49:23 +0100 Subject: Tag helper should output an attribute with the value 'false' instead of omitting the attribute, if the associated option is false but not nil. --- actionpack/lib/action_view/helpers/tag_helper.rb | 10 ++++++---- actionpack/test/template/form_tag_helper_test.rb | 2 +- actionpack/test/template/tag_helper_test.rb | 4 ++++ 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'actionpack') 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/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 %(), check_box_tag("admin", 1, true, 'disabled' => true, :readonly => "yes") assert_dom_equal %(), check_box_tag("admin", 1, true, :disabled => false, :readonly => nil) assert_dom_equal %(), select_tag("people", "", :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 "

", tag("p", :ignored => nil) end + def test_tag_options_accepts_false_option + assert_equal "

", tag("p", :value => false) + end + def test_tag_options_accepts_blank_option assert_equal "

", tag("p", :included => '') end -- cgit v1.2.3 From 94d6716324126028b89dde886f160474049b1b0c Mon Sep 17 00:00:00 2001 From: hiroshi Date: Mon, 3 Nov 2008 14:09:07 +0900 Subject: Make polymorphic_url compact given array [#1317 state:committed] Signed-off-by: David Heinemeier Hansson --- actionpack/CHANGELOG | 2 ++ actionpack/lib/action_controller/polymorphic_routes.rb | 2 +- actionpack/test/controller/polymorphic_routes_test.rb | 11 +++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index e7d5031f1a..97389dfc20 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *2.2.1 [RC2 or 2.2 final]* +* 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/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/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) -- cgit v1.2.3 From 2ecec6052f7f290252a9fd9cc27ec804c7aad36c Mon Sep 17 00:00:00 2001 From: Tom Stuart Date: Thu, 13 Nov 2008 20:00:11 +0000 Subject: Make inheritance of map.resources :only/:except options behave more predictably Signed-off-by: Michael Koziarski --- actionpack/lib/action_controller/resources.rb | 33 ++++++++++++--------------- actionpack/test/controller/resources_test.rb | 26 +++++++++++++++++++++ 2 files changed, 40 insertions(+), 19 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index d6cc4aa418..7700b9d4d0 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -42,7 +42,7 @@ module ActionController # # Read more about REST at http://en.wikipedia.org/wiki/Representational_State_Transfer module Resources - INHERITABLE_OPTIONS = :namespace, :shallow, :only, :except + INHERITABLE_OPTIONS = :namespace, :shallow, :actions class Resource #:nodoc: DEFAULT_ACTIONS = :index, :create, :new, :edit, :show, :update, :destroy @@ -119,7 +119,7 @@ module ActionController end def has_action?(action) - !DEFAULT_ACTIONS.include?(action) || action_allowed?(action) + !DEFAULT_ACTIONS.include?(action) || @options[:actions].nil? || @options[:actions].include?(action) end protected @@ -135,29 +135,24 @@ module ActionController end def set_allowed_actions - only, except = @options.values_at(:only, :except) - @allowed_actions ||= {} + only = @options.delete(:only) + except = @options.delete(:except) - if only == :all || except == :none - only = nil - 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 - only = [] - except = nil - end - - if only - @allowed_actions[:only] = Array(only).map(&:to_sym) + options[:actions] = [] + elsif only + options[:actions] = DEFAULT_ACTIONS & Array(only).map(&:to_sym) elsif except - @allowed_actions[:except] = Array(except).map(&:to_sym) + options[:actions] = DEFAULT_ACTIONS - Array(except).map(&:to_sym) + else + # leave options[:actions] alone end end - def action_allowed?(action) - only, except = @allowed_actions.values_at(:only, :except) - (!only || only.include?(action)) && (!except || !except.include?(action)) - end - def set_prefixes @path_prefix = options.delete(:path_prefix) @name_prefix = options.delete(:name_prefix) diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index 1f1f7b8a2c..04f7a0a528 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -971,6 +971,32 @@ class ResourcesTest < Test::Unit::TestCase 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| -- cgit v1.2.3 From 61e43700b85de753b6254893d5365e04d3465b9a Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 14 Nov 2008 12:26:50 +0100 Subject: Prepare for RC2 --- actionpack/CHANGELOG | 4 +++- actionpack/lib/action_pack/version.rb | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 97389dfc20..dc7ee64358 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,4 +1,6 @@ -*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] 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 -- cgit v1.2.3 From c70b993a9e01547de88417cb8fa95b48acbed2db Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 14 Nov 2008 17:47:21 +0530 Subject: Merge docrails. --- actionpack/lib/action_controller/base.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 43f6c1be44..f35c42f929 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -1029,10 +1029,10 @@ module ActionController #:nodoc: # # * Hash - The URL will be generated by calling url_for with the +options+. # * Record - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record. - # * String starting with protocol:// (like http://) - Is passed straight through as the target for redirection. - # * String not containing a protocol - The current protocol and host is prepended to the string. + # * String starting with protocol:// (like http://) - Is passed straight through as the target for redirection. + # * String not containing a protocol - The current protocol and host is prepended to the string. # * :back - 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 redirect_to(request.env["HTTP_REFERER"]) # # Examples: # redirect_to :action => "show", :id => 5 -- cgit v1.2.3 From 3be853b59d3175e74ef4564b78309c10bc0cc550 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 14 Nov 2008 14:08:26 +0100 Subject: A few more dependency updates --- actionpack/Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 73da8b1ce3..4020b4aa78 100644 --- a/actionpack/Rakefile +++ b/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' -- cgit v1.2.3 From 16ae82db1e2b830424aa3c94db57281da96aa62d Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Fri, 14 Nov 2008 16:04:19 +0100 Subject: Missing changelog for :only/:except on map.resources --- actionpack/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index dc7ee64358..0b3811c794 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *2.2.1 [RC2] (November 14th, 2008)* +* 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] + * 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] -- cgit v1.2.3 From e4a345c1dc13f7de99b782f4a1115d58b7bf1b45 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Fri, 14 Nov 2008 16:07:26 +0100 Subject: Missing changelog for CSRF changes --- actionpack/CHANGELOG | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 0b3811c794..5b9114755c 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,7 +1,13 @@ *2.2.1 [RC2] (November 14th, 2008)* +* 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] -- cgit v1.2.3 From 44c3b865ac52a7c9a6312982ba0f6c20d7ad41e1 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Fri, 14 Nov 2008 16:10:57 +0100 Subject: Missing changelogs for relative_url_root changes --- actionpack/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 5b9114755c..b7a824d559 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *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] -- cgit v1.2.3 From c6c5cd554110f6e62290de3e3008076b2f69e7cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Wed, 12 Nov 2008 13:15:57 +0100 Subject: refactor autolink helper. change tests to expect HTML-escaped URLs Signed-off-by: Michael Koziarski --- actionpack/lib/action_view/helpers/text_helper.rb | 46 ++++++++++------------- actionpack/test/template/text_helper_test.rb | 37 +++++++++++------- 2 files changed, 44 insertions(+), 39 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 36f7575652..07f98158f7 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -545,38 +545,32 @@ module ActionView 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) # 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 =~ /]*href="$/ + if href =~ /[^\w\/-]$/ + punctuation = href[-1, 1] + href = href[0, href.length - 1] + else + punctuation = '' + 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 else - text = b + c - text = yield(text) if block_given? - %(#{a}#{text}#{d}) + # do not change string; URL is alreay linked + href end end end diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index 095c952d67..42390d84c8 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -225,36 +225,41 @@ class TextHelperTest < ActionView::TestCase ) urls.each do |url| - assert_equal %(#{url}), auto_link(url) + assert_equal %(#{CGI::escapeHTML url}), auto_link(url) end end + def generate_result(link_text, href = nil) + href ||= link_text + %{#{CGI::escapeHTML link_text}} + end + def test_auto_linking email_raw = 'david@loudthinking.com' email_result = %{#{email_raw}} email2_raw = '+david@loudthinking.com' email2_result = %{#{email2_raw}} link_raw = 'http://www.rubyonrails.com' - link_result = %{#{link_raw}} + link_result = generate_result(link_raw) link_result_with_options = %{#{link_raw}} link2_raw = 'www.rubyonrails.com' - link2_result = %{#{link2_raw}} + link2_result = generate_result(link2_raw, "http://#{link2_raw}") link3_raw = 'http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281' - link3_result = %{#{link3_raw}} + link3_result = generate_result(link3_raw) link4_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor123' - link4_result = %{#{link4_raw}} + link4_result = generate_result(link4_raw) link5_raw = 'http://foo.example.com:3000/controller/action' - link5_result = %{#{link5_raw}} + link5_result = generate_result(link5_raw) link6_raw = 'http://foo.example.com:3000/controller/action+pack' - link6_result = %{#{link6_raw}} + link6_result = generate_result(link6_raw) link7_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor-123' - link7_result = %{#{link7_raw}} + link7_result = generate_result(link7_raw) link8_raw = 'http://foo.example.com:3000/controller/action.html' - link8_result = %{#{link8_raw}} + link8_result = generate_result(link8_raw) link9_raw = 'http://business.timesonline.co.uk/article/0,,9065-2473189,00.html' - link9_result = %{#{link9_raw}} + link9_result = generate_result(link9_raw) link10_raw = 'http://www.mail-archive.com/ruby-talk@ruby-lang.org/' - link10_result = %{#{link10_raw}} + link10_result = generate_result(link10_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) @@ -299,7 +304,13 @@ class TextHelperTest < ActionView::TestCase 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 'Ruby On Rails', auto_link('Ruby On Rails') + 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_at_eol @@ -317,7 +328,7 @@ class TextHelperTest < ActionView::TestCase end def test_auto_link_with_options_hash - assert_equal 'Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com.', + assert_dom_equal 'Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com.', 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 -- cgit v1.2.3 From 4f984c9d0e66601a81cb5ae6e3b50582e6dc0c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Thu, 13 Nov 2008 22:39:16 +0100 Subject: auto_link helper: add intelligent ending closing bracket handling. add new tests and reorder new ones for readability Signed-off-by: Michael Koziarski [#1353 state:committed] --- actionpack/lib/action_view/helpers/text_helper.rb | 22 ++-- actionpack/test/template/text_helper_test.rb | 128 ++++++++++++++-------- 2 files changed, 94 insertions(+), 56 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 07f98158f7..9bd3d63423 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -549,28 +549,32 @@ module ActionView [^\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 = {}) link_attributes = html_options.stringify_keys text.gsub(AUTO_LINK_RE) do href = $& + punctuation = '' # detect already linked URLs - unless $` =~ /]*href="$/ - if href =~ /[^\w\/-]$/ - punctuation = href[-1, 1] - href = href[0, href.length - 1] - else - punctuation = '' + if $` =~ /]*href="$/ + # do not change string; URL is alreay linked + href + else + # 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 - else - # do not change string; URL is alreay linked - href end end end diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index 42390d84c8..3e7a8f3e44 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -205,27 +205,30 @@ class TextHelperTest < ActionView::TestCase 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 %(#{CGI::escapeHTML url}), auto_link(url) + assert_equal generate_result(url), auto_link(url) end end @@ -237,29 +240,13 @@ class TextHelperTest < ActionView::TestCase def test_auto_linking email_raw = 'david@loudthinking.com' email_result = %{#{email_raw}} - email2_raw = '+david@loudthinking.com' - email2_result = %{#{email2_raw}} link_raw = 'http://www.rubyonrails.com' link_result = generate_result(link_raw) - link_result_with_options = %{#{link_raw}} - link2_raw = 'www.rubyonrails.com' - link2_result = generate_result(link2_raw, "http://#{link2_raw}") - link3_raw = 'http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281' - link3_result = generate_result(link3_raw) - link4_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor123' - link4_result = generate_result(link4_raw) - link5_raw = 'http://foo.example.com:3000/controller/action' - link5_result = generate_result(link5_raw) - link6_raw = 'http://foo.example.com:3000/controller/action+pack' - link6_result = generate_result(link6_raw) - link7_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor-123' - link7_result = generate_result(link7_raw) - link8_raw = 'http://foo.example.com:3000/controller/action.html' - link8_result = generate_result(link8_raw) - link9_raw = 'http://business.timesonline.co.uk/article/0,,9065-2473189,00.html' - link9_result = generate_result(link9_raw) - link10_raw = 'http://www.mail-archive.com/ruby-talk@ruby-lang.org/' - link10_result = generate_result(link10_raw) + link_result_with_options = %{#{link_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 %(hello #{email_result}), auto_link("hello #{email_raw}", :email_addresses) assert_equal %(Go to #{link_result}), auto_link("Go to #{link_raw}", :urls) @@ -270,40 +257,70 @@ class TextHelperTest < ActionView::TestCase assert_equal %(

Link #{link_result_with_options}

), auto_link("

Link #{link_raw}

", :all, {:target => "_blank"}) assert_equal %(Go to #{link_result}.), auto_link(%(Go to #{link_raw}.)) assert_equal %(

Go to #{link_result}, then say hello to #{email_result}.

), auto_link(%(

Go to #{link_raw}, then say hello to #{email_raw}.

)) + + email2_raw = '+david@loudthinking.com' + email2_result = %{#{email2_raw}} + 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 %(

Link #{link2_result}

), auto_link("

Link #{link2_raw}

") assert_equal %(

#{link2_result} Link

), auto_link("

#{link2_raw} Link

") assert_equal %(Go to #{link2_result}.), auto_link(%(Go to #{link2_raw}.)) assert_equal %(

Say hello to #{email_result}, then go to #{link2_result}.

), auto_link(%(

Say hello to #{email_raw}, then go to #{link2_raw}.

)) + + 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 %(

Link #{link3_result}

), auto_link("

Link #{link3_raw}

") assert_equal %(

#{link3_result} Link

), auto_link("

#{link3_raw} Link

") assert_equal %(Go to #{link3_result}.), auto_link(%(Go to #{link3_raw}.)) - assert_equal %(

Go to #{link3_result}. seriously, #{link3_result}? i think I'll say hello to #{email_result}. instead.

), auto_link(%(

Go to #{link3_raw}. seriously, #{link3_raw}? i think I'll say hello to #{email_raw}. instead.

)) + assert_equal %(

Go to #{link3_result}. Seriously, #{link3_result}? I think I'll say hello to #{email_result}. Instead.

), + auto_link(%(

Go to #{link3_raw}. Seriously, #{link3_raw}? I think I'll say hello to #{email_raw}. Instead.

)) + + link4_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor123' + link4_result = generate_result(link4_raw) assert_equal %(

Link #{link4_result}

), auto_link("

Link #{link4_raw}

") assert_equal %(

#{link4_result} Link

), auto_link("

#{link4_raw} Link

") + + link5_raw = 'http://foo.example.com:3000/controller/action' + link5_result = generate_result(link5_raw) assert_equal %(

#{link5_result} Link

), auto_link("

#{link5_raw} Link

") + + link6_raw = 'http://foo.example.com:3000/controller/action+pack' + link6_result = generate_result(link6_raw) assert_equal %(

#{link6_result} Link

), auto_link("

#{link6_raw} Link

") + + link7_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor-123' + link7_result = generate_result(link7_raw) assert_equal %(

#{link7_result} Link

), auto_link("

#{link7_raw} Link

") + + 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 %(

Link #{link8_result}

), auto_link("

Link #{link8_raw}

") assert_equal %(

#{link8_result} Link

), auto_link("

#{link8_raw} Link

") assert_equal %(Go to #{link8_result}.), auto_link(%(Go to #{link8_raw}.)) - assert_equal %(

Go to #{link8_result}. seriously, #{link8_result}? i think I'll say hello to #{email_result}. instead.

), auto_link(%(

Go to #{link8_raw}. seriously, #{link8_raw}? i think I'll say hello to #{email_raw}. instead.

)) + assert_equal %(

Go to #{link8_result}. Seriously, #{link8_result}? I think I'll say hello to #{email_result}. Instead.

), + auto_link(%(

Go to #{link8_raw}. Seriously, #{link8_raw}? I think I'll say hello to #{email_raw}. Instead.

)) + + 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 %(

Link #{link9_result}

), auto_link("

Link #{link9_raw}

") assert_equal %(

#{link9_result} Link

), auto_link("

#{link9_raw} Link

") assert_equal %(Go to #{link9_result}.), auto_link(%(Go to #{link9_raw}.)) - assert_equal %(

Go to #{link9_result}. seriously, #{link9_result}? i think I'll say hello to #{email_result}. instead.

), auto_link(%(

Go to #{link9_raw}. seriously, #{link9_raw}? i think I'll say hello to #{email_raw}. instead.

)) + assert_equal %(

Go to #{link9_result}. Seriously, #{link9_result}? I think I'll say hello to #{email_result}. Instead.

), + auto_link(%(

Go to #{link9_raw}. Seriously, #{link9_raw}? I think I'll say hello to #{email_raw}. Instead.

)) + + link10_raw = 'http://www.mail-archive.com/ruby-talk@ruby-lang.org/' + link10_result = generate_result(link10_raw) assert_equal %(

#{link10_result} Link

), auto_link("

#{link10_raw} Link

") - 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}") end def test_auto_link_already_linked @@ -313,6 +330,23 @@ class TextHelperTest < ActionView::TestCase 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 url1 = "http://api.rubyonrails.com/Foo.html" url2 = "http://www.ruby-doc.org/core/Bar.html" -- cgit v1.2.3