diff options
Diffstat (limited to 'actionpack')
96 files changed, 2836 insertions, 1710 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 382a3cbd1d..459f5b90e4 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,57 @@ ## Rails 4.0.0 (unreleased) ## -* Add `config.action_view.logger` to configure logger for ActionView. *Rafael França* + +* Add `date_field` and `date_field_tag` helpers which render an `input[type="date"]` tag *Olek Janiszewski* + +* Adds `image_url`, `javascript_url`, `stylesheet_url`, `audio_url`, `video_url`, and `font_url` + to assets tag helper. These URL helpers will return the full path to your assets. This is useful + when you are going to reference this asset from external host. *Prem Sichanugrist* + +* Default responder will now always use your overridden block in `respond_with` to render your response. *Prem Sichanugrist* + +* Allow `value_method` and `text_method` arguments from `collection_select` and + `options_from_collection_for_select` to receive an object that responds to `:call`, + such as a `proc`, to evaluate the option in the current element context. This works + the same way with `collection_radio_buttons` and `collection_check_boxes`. + + *Carlos Antonio da Silva + Rafael Mendonça França* + +* Add `collection_check_boxes` form helper, similar to `collection_select`: + Example: + + collection_check_boxes :post, :author_ids, Author.all, :id, :name + # Outputs something like: + <input id="post_author_ids_1" name="post[author_ids][]" type="checkbox" value="1" /> + <label for="post_author_ids_1">D. Heinemeier Hansson</label> + <input id="post_author_ids_2" name="post[author_ids][]" type="checkbox" value="2" /> + <label for="post_author_ids_2">D. Thomas</label> + <input name="post[author_ids][]" type="hidden" value="" /> + + The label/check_box pairs can be customized with a block. + + *Carlos Antonio da Silva + Rafael Mendonça França* + +* Add `collection_radio_buttons` form helper, similar to `collection_select`: + Example: + + collection_radio_buttons :post, :author_id, Author.all, :id, :name + # Outputs something like: + <input id="post_author_id_1" name="post[author_id]" type="radio" value="1" /> + <label for="post_author_id_1">D. Heinemeier Hansson</label> + <input id="post_author_id_2" name="post[author_id]" type="radio" value="2" /> + <label for="post_author_id_2">D. Thomas</label> + + The label/radio_button pairs can be customized with a block. + + *Carlos Antonio da Silva + Rafael Mendonça França* + +* check_box with `:form` html5 attribute will now replicate the `:form` + attribute to the hidden field as well. *Carlos Antonio da Silva* + +* `label` form helper accepts :for => nil to not generate the attribute. *Carlos Antonio da Silva* + +* Add `:format` option to number_to_percentage *Rodrigo Flores* + +* Add `config.action_view.logger` to configure logger for ActionView. *Rafael Mendonça França* * Deprecated ActionController::Integration in favour of ActionDispatch::Integration @@ -21,7 +73,12 @@ This is a behavior change, previously the hidden tag had a value of the disabled checkbox. *Tadas Tamosauskas* -## Rails 3.2.0 (unreleased) ## +* `favicon_link_tag` helper will now use the favicon in app/assets by default. *Lucas Caton* + +* `ActionView::Helpers::TextHelper#highlight` now defaults to the + HTML5 `mark` element. *Brian Cardarella* + +## Rails 3.2.0 (January 20, 2012) ## * Add `config.action_dispatch.default_charset` to configure default charset for ActionDispatch::Response. *Carlos Antonio da Silva* @@ -33,8 +90,6 @@ * Deprecate method_missing handling for not found actions, use action_missing instead. *Carlos Antonio da Silva* -* Deprecate ActionController#performed?, check for response_body presence instead. *Carlos Antonio da Silva* - * Deprecate ActionController#rescue_action, ActionController#initialize_template_class, and ActionController#assign_shortcuts. These methods were not being used internally anymore and are going to be removed in Rails 4. *Carlos Antonio da Silva* diff --git a/actionpack/Rakefile b/actionpack/Rakefile index effb6badfc..bb1e704767 100755 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -55,15 +55,15 @@ end task :lines do lines, codelines, total_lines, total_codelines = 0, 0, 0, 0 - for file_name in FileList["lib/**/*.rb"] + FileList["lib/**/*.rb"].each do |file_name| next if file_name =~ /vendor/ - f = File.open(file_name) - - while line = f.gets - lines += 1 - next if line =~ /^\s*$/ - next if line =~ /^\s*#/ - codelines += 1 + File.open(file_name, 'r') do |f| + while line = f.gets + lines += 1 + next if line =~ /^\s*$/ + next if line =~ /^\s*#/ + codelines += 1 + end end puts "L: #{sprintf("%4d", lines)}, LOC #{sprintf("%4d", codelines)} | #{file_name}" diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 4ce0624207..b205acdb79 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -20,9 +20,9 @@ Gem::Specification.new do |s| s.add_dependency('activemodel', version) s.add_dependency('rack-cache', '~> 1.1') s.add_dependency('builder', '~> 3.0.0') - s.add_dependency('rack', '~> 1.4.0') + s.add_dependency('rack', '~> 1.4.1') s.add_dependency('rack-test', '~> 0.6.1') - s.add_dependency('journey', '~> 1.0.0') + s.add_dependency('journey', '~> 1.0.1') s.add_dependency('sprockets', '~> 2.2.0') s.add_dependency('erubis', '~> 2.7.0') diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index fffe3edac2..44c9ea34ba 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -8,7 +8,7 @@ module AbstractController include ActiveSupport::Callbacks included do - define_callbacks :process_action, :terminator => "response_body" + define_callbacks :process_action, :terminator => "response_body", :skip_after_callbacks_if_terminated => true end # Override AbstractController::Base's process_action to run the @@ -21,11 +21,9 @@ module AbstractController module ClassMethods # If :only or :except are used, convert the options into the - # primitive form (:per_key) used by ActiveSupport::Callbacks. + # :unless and :if options of ActiveSupport::Callbacks. # The basic idea is that :only => :index gets converted to - # :if => proc {|c| c.action_name == "index" }, but that the - # proc is only evaluated once per action for the lifetime of - # a Rails process. + # :if => proc {|c| c.action_name == "index" }. # # ==== Options # * <tt>only</tt> - The callback should be run only for this action @@ -33,11 +31,11 @@ module AbstractController def _normalize_callback_options(options) if only = options[:only] only = Array(only).map {|o| "action_name == '#{o}'"}.join(" || ") - options[:per_key] = {:if => only} + options[:if] = Array(options[:if]) << only end if except = options[:except] except = Array(except).map {|e| "action_name == '#{e}'"}.join(" || ") - options[:per_key] = {:unless => except} + options[:unless] = Array(options[:unless]) << except end end @@ -167,7 +165,6 @@ module AbstractController # for details on the allowed parameters. def #{filter}_filter(*names, &blk) # def before_filter(*names, &blk) _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options| - options[:if] = (Array(options[:if]) << "!halted") if #{filter == :after} # options[:if] = (Array(options[:if]) << "!halted") if false set_callback(:process_action, :#{filter}, name, options) # set_callback(:process_action, :before, name, options) end # end end # end @@ -176,7 +173,6 @@ module AbstractController # for details on the allowed parameters. def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk) _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options| - options[:if] = (Array(options[:if]) << "!halted") if #{filter == :after} # options[:if] = (Array(options[:if]) << "!halted") if false set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true)) end # end end # end diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index f4eaa2fd1b..a0c54dbd84 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -40,7 +40,6 @@ module ActionController autoload :Integration, 'action_controller/deprecated/integration_test' autoload :IntegrationTest, 'action_controller/deprecated/integration_test' autoload :PerformanceTest, 'action_controller/deprecated/performance_test' - autoload :UrlWriter, 'action_controller/deprecated' autoload :Routing, 'action_controller/deprecated' autoload :TestCase, 'action_controller/test_case' autoload :TemplateAssertions, 'action_controller/test_case' diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index e76a79f710..bd3b0b5df3 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -47,7 +47,8 @@ module ActionController #:nodoc: # And you can also use <tt>:if</tt> (or <tt>:unless</tt>) to pass a # proc that specifies when the action should be cached. # - # Finally, if you are using memcached, you can also pass <tt>:expires_in</tt>. + # As of Rails 3.0, you can also pass <tt>:expires_in</tt> with a time + # interval (in seconds) to schedule expiration of the cached item. # # The following example depicts some of the points made above: # diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 3aab77a069..92433ab462 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -181,9 +181,13 @@ module ActionController @_status = Rack::Utils.status_code(status) end - def response_body=(val) - body = (val.nil? || val.respond_to?(:each)) ? val : [val] - super body + def response_body=(body) + body = [body] unless body.nil? || body.respond_to?(:each) + super + end + + def performed? + !!response_body end def dispatch(name, request) #:nodoc: diff --git a/actionpack/lib/action_controller/metal/force_ssl.rb b/actionpack/lib/action_controller/metal/force_ssl.rb index b45f211e83..69e37d8713 100644 --- a/actionpack/lib/action_controller/metal/force_ssl.rb +++ b/actionpack/lib/action_controller/metal/force_ssl.rb @@ -29,6 +29,7 @@ module ActionController if !request.ssl? && !Rails.env.development? redirect_options = {:protocol => 'https://', :status => :moved_permanently} redirect_options.merge!(:host => host) if host + redirect_options.merge!(:params => request.query_parameters) flash.keep redirect_to redirect_options end diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index 4972c6bede..3d46163b74 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -67,7 +67,7 @@ module ActionController # class PostsController < ApplicationController # REALM = "SuperSecret" # USERS = {"dhh" => "secret", #plain text password - # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":")) #ha1 digest password + # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":"))} #ha1 digest password # # before_filter :authenticate, :except => [:index] # diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb index e8e465d3ba..ae04b53825 100644 --- a/actionpack/lib/action_controller/metal/implicit_render.rb +++ b/actionpack/lib/action_controller/metal/implicit_render.rb @@ -2,7 +2,7 @@ module ActionController module ImplicitRender def send_action(method, *args) ret = super - default_render unless response_body + default_render unless performed? ret end diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index ca383be76b..80ecc16d53 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -191,8 +191,9 @@ module ActionController #:nodoc: def respond_to(*mimes, &block) raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given? - if response = retrieve_response_from_mimes(mimes, &block) - response.call(nil) + if collector = retrieve_collector_from_mimes(mimes, &block) + response = collector.response + response ? response.call : default_render({}) end end @@ -232,10 +233,18 @@ module ActionController #:nodoc: raise "In order to use respond_with, first you need to declare the formats your " << "controller responds to in the class level" if self.class.mimes_for_respond_to.empty? - if response = retrieve_response_from_mimes(&block) + if collector = retrieve_collector_from_mimes(&block) options = resources.size == 1 ? {} : resources.extract_options! - options.merge!(:default_response => response) - (options.delete(:responder) || self.class.responder).call(self, resources, options) + + if defined_response = collector.response + if action = options.delete(:action) + render :action => action + else + defined_response.call + end + else + (options.delete(:responder) || self.class.responder).call(self, resources, options) + end end end @@ -263,15 +272,16 @@ module ActionController #:nodoc: # Collects mimes and return the response for the negotiated format. Returns # nil if :not_acceptable was sent to the client. # - def retrieve_response_from_mimes(mimes=nil, &block) #:nodoc: + def retrieve_collector_from_mimes(mimes=nil, &block) #:nodoc: mimes ||= collect_mimes_from_class_level - collector = Collector.new(mimes) { |options| default_render(options || {}) } + collector = Collector.new(mimes) block.call(collector) if block_given? + format = collector.negotiate_format(request) - if format = request.negotiate_mime(collector.order) + if format self.content_type ||= format.to_s lookup_context.freeze_formats([format.to_sym]) - collector.response_for(format) + collector else head :not_acceptable nil @@ -280,10 +290,10 @@ module ActionController #:nodoc: class Collector #:nodoc: include AbstractController::Collector - attr_accessor :order + attr_accessor :order, :format - def initialize(mimes, &block) - @order, @responses, @default_response = [], {}, block + def initialize(mimes) + @order, @responses = [], {} mimes.each { |mime| send(mime) } end @@ -302,8 +312,12 @@ module ActionController #:nodoc: @responses[mime_type] ||= block end - def response_for(mime) - @responses[mime] || @responses[Mime::ALL] || @default_response + def response + @responses[format] || @responses[Mime::ALL] + end + + def negotiate_format(request) + @format = request.negotiate_mime(order) end end end diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index 9500a349cb..4ad64bff20 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -129,7 +129,6 @@ module ActionController #:nodoc: @resources = resources @options = options @action = options.delete(:action) - @default_response = options.delete(:default_response) end delegate :head, :render, :redirect_to, :to => :controller @@ -226,7 +225,7 @@ module ActionController #:nodoc: # controller. # def default_render - @default_response.call(options) + controller.default_render(options) end # Display is just a shortcut to render a resource with the current format. diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index fce6e29d5f..1e226fc336 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -351,7 +351,7 @@ module ActionController def tests(controller_class) case controller_class when String, Symbol - self.controller_class = "#{controller_class.to_s.underscore}_controller".camelize.constantize + self.controller_class = "#{controller_class.to_s.camelize}Controller".constantize when Class self.controller_class = controller_class else diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 25affb9f50..2152351703 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -82,6 +82,7 @@ module Mime class << self TRAILING_STAR_REGEXP = /(text|application)\/\*/ + Q_SEPARATOR_REGEXP = /;\s*q=/ def lookup(string) LOOKUP[string] @@ -108,6 +109,7 @@ module Mime def parse(accept_header) if accept_header !~ /,/ + accept_header = accept_header.split(Q_SEPARATOR_REGEXP).first if accept_header =~ TRAILING_STAR_REGEXP parse_data_with_trailing_star($1) else @@ -117,7 +119,7 @@ module Mime # keep track of creation order to keep the subsequent sort stable list, index = [], 0 accept_header.split(/,/).each do |header| - params, q = header.split(/;\s*q=/) + params, q = header.split(Q_SEPARATOR_REGEXP) if params.present? params.strip! diff --git a/actionpack/lib/action_dispatch/http/mime_types.rb b/actionpack/lib/action_dispatch/http/mime_types.rb index 3da4f91051..a6b3aee5e7 100644 --- a/actionpack/lib/action_dispatch/http/mime_types.rb +++ b/actionpack/lib/action_dispatch/http/mime_types.rb @@ -9,7 +9,7 @@ Mime::Type.register "text/calendar", :ics Mime::Type.register "text/csv", :csv Mime::Type.register "image/png", :png, [], %w(png) -Mime::Type.register "image/jpeg", :jpeg, [], %w(jpg jpeg jpe) +Mime::Type.register "image/jpeg", :jpeg, [], %w(jpg jpeg jpe pjpeg) Mime::Type.register "image/gif", :gif, [], %w(gif) Mime::Type.register "image/bmp", :bmp, [], %w(bmp) Mime::Type.register "image/tiff", :tiff, [], %w(tif tiff) diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 39ff58a447..25f1db8228 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -191,6 +191,15 @@ module ActionDispatch value end + # Whether the given cookie is to be deleted by this CookieJar. + # Like <tt>[]=</tt>, you can pass in an options hash to test if a + # deletion applies to a specific <tt>:path</tt>, <tt>:domain</tt> etc. + def deleted?(key, options = {}) + options.symbolize_keys! + handle_options(options) + @delete_cookies[key.to_s] == options + end + # Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie def clear(options = {}) @cookies.each_key{ |k| delete(k, options) } diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb index 030ccb2017..d924f21fad 100644 --- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb +++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb @@ -18,11 +18,13 @@ module ActionDispatch def initialize(app, check_ip_spoofing = true, custom_proxies = nil) @app = app @check_ip = check_ip_spoofing - if custom_proxies - custom_regexp = Regexp.new(custom_proxies) - @proxies = Regexp.union(TRUSTED_PROXIES, custom_regexp) + @proxies = case custom_proxies + when Regexp + custom_proxies + when nil + TRUSTED_PROXIES else - @proxies = TRUSTED_PROXIES + Regexp.union(TRUSTED_PROXIES, custom_proxies) end end @@ -57,7 +59,7 @@ module ActionDispatch "HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}" end - not_proxy = client_ip || forwarded_ips.last || remote_addrs.first + not_proxy = client_ip || forwarded_ips.first || remote_addrs.first # Return first REMOTE_ADDR if there are no other options not_proxy || ips_from('REMOTE_ADDR', :allow_proxies).first diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb index a4308f528c..28e8fbdab8 100644 --- a/actionpack/lib/action_dispatch/middleware/stack.rb +++ b/actionpack/lib/action_dispatch/middleware/stack.rb @@ -93,8 +93,9 @@ module ActionDispatch end def swap(target, *args, &block) - insert_before(target, *args, &block) - delete(target) + index = assert_index(target, :before) + insert(index, *args, &block) + middlewares.delete_at(index + 1) end def delete(target) diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb index 2f6b9d266d..107fe80d1f 100644 --- a/actionpack/lib/action_dispatch/routing.rb +++ b/actionpack/lib/action_dispatch/routing.rb @@ -190,7 +190,7 @@ module ActionDispatch # Examples: # # match 'post/:id' => 'posts#show', :via => :get - # match 'post/:id' => "posts#create_comment', :via => :post + # match 'post/:id' => 'posts#create_comment', :via => :post # # Now, if you POST to <tt>/posts/:id</tt>, it will route to the <tt>create_comment</tt> action. A GET on the same # URL will route to the <tt>show</tt> action. @@ -203,7 +203,7 @@ module ActionDispatch # Examples: # # get 'post/:id' => 'posts#show' - # post 'post/:id' => "posts#create_comment' + # post 'post/:id' => 'posts#create_comment' # # This syntax is less verbose and the intention is more apparent to someone else reading your code, # however if your route needs to respond to more than one HTTP method (or all methods) then using the diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index db1e3198b3..cf9c0d7b6a 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -54,6 +54,7 @@ module ActionDispatch def initialize(set, scope, path, options) @set, @scope = set, scope + @segment_keys = nil @options = (@scope[:options] || {}).merge(options) @path = normalize_path(path) normalize_options! @@ -213,7 +214,9 @@ module ActionDispatch end def segment_keys - @segment_keys ||= Journey::Path::Pattern.new( + return @segment_keys if @segment_keys + + @segment_keys = Journey::Path::Pattern.new( Journey::Router::Strexp.compile(@path, requirements, SEPARATORS) ).names end @@ -464,7 +467,7 @@ module ActionDispatch # # get 'bacon', :to => 'food#bacon' def get(*args, &block) - map_method(:get, *args, &block) + map_method(:get, args, &block) end # Define a route that only recognizes HTTP POST. @@ -474,7 +477,7 @@ module ActionDispatch # # post 'bacon', :to => 'food#bacon' def post(*args, &block) - map_method(:post, *args, &block) + map_method(:post, args, &block) end # Define a route that only recognizes HTTP PUT. @@ -484,25 +487,24 @@ module ActionDispatch # # put 'bacon', :to => 'food#bacon' def put(*args, &block) - map_method(:put, *args, &block) + map_method(:put, args, &block) end - # Define a route that only recognizes HTTP PUT. + # Define a route that only recognizes HTTP DELETE. # For supported arguments, see <tt>Base#match</tt>. # # Example: # # delete 'broccoli', :to => 'food#broccoli' def delete(*args, &block) - map_method(:delete, *args, &block) + map_method(:delete, args, &block) end private - def map_method(method, *args, &block) + def map_method(method, args, &block) options = args.extract_options! options[:via] = method - args.push(options) - match(*args, &block) + match(*args, options, &block) self end end @@ -1247,6 +1249,9 @@ module ActionDispatch parent_resource.instance_of?(Resource) && @scope[:shallow] end + # match 'path' => 'controller#action' + # match 'path', to: 'controller#action' + # match 'path', 'otherpath', on: :member, via: :get def match(path, *rest) if rest.empty? && Hash === path options = path diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 2c21887220..6c189fdba6 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -31,6 +31,7 @@ module ActionDispatch end def prepare_params!(params) + normalize_controller!(params) merge_default_action!(params) split_glob_param!(params) if @glob_param end @@ -66,6 +67,10 @@ module ActionDispatch controller.action(action).call(env) end + def normalize_controller!(params) + params[:controller] = params[:controller].underscore if params.key?(:controller) + end + def merge_default_action!(params) params[:action] ||= 'index' end @@ -360,7 +365,26 @@ module ActionDispatch SEPARATORS, anchor) - Journey::Path::Pattern.new(strexp) + pattern = Journey::Path::Pattern.new(strexp) + + builder = Journey::GTG::Builder.new pattern.spec + + # Get all the symbol nodes followed by literals that are not the + # dummy node. + symbols = pattern.spec.grep(Journey::Nodes::Symbol).find_all { |n| + builder.followpos(n).first.literal? + } + + # Get all the symbol nodes preceded by literals. + symbols.concat pattern.spec.find_all(&:literal?).map { |n| + builder.followpos(n).first + }.find_all(&:symbol?) + + symbols.each { |x| + x.regexp = /(?:#{Regexp.union(x.regexp, '-')})+/ + } + + pattern end private :build_path @@ -463,7 +487,7 @@ module ActionDispatch # if the current controller is "foo/bar/baz" and :controller => "baz/bat" # is specified, the controller becomes "foo/baz/bat" def use_relative_controller! - if !named_route && different_controller? + if !named_route && different_controller? && !controller.start_with?("/") old_parts = current_controller.split('/') size = controller.count("/") + 1 parts = old_parts[0...-size] << controller @@ -548,6 +572,7 @@ module ActionDispatch path_addition, params = generate(path_options, path_segments || {}) path << path_addition + params.merge!(options[:params] || {}) ActionDispatch::Http::URL.url_for(options.merge!({ :path => path, @@ -579,7 +604,8 @@ module ActionDispatch params[key] = URI.parser.unescape(value) end end - + old_params = env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] + env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] = (old_params || {}).merge(params) dispatcher = route.app while dispatcher.is_a?(Mapper::Constraints) && dispatcher.matches?(env) do dispatcher = dispatcher.app diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 4d963803e6..8eed85bce2 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -340,8 +340,8 @@ module ActionDispatch # element +encoded+. It then calls the block with all un-encoded elements. # # ==== Examples - # # Selects all bold tags from within the title of an ATOM feed's entries (perhaps to nab a section name prefix) - # assert_select_feed :atom, 1.0 do + # # Selects all bold tags from within the title of an Atom feed's entries (perhaps to nab a section name prefix) + # assert_select "feed[xmlns='http://www.w3.org/2005/Atom']" do # # Select each entry item and then the title item # assert_select "entry>title" do # # Run assertions on the encoded title elements @@ -353,7 +353,7 @@ module ActionDispatch # # # # Selects all paragraph tags from within the description of an RSS feed - # assert_select_feed :rss, 2.0 do + # assert_select "rss[version=2.0]" do # # Select description element of each feed item. # assert_select "channel>item>description" do # # Run assertions on the encoded elements. @@ -417,8 +417,8 @@ module ActionDispatch deliveries = ActionMailer::Base.deliveries assert !deliveries.empty?, "No e-mail in delivery list" - for delivery in deliveries - for part in (delivery.parts.empty? ? [delivery] : delivery.parts) + deliveries.each do |delivery| + (delivery.parts.empty? ? [delivery] : delivery.parts).each do |part| if part["Content-Type"].to_s =~ /^text\/html\W/ root = HTML::Document.new(part.body.to_s).root assert_select root, ":root", &block diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 122dc9db7f..23329d7f35 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -147,7 +147,6 @@ module ActionView #:nodoc: class << self delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB' - delegate :logger, :to => 'ActionController::Base', :allow_nil => true def cache_template_loading ActionView::Resolver.caching? diff --git a/actionpack/lib/action_view/flows.rb b/actionpack/lib/action_view/flows.rb index a8f740713f..c0e458cd41 100644 --- a/actionpack/lib/action_view/flows.rb +++ b/actionpack/lib/action_view/flows.rb @@ -22,11 +22,8 @@ module ActionView def append(key, value) @content[key] << value end + alias_method :append!, :append - # Called by provide - def append!(key, value) - @content[key] << value - end end class StreamingFlow < OutputFlow #:nodoc: diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb index 973135e2ea..e27111012d 100644 --- a/actionpack/lib/action_view/helpers/active_model_helper.rb +++ b/actionpack/lib/action_view/helpers/active_model_helper.rb @@ -16,7 +16,9 @@ module ActionView end end - module_eval "def content_tag(*) error_wrapping(super) end", __FILE__, __LINE__ + def content_tag(*) + error_wrapping(super) + end def tag(type, options, *) tag_generate_errors?(options) ? error_wrapping(super) : super @@ -37,7 +39,7 @@ module ActionView private def object_has_errors? - object.respond_to?(:errors) && object.errors.respond_to?(:full_messages) && error_message.any? + object.respond_to?(:errors) && object.errors.respond_to?(:[]) && error_message.present? end def tag_generate_errors?(options) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 5dbba3c4a7..662adbe183 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/array/extract_options' +require 'active_support/core_ext/hash/keys' require 'action_view/helpers/asset_tag_helpers/javascript_tag_helpers' require 'action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers' require 'action_view/helpers/asset_tag_helpers/asset_paths' @@ -196,7 +198,7 @@ module ActionView include JavascriptTagHelpers include StylesheetTagHelpers # Returns a link tag that browsers and news readers can use to auto-detect - # an RSS or ATOM feed. The +type+ can either be <tt>:rss</tt> (default) or + # an RSS or Atom feed. The +type+ can either be <tt>:rss</tt> (default) or # <tt>:atom</tt>. Control the link options in url_for format using the # +url_options+. You can modify the LINK tag itself in +tag_options+. # @@ -232,7 +234,7 @@ module ActionView # # generates # - # <link href="/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" /> + # <link href="/assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" /> # # You may specify a different file in the first argument: # @@ -250,7 +252,7 @@ module ActionView # # <%= favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png' %> # - def favicon_link_tag(source='/favicon.ico', options={}) + def favicon_link_tag(source='favicon.ico', options={}) tag('link', { :rel => 'shortcut icon', :type => 'image/vnd.microsoft.icon', @@ -276,6 +278,13 @@ module ActionView end alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route + # Computes the full URL to an image asset in the public images directory. + # This will use +image_path+ internally, so most of their behaviors will be the same. + def image_url(source) + URI.join(current_host, path_to_image(source)).to_s + end + alias_method :url_to_image, :image_url # aliased to avoid conflicts with an image_url named route + # Computes the path to a video asset in the public videos directory. # Full paths from the document root will be passed through. # Used internally by +video_tag+ to build the video path. @@ -291,6 +300,13 @@ module ActionView end alias_method :path_to_video, :video_path # aliased to avoid conflicts with a video_path named route + # Computes the full URL to a video asset in the public videos directory. + # This will use +video_path+ internally, so most of their behaviors will be the same. + def video_url(source) + URI.join(current_host, path_to_video(source)).to_s + end + alias_method :url_to_video, :video_url # aliased to avoid conflicts with an video_url named route + # Computes the path to an audio asset in the public audios directory. # Full paths from the document root will be passed through. # Used internally by +audio_tag+ to build the audio path. @@ -306,6 +322,13 @@ module ActionView end alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route + # Computes the full URL to a audio asset in the public audios directory. + # This will use +audio_path+ internally, so most of their behaviors will be the same. + def audio_url(source) + URI.join(current_host, path_to_audio(source)).to_s + end + alias_method :url_to_audio, :audio_url # aliased to avoid conflicts with an audio_url named route + # Computes the path to a font asset in the public fonts directory. # Full paths from the document root will be passed through. # @@ -320,6 +343,13 @@ module ActionView end alias_method :path_to_font, :font_path # aliased to avoid conflicts with an font_path named route + # Computes the full URL to a font asset in the public fonts directory. + # This will use +font_path+ internally, so most of their behaviors will be the same. + def font_url(source) + URI.join(current_host, path_to_font(source)).to_s + end + alias_method :url_to_font, :font_url # aliased to avoid conflicts with an font_url named route + # Returns an html image tag for the +source+. The +source+ can be a full # path or a file that exists in your public images directory. # @@ -353,8 +383,8 @@ module ActionView # <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" /> # image_tag("mouse.png", :mouseover => image_path("mouse_over.png")) # => # <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" /> - def image_tag(source, options = {}) - options.symbolize_keys! + def image_tag(source, options={}) + options = options.dup.symbolize_keys! src = options[:src] = path_to_image(source) @@ -407,26 +437,19 @@ module ActionView # <video src="/trailers/hd.avi" width="16" height="16" /> # video_tag("/trailers/hd.avi", :height => '32', :width => '32') # => # <video height="32" src="/trailers/hd.avi" width="32" /> + # video_tag("trailer.ogg", "trailer.flv") # => + # <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video> # video_tag(["trailer.ogg", "trailer.flv"]) # => - # <video><source src="trailer.ogg" /><source src="trailer.ogg" /><source src="trailer.flv" /></video> + # <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video> # video_tag(["trailer.ogg", "trailer.flv"] :size => "160x120") # => - # <video height="120" width="160"><source src="trailer.ogg" /><source src="trailer.flv" /></video> - def video_tag(sources, options = {}) - options.symbolize_keys! - - options[:poster] = path_to_image(options[:poster]) if options[:poster] - - if size = options.delete(:size) - options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$} - end + # <video height="120" width="160"><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video> + def video_tag(*sources) + multiple_sources_tag('video', sources) do |options| + options[:poster] = path_to_image(options[:poster]) if options[:poster] - if sources.is_a?(Array) - content_tag("video", options) do - sources.map { |source| tag("source", :src => source) }.join.html_safe + if size = options.delete(:size) + options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$} end - else - options[:src] = path_to_video(sources) - tag("video", options) end end @@ -441,10 +464,10 @@ module ActionView # <audio src="/audios/sound.wav" /> # audio_tag("sound.wav", :autoplay => true, :controls => true) # => # <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" /> - def audio_tag(source, options = {}) - options.symbolize_keys! - options[:src] = path_to_audio(source) - tag("audio", options) + # audio_tag("sound.wav", "sound.mid") # => + # <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio> + def audio_tag(*sources) + multiple_sources_tag('audio', sources) end private @@ -452,6 +475,26 @@ module ActionView def asset_paths @asset_paths ||= AssetTagHelper::AssetPaths.new(config, controller) end + + def multiple_sources_tag(type, sources) + options = sources.extract_options!.dup.symbolize_keys! + sources.flatten! + + yield options if block_given? + + if sources.size > 1 + content_tag(type, options) do + safe_join sources.map { |source| tag("source", :src => send("path_to_#{type}", source)) } + end + else + options[:src] = send("path_to_#{type}", sources.first) + content_tag(type, nil, options) + end + end + + def current_host + url_for(:only_path => false) + end end end end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb index d9f1f88ade..c67f81dcf4 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb @@ -87,6 +87,13 @@ module ActionView end alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route + # Computes the full URL to a javascript asset in the public javascripts directory. + # This will use +javascript_path+ internally, so most of their behaviors will be the same. + def javascript_url(source) + URI.join(current_host, path_to_javascript(source)).to_s + end + alias_method :url_to_javascript, :javascript_url # aliased to avoid conflicts with a javascript_url named route + # Returns an HTML script tag for each of the +sources+ provided. # # Sources may be paths to JavaScript files. Relative paths are assumed to be relative diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb index 41958c6559..2584b67548 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb @@ -65,6 +65,13 @@ module ActionView end alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route + # Computes the full URL to a stylesheet asset in the public stylesheets directory. + # This will use +stylesheet_path+ internally, so most of their behaviors will be the same. + def stylesheet_url(source) + URI.join(current_host, path_to_stylesheet(source)).to_s + end + alias_method :url_to_stylesheet, :stylesheet_url # aliased to avoid conflicts with a stylesheet_url named route + # Returns a stylesheet link tag for the sources specified as arguments. If # you don't specify an extension, <tt>.css</tt> will be appended automatically. # You can modify the link attributes by passing a hash as the last argument. diff --git a/actionpack/lib/action_view/helpers/csrf_helper.rb b/actionpack/lib/action_view/helpers/csrf_helper.rb index 1f2bc28cac..eeb0ed94b9 100644 --- a/actionpack/lib/action_view/helpers/csrf_helper.rb +++ b/actionpack/lib/action_view/helpers/csrf_helper.rb @@ -1,5 +1,3 @@ -require 'active_support/core_ext/string/strip' - module ActionView # = Action View CSRF Helper module Helpers diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index f5077b034a..2d37923825 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -142,6 +142,8 @@ module ActionView # ==== Options # * <tt>:use_month_numbers</tt> - Set to true if you want to use month numbers rather than month names (e.g. # "2" instead of "February"). + # * <tt>:use_two_digit_numbers</tt> - Set to true if you want to display two digit month and day numbers (e.g. + # "02" instead of "February" and "08" instead of "8"). # * <tt>:use_short_month</tt> - Set to true if you want to use abbreviated month names instead of full # month names (e.g. "Feb" instead of "February"). # * <tt>:add_month_numbers</tt> - Set to true if you want to use both month numbers and month names (e.g. @@ -189,6 +191,10 @@ module ActionView # date_select("article", "written_on", :start_year => 1995, :use_month_numbers => true, # :discard_day => true, :include_blank => true) # + # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute, + # # with two digit numbers used for months and days. + # date_select("article", "written_on", :use_two_digit_numbers => true) + # # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute # # with the fields ordered as day, month, year rather than month, day, year. # date_select("article", "written_on", :order => [:day, :month, :year]) @@ -502,6 +508,7 @@ module ActionView # Returns a select tag with options for each of the days 1 through 31 with the current day selected. # The <tt>date</tt> can also be substituted for a day number. + # If you want to display days with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true. # Override the field name using the <tt>:field_name</tt> option, 'day' by default. # # ==== Examples @@ -513,6 +520,9 @@ module ActionView # # Generates a select field for days that defaults to the number given. # select_day(5) # + # # Generates a select field for days that defaults to the number given, but displays it with two digits. + # select_day(5, :use_two_digit_numbers => true) + # # # Generates a select field for days that defaults to the day for the date in my_date # # that is named 'due' rather than 'day'. # select_day(my_time, :field_name => 'due') @@ -532,6 +542,7 @@ module ActionView # want both numbers and names, set the <tt>:add_month_numbers</tt> key in +options+ to true. If you would prefer # to show month names as abbreviations, set the <tt>:use_short_month</tt> key in +options+ to true. If you want # to use your own month names, set the <tt>:use_month_names</tt> key in +options+ to an array of 12 month names. + # If you want to display months with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true. # Override the field name using the <tt>:field_name</tt> option, 'month' by default. # # ==== Examples @@ -559,6 +570,10 @@ module ActionView # # will use keys like "Januar", "Marts." # select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...)) # + # # Generates a select field for months that defaults to the current month that + # # will use keys with two digit numbers like "01", "03". + # select_month(Date.today, :use_two_digit_numbers => true) + # # # Generates a select field for months with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. # select_month(14, :prompt => 'Choose month') @@ -734,7 +749,7 @@ module ActionView def select_day if @options[:use_hidden] || @options[:discard_day] - build_hidden(:day, day) + build_hidden(:day, day || 1) else build_options_and_select(:day, day, :start => 1, :end => 31, :leading_zeros => false, :use_two_digit_numbers => @options[:use_two_digit_numbers]) end @@ -742,7 +757,7 @@ module ActionView def select_month if @options[:use_hidden] || @options[:discard_month] - build_hidden(:month, month) + build_hidden(:month, month || 1) else month_options = [] 1.upto(12) do |month_number| @@ -756,7 +771,7 @@ module ActionView def select_year if !@datetime || @datetime == 0 - val = '' + val = '1' middle_year = Date.today.year else val = middle_year = year @@ -817,6 +832,9 @@ module ActionView # If <tt>:use_month_numbers</tt> option is passed # month_name(1) => 1 # + # If <tt>:use_two_month_numbers</tt> option is passed + # month_name(1) => '01' + # # If <tt>:add_month_numbers</tt> option is passed # month_name(1) => "1 - January" def month_name(number) @@ -836,7 +854,15 @@ module ActionView end def translated_date_order - I18n.translate(:'date.order', :locale => @options[:locale]) || [] + date_order = I18n.translate(:'date.order', :locale => @options[:locale], :default => []) + + forbidden_elements = date_order - [:year, :month, :day] + if forbidden_elements.any? + raise StandardError, + "#{@options[:locale]}.date.order only accepts :year, :month and :day" + end + + date_order end # Build full select tag from date type and options. @@ -850,6 +876,12 @@ module ActionView # <option value="2">2</option> # <option value="3">3</option>..." # + # If <tt>:use_two_digit_numbers => true</tt> option is passed + # build_options(15, :start => 1, :end => 31, :use_two_digit_numbers => true) + # => "<option value="1">01</option> + # <option value="2">02</option> + # <option value="3">03</option>..." + # # If <tt>:step</tt> options is passed # build_options(15, :start => 1, :end => 31, :step => 2) # => "<option value="1">1</option> @@ -958,18 +990,12 @@ module ActionView # Returns the separator for a given datetime component. def separator(type) case type - when :year - @options[:discard_year] ? "" : @options[:date_separator] - when :month - @options[:discard_month] ? "" : @options[:date_separator] - when :day - @options[:discard_day] ? "" : @options[:date_separator] + when :year, :month, :day + @options[:"discard_#{type}"] ? "" : @options[:date_separator] when :hour (@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator] - when :minute - @options[:discard_minute] ? "" : @options[:time_separator] - when :second - @options[:include_seconds] ? @options[:time_separator] : "" + when :minute, :second + @options[:"discard_#{type}"] ? "" : @options[:time_separator] end end end diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index bdfef920c5..44e24fecd1 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -889,6 +889,24 @@ module ActionView end alias phone_field telephone_field + # Returns a text_field of type "date". + # + # date_field("user", "born_on") + # # => <input id="user_born_on" name="user[born_on]" type="date" /> + # + # The default value is generated by trying to call "to_date" + # on the object's value, which makes it behave as expected for instances + # of DateTime and ActiveSupport::TimeWithZone. You can still override that + # by passing the "value" option explicitly, e.g. + # + # @user.born_on = Date.new(1984, 1, 27) + # date_field("user", "born_on", value: "1984-05-12") + # # => <input id="user_born_on" name="user[born_on]" type="date" value="1984-05-12" /> + # + def date_field(object_name, method, options = {}) + Tags::DateField.new(object_name, method, self, options).render + end + # Returns a text_field of type "url". # # url_field("user", "homepage") diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index e323350608..bc03a1cf83 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -164,7 +164,9 @@ module ActionView # # The <tt>:value_method</tt> and <tt>:text_method</tt> parameters are methods to be called on each member # of +collection+. The return values are used as the +value+ attribute and contents of each - # <tt><option></tt> tag, respectively. + # <tt><option></tt> tag, respectively. They can also be any object that responds to +call+, such + # as a +proc+, that will be called for each member of the +collection+ to + # retrieve the value/text. # # Example object structure for use with this method: # class Post < ActiveRecord::Base @@ -334,7 +336,7 @@ module ActionView end.join("\n").html_safe end - # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the + # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning # the result of a call to the +value_method+ as the option value and the +text_method+ as the option text. # Example: # options_from_collection_for_select(@people, 'id', 'name') @@ -360,12 +362,13 @@ module ActionView # should produce the desired results. def options_from_collection_for_select(collection, value_method, text_method, selected = nil) options = collection.map do |element| - [element.send(text_method), element.send(value_method)] + [value_for_collection(element, text_method), value_for_collection(element, value_method)] end selected, disabled = extract_selected_and_disabled(selected) - select_deselect = {} - select_deselect[:selected] = extract_values_from_collection(collection, value_method, selected) - select_deselect[:disabled] = extract_values_from_collection(collection, value_method, disabled) + select_deselect = { + :selected => extract_values_from_collection(collection, value_method, selected), + :disabled => extract_values_from_collection(collection, value_method, disabled) + } options_for_select(options, select_deselect) end @@ -418,10 +421,10 @@ module ActionView # wrap the output in an appropriate <tt><select></tt> tag. def option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil) collection.map do |group| - group_label_string = eval("group.#{group_label_method}") - "<optgroup label=\"#{ERB::Util.html_escape(group_label_string)}\">" + - options_from_collection_for_select(eval("group.#{group_method}"), option_key_method, option_value_method, selected_key) + - '</optgroup>' + option_tags = options_from_collection_for_select( + group.send(group_method), option_key_method, option_value_method, selected_key) + + content_tag(:optgroup, option_tags, :label => group.send(group_label_method)) end.join.html_safe end @@ -519,14 +522,138 @@ module ActionView zone_options.html_safe end + # Returns radio button tags for the collection of existing return values + # of +method+ for +object+'s class. The value returned from calling + # +method+ on the instance +object+ will be selected. If calling +method+ + # returns +nil+, no selection is made. + # + # The <tt>:value_method</tt> and <tt>:text_method</tt> parameters are + # methods to be called on each member of +collection+. The return values + # are used as the +value+ attribute and contents of each radio button tag, + # respectively. They can also be any object that responds to +call+, such + # as a +proc+, that will be called for each member of the +collection+ to + # retrieve the value/text. + # + # Example object structure for use with this method: + # class Post < ActiveRecord::Base + # belongs_to :author + # end + # class Author < ActiveRecord::Base + # has_many :posts + # def name_with_initial + # "#{first_name.first}. #{last_name}" + # end + # end + # + # Sample usage (selecting the associated Author for an instance of Post, <tt>@post</tt>): + # collection_radio_buttons(:post, :author_id, Author.all, :id, :name_with_initial) + # + # If <tt>@post.author_id</tt> is already <tt>1</tt>, this would return: + # <input id="post_author_id_1" name="post[author_id]" type="radio" value="1" checked="checked" /> + # <label for="post_author_id_1">D. Heinemeier Hansson</label> + # <input id="post_author_id_2" name="post[author_id]" type="radio" value="2" /> + # <label for="post_author_id_2">D. Thomas</label> + # <input id="post_author_id_3" name="post[author_id]" type="radio" value="3" /> + # <label for="post_author_id_3">M. Clark</label> + # + # It is also possible to customize the way the elements will be shown by + # giving a block to the method: + # collection_radio_buttons(:post, :author_id, Author.all, :id, :name_with_initial) do |b| + # b.label { b.radio_button } + # end + # + # The argument passed to the block is a special kind of builder for this + # collection, which has the ability to generate the label and radio button + # for the current item in the collection, with proper text and value. + # Using it, you can change the label and radio button display order or + # even use the label as wrapper, as in the example above. + # + # The builder methods <tt>label</tt> and <tt>radio_button</tt> also accept + # extra html options: + # collection_radio_buttons(:post, :author_id, Author.all, :id, :name_with_initial) do |b| + # b.label(:class => "radio_button") { b.radio_button(:class => "radio_button") } + # end + # + # There are also two special methods available: <tt>text</tt> and + # <tt>value</tt>, which are the current text and value methods for the + # item being rendered, respectively. You can use them like this: + # collection_radio_buttons(:post, :author_id, Author.all, :id, :name_with_initial) do |b| + # b.label(:"data-value" => b.value) { b.radio_button + b.text } + # end + def collection_radio_buttons(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block) + Tags::CollectionRadioButtons.new(object, method, self, collection, value_method, text_method, options, html_options).render(&block) + end + + # Returns check box tags for the collection of existing return values of + # +method+ for +object+'s class. The value returned from calling +method+ + # on the instance +object+ will be selected. If calling +method+ returns + # +nil+, no selection is made. + # + # The <tt>:value_method</tt> and <tt>:text_method</tt> parameters are + # methods to be called on each member of +collection+. The return values + # are used as the +value+ attribute and contents of each check box tag, + # respectively. They can also be any object that responds to +call+, such + # as a +proc+, that will be called for each member of the +collection+ to + # retrieve the value/text. + # + # Example object structure for use with this method: + # class Post < ActiveRecord::Base + # has_and_belongs_to_many :author + # end + # class Author < ActiveRecord::Base + # has_and_belongs_to_many :posts + # def name_with_initial + # "#{first_name.first}. #{last_name}" + # end + # end + # + # Sample usage (selecting the associated Author for an instance of Post, <tt>@post</tt>): + # collection_check_boxes(:post, :author_ids, Author.all, :id, :name_with_initial) + # + # If <tt>@post.author_ids</tt> is already <tt>[1]</tt>, this would return: + # <input id="post_author_ids_1" name="post[author_ids][]" type="checkbox" value="1" checked="checked" /> + # <label for="post_author_ids_1">D. Heinemeier Hansson</label> + # <input id="post_author_ids_2" name="post[author_ids][]" type="checkbox" value="2" /> + # <label for="post_author_ids_2">D. Thomas</label> + # <input id="post_author_ids_3" name="post[author_ids][]" type="checkbox" value="3" /> + # <label for="post_author_ids_3">M. Clark</label> + # <input name="post[author_ids][]" type="hidden" value="" /> + # + # It is also possible to customize the way the elements will be shown by + # giving a block to the method: + # collection_check_boxes(:post, :author_ids, Author.all, :id, :name_with_initial) do |b| + # b.label { b.check_box } + # end + # + # The argument passed to the block is a special kind of builder for this + # collection, which has the ability to generate the label and check box + # for the current item in the collection, with proper text and value. + # Using it, you can change the label and check box display order or even + # use the label as wrapper, as in the example above. + # + # The builder methods <tt>label</tt> and <tt>check_box</tt> also accept + # extra html options: + # collection_check_boxes(:post, :author_ids, Author.all, :id, :name_with_initial) do |b| + # b.label(:class => "check_box") { b.check_box(:class => "check_box") } + # end + # + # There are also two special methods available: <tt>text</tt> and + # <tt>value</tt>, which are the current text and value methods for the + # item being rendered, respectively. You can use them like this: + # collection_check_boxes(:post, :author_ids, Author.all, :id, :name_with_initial) do |b| + # b.label(:"data-value" => b.value) { b.check_box + b.text } + # end + def collection_check_boxes(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block) + Tags::CollectionCheckBoxes.new(object, method, self, collection, value_method, text_method, options, html_options).render(&block) + end + private def option_html_attributes(element) return "" unless Array === element - html_attributes = [] - element.select { |e| Hash === e }.reduce({}, :merge).each do |k, v| - html_attributes << " #{k}=\"#{ERB::Util.html_escape(v.to_s)}\"" - end - html_attributes.join + + element.select { |e| Hash === e }.reduce({}, :merge).map do |k, v| + " #{k}=\"#{ERB::Util.html_escape(v.to_s)}\"" + end.join end def option_text_and_value(option) @@ -552,12 +679,12 @@ module ActionView def extract_selected_and_disabled(selected) if selected.is_a?(Proc) - [ selected, nil ] + [selected, nil] else selected = Array.wrap(selected) options = selected.extract_options!.symbolize_keys - selected_items = options.include?(:selected) ? options[:selected] : selected - [ selected_items, options[:disabled] ] + selected_items = options.fetch(:selected, selected) + [selected_items, options[:disabled]] end end @@ -570,6 +697,10 @@ module ActionView selected end end + + def value_for_collection(item, value) + value.respond_to?(:call) ? value.call(item) : item.send(value) + end end class FormBuilder @@ -588,6 +719,14 @@ module ActionView def time_zone_select(method, priority_zones = nil, options = {}, html_options = {}) @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_options.merge(html_options)) end + + def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}) + @template.collection_check_boxes(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)) + end + + def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}) + @template.collection_radio_buttons(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)) + end end end end diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 57b90a9c42..53fd189c39 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -549,6 +549,14 @@ module ActionView end alias phone_field_tag telephone_field_tag + # Creates a text field of type "date". + # + # ==== Options + # * Accepts the same options as text_field_tag. + def date_field_tag(name, value = nil, options = {}) + text_field_tag(name, value, options.stringify_keys.update("type" => "date")) + end + # Creates a text field of type "url". # # ==== Options @@ -627,7 +635,7 @@ module ActionView token_tag(authenticity_token) else html_options["method"] = "post" - tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag(authenticity_token) + method_tag(method) + token_tag(authenticity_token) end tags = utf8_enforcer_tag << method_tag @@ -646,15 +654,6 @@ module ActionView output.safe_concat("</form>") end - def token_tag(token) - if token == false || !protect_against_forgery? - '' - else - token ||= form_authenticity_token - tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => token) - end - end - # see http://www.w3.org/TR/html4/types.html#type-name def sanitize_to_id(name) name.to_s.gsub(']','').gsub(/[^-a-zA-Z0-9:.]/, "_") diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 309923490c..ac9e530f01 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -1,5 +1,4 @@ require 'action_view/helpers/tag_helper' -require 'active_support/core_ext/string/encoding' module ActionView module Helpers diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index 43122ef2ba..b0860f87c4 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -57,15 +57,11 @@ module ActionView # # => +1.123.555.1234 x 1343 def number_to_phone(number, options = {}) return unless number + options = options.symbolize_keys - begin - Float(number) - rescue ArgumentError, TypeError - raise InvalidNumberError, number - end if options[:raise] + parse_float(number, true) if options[:raise] number = number.to_s.strip - options = options.symbolize_keys area_code = options[:area_code] delimiter = options[:delimiter] || "-" extension = options[:extension] @@ -75,7 +71,7 @@ module ActionView number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3") else number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3") - number.slice!(0, 1) if number.starts_with?(delimiter) && !delimiter.blank? + number.slice!(0, 1) if number.start_with?(delimiter) && !delimiter.blank? end str = [] @@ -122,14 +118,12 @@ module ActionView # # => 1234567890,50 £ def number_to_currency(number, options = {}) return unless number + options = options.symbolize_keys - options.symbolize_keys! - - defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) - currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {}) + currency = translations_for('currency', options[:locale]) currency[:negative_format] ||= "-" + currency[:format] if currency[:format] - defaults = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency) + defaults = DEFAULT_CURRENCY_VALUES.merge(defaults_translations(options[:locale])).merge!(currency) defaults[:negative_format] = "-" + options[:format] if options[:format] options = defaults.merge!(options) @@ -152,7 +146,6 @@ module ActionView e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number end end - end # Formats a +number+ as a percentage string (e.g., 65%). You can customize the format in the +options+ hash. @@ -169,6 +162,8 @@ module ActionView # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ""). # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator # (defaults to +false+). + # * <tt>:format</tt> - Specifies the format of the percentage string + # The number field is <tt>%n</tt> (defaults to "%n%"). # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid. # # ==== Examples @@ -180,26 +175,27 @@ module ActionView # number_to_percentage(302.24398923423, :precision => 5) # => 302.24399% # number_to_percentage(1000, :locale => :fr) # => 1 000,000% # number_to_percentage("98a") # => 98a% + # number_to_percentage(100, :format => "%n %") # => 100 % # # number_to_percentage("98a", :raise => true) # => InvalidNumberError def number_to_percentage(number, options = {}) return unless number + options = options.symbolize_keys - options.symbolize_keys! + defaults = format_translations('percentage', options[:locale]) + options = defaults.merge!(options) - defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) - percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :default => {}) - defaults = defaults.merge(percentage) - - options = options.reverse_merge(defaults) + format = options[:format] || "%n%" begin - "#{number_with_precision(number, options.merge(:raise => true))}%".html_safe + value = number_with_precision(number, options.merge(:raise => true)) + format.gsub(/%n/, value).html_safe rescue InvalidNumberError => e if options[:raise] raise else - e.number.to_s.html_safe? ? "#{e.number}%".html_safe : "#{e.number}%" + formatted_number = format.gsub(/%n/, e.number) + e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number end end end @@ -229,25 +225,15 @@ module ActionView # # number_with_delimiter("112a", :raise => true) # => raise InvalidNumberError def number_with_delimiter(number, options = {}) - options.symbolize_keys! + options = options.symbolize_keys - begin - Float(number) - rescue ArgumentError, TypeError - if options[:raise] - raise InvalidNumberError, number - else - return number - end - end + parse_float(number, options[:raise]) or return number - defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) - options = options.reverse_merge(defaults) + options = defaults_translations(options[:locale]).merge(options) parts = number.to_s.to_str.split('.') parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}") parts.join(options[:separator]).html_safe - end # Formats a +number+ with the specified level of <tt>:precision</tt> (e.g., 112.32 has a precision @@ -264,6 +250,7 @@ module ActionView # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ""). # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator # (defaults to +false+). + # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid. # # ==== Examples # number_with_precision(111.2345) # => 111.235 @@ -282,23 +269,13 @@ module ActionView # number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.') # # => 1.111,23 def number_with_precision(number, options = {}) - options.symbolize_keys! + options = options.symbolize_keys - number = begin - Float(number) - rescue ArgumentError, TypeError - if options[:raise] - raise InvalidNumberError, number - else - return number - end - end + number = (parse_float(number, options[:raise]) or return number) - defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) - precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale], :default => {}) - defaults = defaults.merge(precision_defaults) + defaults = format_translations('precision', options[:locale]) + options = defaults.merge!(options) - options = options.reverse_merge(defaults) # Allow the user to unset default values: Eg.: :significant => false precision = options.delete :precision significant = options.delete :significant strip_insignificant_zeros = options.delete :strip_insignificant_zeros @@ -323,7 +300,6 @@ module ActionView else formatted_number end - end STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze @@ -343,6 +319,7 @@ module ActionView # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ""). # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator (defaults to +true+) # * <tt>:prefix</tt> - If +:si+ formats the number using the SI prefix (defaults to :binary) + # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid. # ==== Examples # number_to_human_size(123) # => 123 Bytes # number_to_human_size(1234) # => 1.21 KB @@ -359,23 +336,13 @@ module ActionView # number_to_human_size(1234567890123, :precision => 5) # => "1.1229 TB" # number_to_human_size(524288000, :precision => 5) # => "500 MB" def number_to_human_size(number, options = {}) - options.symbolize_keys! + options = options.symbolize_keys - number = begin - Float(number) - rescue ArgumentError, TypeError - if options[:raise] - raise InvalidNumberError, number - else - return number - end - end + number = (parse_float(number, options[:raise]) or return number) - defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) - human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {}) - defaults = defaults.merge(human) + defaults = format_translations('human', options[:locale]) + options = defaults.merge!(options) - options = options.reverse_merge(defaults) #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros) @@ -424,6 +391,7 @@ module ActionView # * *integers*: <tt>:unit</tt>, <tt>:ten</tt>, <tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>, <tt>:billion</tt>, <tt>:trillion</tt>, <tt>:quadrillion</tt> # * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>, <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>, <tt>:pico</tt>, <tt>:femto</tt> # * <tt>:format</tt> - Sets the format of the output string (defaults to "%n %u"). The field types are: + # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid. # # %u The quantifier (ex.: 'thousand') # %n The number @@ -478,23 +446,13 @@ module ActionView # number_to_human(0.34, :units => :distance) # => "34 centimeters" # def number_to_human(number, options = {}) - options.symbolize_keys! + options = options.symbolize_keys - number = begin - Float(number) - rescue ArgumentError, TypeError - if options[:raise] - raise InvalidNumberError, number - else - return number - end - end + number = (parse_float(number, options[:raise]) or return number) - defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) - human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {}) - defaults = defaults.merge(human) + defaults = format_translations('human', options[:locale]) + options = defaults.merge!(options) - options = options.reverse_merge(defaults) #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros) @@ -530,6 +488,25 @@ module ActionView decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip.html_safe end + private + + def format_translations(namespace, locale) + defaults_translations(locale).merge(translations_for(namespace, locale)) + end + + def defaults_translations(locale) + I18n.translate(:'number.format', :locale => locale, :default => {}) + end + + def translations_for(namespace, locale) + I18n.translate(:"number.#{namespace}.format", :locale => locale, :default => {}) + end + + def parse_float(number, raise_error) + Float(number) + rescue ArgumentError, TypeError + raise InvalidNumberError, number if raise_error + end end end end diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index d7a2651bad..ecd26891d6 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -118,7 +118,7 @@ module ActionView # escape_once("<< Accept & Checkout") # # => "<< Accept & Checkout" def escape_once(html) - html.to_s.gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] } + ERB::Util.html_escape_once(html) end private diff --git a/actionpack/lib/action_view/helpers/tags.rb b/actionpack/lib/action_view/helpers/tags.rb index 89b3efda5f..3cf762877f 100644 --- a/actionpack/lib/action_view/helpers/tags.rb +++ b/actionpack/lib/action_view/helpers/tags.rb @@ -1,28 +1,33 @@ module ActionView module Helpers - module Tags - autoload :Base, 'action_view/helpers/tags/base' - autoload :Label, 'action_view/helpers/tags/label' - autoload :TextField, 'action_view/helpers/tags/text_field' - autoload :PasswordField, 'action_view/helpers/tags/password_field' - autoload :HiddenField, 'action_view/helpers/tags/hidden_field' - autoload :FileField, 'action_view/helpers/tags/file_field' - autoload :SearchField, 'action_view/helpers/tags/search_field' - autoload :TelField, 'action_view/helpers/tags/tel_field' - autoload :UrlField, 'action_view/helpers/tags/url_field' - autoload :EmailField, 'action_view/helpers/tags/email_field' - autoload :NumberField, 'action_view/helpers/tags/number_field' - autoload :RangeField, 'action_view/helpers/tags/range_field' - autoload :TextArea, 'action_view/helpers/tags/text_area' - autoload :CheckBox, 'action_view/helpers/tags/check_box' - autoload :RadioButton, 'action_view/helpers/tags/radio_button' - autoload :Select, 'action_view/helpers/tags/select' - autoload :CollectionSelect, 'action_view/helpers/tags/collection_select' - autoload :GroupedCollectionSelect, 'action_view/helpers/tags/grouped_collection_select' - autoload :TimeZoneSelect, 'action_view/helpers/tags/time_zone_select' - autoload :DateSelect, 'action_view/helpers/tags/date_select' - autoload :TimeSelect, 'action_view/helpers/tags/time_select' - autoload :DatetimeSelect, 'action_view/helpers/tags/datetime_select' + module Tags #:nodoc: + extend ActiveSupport::Autoload + + autoload :Base + autoload :CheckBox + autoload :CollectionCheckBoxes + autoload :CollectionRadioButtons + autoload :CollectionSelect + autoload :DateField + autoload :DateSelect + autoload :DatetimeSelect + autoload :EmailField + autoload :FileField + autoload :GroupedCollectionSelect + autoload :HiddenField + autoload :Label + autoload :NumberField + autoload :PasswordField + autoload :RadioButton + autoload :RangeField + autoload :SearchField + autoload :Select + autoload :TelField + autoload :TextArea + autoload :TextField + autoload :TimeSelect + autoload :TimeZoneSelect + autoload :UrlField end end end diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb index 24956beb9c..1ece0ad2fc 100644 --- a/actionpack/lib/action_view/helpers/tags/base.rb +++ b/actionpack/lib/action_view/helpers/tags/base.rb @@ -19,8 +19,9 @@ module ActionView @auto_index = retrieve_autoindex(Regexp.last_match.pre_match) if Regexp.last_match end - def render(&block) - raise "Abstract Method called" + # This is what child classes implement. + def render + raise NotImplementedError, "Subclasses must implement a render method" end private @@ -31,9 +32,11 @@ module ActionView def value_before_type_cast(object) unless object.nil? - object.respond_to?(@method_name + "_before_type_cast") ? - object.send(@method_name + "_before_type_cast") : - object.send(@method_name) + method_before_type_cast = @method_name + "_before_type_cast" + + object.respond_to?(method_before_type_cast) ? + object.send(method_before_type_cast) : + value(object) end end @@ -58,13 +61,15 @@ module ActionView end def add_default_name_and_id_for_value(tag_value, options) - unless tag_value.nil? - pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase - specified_id = options["id"] + if tag_value.nil? add_default_name_and_id(options) - options["id"] += "_#{pretty_tag_value}" if specified_id.blank? && options["id"].present? else + specified_id = options["id"] add_default_name_and_id(options) + + if specified_id.blank? && options["id"].present? + options["id"] += "_#{sanitized_value(tag_value)}" + end end end @@ -77,7 +82,7 @@ module ActionView options["name"] ||= tag_name_with_index(@auto_index) options["id"] = options.fetch("id"){ tag_id_with_index(@auto_index) } else - options["name"] ||= tag_name + (options['multiple'] ? '[]' : '') + options["name"] ||= options['multiple'] ? tag_name_multiple : tag_name options["id"] = options.fetch("id"){ tag_id } end options["id"] = [options.delete('namespace'), options["id"]].compact.join("_").presence @@ -87,6 +92,10 @@ module ActionView "#{@object_name}[#{sanitized_method_name}]" end + def tag_name_multiple + "#{tag_name}[]" + end + def tag_name_with_index(index) "#{@object_name}[#{index}][#{sanitized_method_name}]" end @@ -107,6 +116,10 @@ module ActionView @sanitized_method_name ||= @method_name.sub(/\?$/,"") end + def sanitized_value(value) + value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase + end + def select_content_tag(option_tags, options, html_options) html_options = html_options.stringify_keys add_default_name_and_id(html_options) diff --git a/actionpack/lib/action_view/helpers/tags/check_box.rb b/actionpack/lib/action_view/helpers/tags/check_box.rb index b3bd6eb2ad..579cdb9fc9 100644 --- a/actionpack/lib/action_view/helpers/tags/check_box.rb +++ b/actionpack/lib/action_view/helpers/tags/check_box.rb @@ -25,7 +25,7 @@ module ActionView add_default_name_and_id(options) end - hidden = @unchecked_value ? tag("input", "name" => options["name"], "type" => "hidden", "value" => @unchecked_value, "disabled" => options["disabled"]) : "" + hidden = hidden_field_for_checkbox(options) checkbox = tag("input", options) hidden + checkbox end @@ -48,6 +48,10 @@ module ActionView value.to_i != 0 end end + + def hidden_field_for_checkbox(options) + @unchecked_value ? tag("input", options.slice("name", "disabled", "form").merge!("type" => "hidden", "value" => @unchecked_value)) : "".html_safe + end end end end diff --git a/actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb b/actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb new file mode 100644 index 0000000000..5f1e9ec026 --- /dev/null +++ b/actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb @@ -0,0 +1,37 @@ +require 'action_view/helpers/tags/collection_helpers' + +module ActionView + module Helpers + module Tags + class CollectionCheckBoxes < Base + include CollectionHelpers + + class CheckBoxBuilder < Builder + def check_box(extra_html_options={}) + html_options = extra_html_options.merge(@input_html_options) + @template_object.check_box(@object_name, @method_name, html_options, @value, nil) + end + end + + def render + rendered_collection = render_collection do |value, text, default_html_options| + default_html_options[:multiple] = true + builder = instantiate_builder(CheckBoxBuilder, value, text, default_html_options) + + if block_given? + yield builder + else + builder.check_box + builder.label + end + end + + # Append a hidden field to make sure something will be sent back to the + # server if all check boxes are unchecked. + hidden = @template_object.hidden_field_tag(tag_name_multiple, "", :id => nil) + + rendered_collection + hidden + end + end + end + end +end diff --git a/actionpack/lib/action_view/helpers/tags/collection_helpers.rb b/actionpack/lib/action_view/helpers/tags/collection_helpers.rb new file mode 100644 index 0000000000..1e2e77dde1 --- /dev/null +++ b/actionpack/lib/action_view/helpers/tags/collection_helpers.rb @@ -0,0 +1,80 @@ +module ActionView + module Helpers + module Tags + module CollectionHelpers + class Builder + attr_reader :text, :value + + def initialize(template_object, object_name, method_name, + sanitized_attribute_name, text, value, input_html_options) + @template_object = template_object + @object_name = object_name + @method_name = method_name + @sanitized_attribute_name = sanitized_attribute_name + @text = text + @value = value + @input_html_options = input_html_options + end + + def label(label_html_options={}, &block) + @template_object.label(@object_name, @sanitized_attribute_name, @text, label_html_options, &block) + end + end + + def initialize(object_name, method_name, template_object, collection, value_method, text_method, options, html_options) + @collection = collection + @value_method = value_method + @text_method = text_method + @html_options = html_options + + super(object_name, method_name, template_object, options) + end + + private + + def instantiate_builder(builder_class, value, text, html_options) + builder_class.new(@template_object, @object_name, @method_name, + sanitize_attribute_name(value), text, value, html_options) + end + + # Generate default options for collection helpers, such as :checked and + # :disabled. + def default_html_options_for_collection(item, value) #:nodoc: + html_options = @html_options.dup + + [:checked, :selected, :disabled].each do |option| + next unless current_value = @options[option] + + accept = if current_value.respond_to?(:call) + current_value.call(item) + else + Array(current_value).include?(value) + end + + if accept + html_options[option] = true + elsif option == :checked + html_options[option] = false + end + end + + html_options + end + + def sanitize_attribute_name(value) #:nodoc: + "#{sanitized_method_name}_#{sanitized_value(value)}" + end + + def render_collection #:nodoc: + @collection.map do |item| + value = value_for_collection(item, @value_method) + text = value_for_collection(item, @text_method) + default_html_options = default_html_options_for_collection(item, value) + + yield value, text, default_html_options + end.join.html_safe + end + end + end + end +end diff --git a/actionpack/lib/action_view/helpers/tags/collection_radio_buttons.rb b/actionpack/lib/action_view/helpers/tags/collection_radio_buttons.rb new file mode 100644 index 0000000000..8e7aeeed63 --- /dev/null +++ b/actionpack/lib/action_view/helpers/tags/collection_radio_buttons.rb @@ -0,0 +1,30 @@ +require 'action_view/helpers/tags/collection_helpers' + +module ActionView + module Helpers + module Tags + class CollectionRadioButtons < Base + include CollectionHelpers + + class RadioButtonBuilder < Builder + def radio_button(extra_html_options={}) + html_options = extra_html_options.merge(@input_html_options) + @template_object.radio_button(@object_name, @method_name, @value, html_options) + end + end + + def render + render_collection do |value, text, default_html_options| + builder = instantiate_builder(RadioButtonBuilder, value, text, default_html_options) + + if block_given? + yield builder + else + builder.radio_button + builder.label + end + end + end + end + end + end +end diff --git a/actionpack/lib/action_view/helpers/tags/collection_select.rb b/actionpack/lib/action_view/helpers/tags/collection_select.rb index f84140d8d0..ec78e6e5f9 100644 --- a/actionpack/lib/action_view/helpers/tags/collection_select.rb +++ b/actionpack/lib/action_view/helpers/tags/collection_select.rb @@ -12,9 +12,14 @@ module ActionView end def render - selected_value = @options.has_key?(:selected) ? @options[:selected] : value(@object) + option_tags_options = { + :selected => @options.fetch(:selected) { value(@object) }, + :disabled => @options[:disabled] + } + select_content_tag( - options_from_collection_for_select(@collection, @value_method, @text_method, :selected => selected_value, :disabled => @options[:disabled]), @options, @html_options + options_from_collection_for_select(@collection, @value_method, @text_method, option_tags_options), + @options, @html_options ) end end diff --git a/actionpack/lib/action_view/helpers/tags/date_field.rb b/actionpack/lib/action_view/helpers/tags/date_field.rb new file mode 100644 index 0000000000..bb968e9f39 --- /dev/null +++ b/actionpack/lib/action_view/helpers/tags/date_field.rb @@ -0,0 +1,15 @@ +module ActionView + module Helpers + module Tags + class DateField < TextField #:nodoc: + def render + options = @options.stringify_keys + options["value"] = @options.fetch("value") { value(object).try(:to_date) } + options["size"] = nil + @options = options + super + end + end + end + end +end diff --git a/actionpack/lib/action_view/helpers/tags/date_select.rb b/actionpack/lib/action_view/helpers/tags/date_select.rb index 5912598ca1..5d706087b0 100644 --- a/actionpack/lib/action_view/helpers/tags/date_select.rb +++ b/actionpack/lib/action_view/helpers/tags/date_select.rb @@ -12,10 +12,16 @@ module ActionView error_wrapping(datetime_selector(@options, @html_options).send("select_#{select_type}").html_safe) end + class << self + def select_type + @select_type ||= self.name.split("::").last.sub("Select", "").downcase + end + end + private def select_type - self.class.name.split("::").last.sub("Select", "").downcase + self.class.select_type end def datetime_selector(options, html_options) diff --git a/actionpack/lib/action_view/helpers/tags/label.rb b/actionpack/lib/action_view/helpers/tags/label.rb index 74ac92ee18..1bd71c2778 100644 --- a/actionpack/lib/action_view/helpers/tags/label.rb +++ b/actionpack/lib/action_view/helpers/tags/label.rb @@ -30,7 +30,7 @@ module ActionView add_default_name_and_id_for_value(tag_value, name_and_id) options.delete("index") options.delete("namespace") - options["for"] ||= name_and_id["id"] + options["for"] = name_and_id["id"] unless options.key?("for") if block_given? @template_object.label_tag(name_and_id["id"], options, &block) diff --git a/actionpack/lib/action_view/helpers/tags/select.rb b/actionpack/lib/action_view/helpers/tags/select.rb index 71fd4d04b7..53a108b7e6 100644 --- a/actionpack/lib/action_view/helpers/tags/select.rb +++ b/actionpack/lib/action_view/helpers/tags/select.rb @@ -4,27 +4,37 @@ module ActionView class Select < Base #:nodoc: def initialize(object_name, method_name, template_object, choices, options, html_options) @choices = choices + @choices = @choices.to_a if @choices.is_a?(Range) @html_options = html_options super(object_name, method_name, template_object, options) end def render - selected_value = @options.has_key?(:selected) ? @options[:selected] : value(@object) + option_tags_options = { + :selected => @options.fetch(:selected) { value(@object) }, + :disabled => @options[:disabled] + } - # Grouped choices look like this: - # - # [nil, []] - # { nil => [] } - # - if !@choices.empty? && @choices.first.respond_to?(:last) && Array === @choices.first.last - option_tags = grouped_options_for_select(@choices, :selected => selected_value, :disabled => @options[:disabled]) + option_tags = if grouped_choices? + grouped_options_for_select(@choices, option_tags_options) else - option_tags = options_for_select(@choices, :selected => selected_value, :disabled => @options[:disabled]) + options_for_select(@choices, option_tags_options) end select_content_tag(option_tags, @options, @html_options) end + + private + + # Grouped choices look like this: + # + # [nil, []] + # { nil => [] } + # + def grouped_choices? + !@choices.empty? && @choices.first.respond_to?(:last) && Array === @choices.first.last + end end end end diff --git a/actionpack/lib/action_view/helpers/tags/text_field.rb b/actionpack/lib/action_view/helpers/tags/text_field.rb index 0f81726eb4..ce5182d20f 100644 --- a/actionpack/lib/action_view/helpers/tags/text_field.rb +++ b/actionpack/lib/action_view/helpers/tags/text_field.rb @@ -13,10 +13,16 @@ module ActionView tag("input", options) end + class << self + def field_type + @field_type ||= self.name.split("::").last.sub("Field", "").downcase + end + end + private def field_type - @field_type ||= self.class.name.split("::").last.sub("Field", "").downcase + self.class.field_type end end end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index ce79a3da48..3dc651501e 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -90,11 +90,11 @@ module ActionView # Highlights one or more +phrases+ everywhere in +text+ by inserting it into # a <tt>:highlighter</tt> string. The highlighter can be specialized by passing <tt>:highlighter</tt> # as a single-quoted string with \1 where the phrase is to be inserted (defaults to - # '<strong class="highlight">\1</strong>') + # '<mark>\1</mark>') # # ==== Examples # highlight('You searched for: rails', 'rails') - # # => You searched for: <strong class="highlight">rails</strong> + # # => You searched for: <mark>rails</mark> # # highlight('You searched for: ruby, rails, dhh', 'actionpack') # # => You searched for: ruby, rails, dhh @@ -111,9 +111,9 @@ module ActionView def highlight(text, phrases, *args) options = args.extract_options! unless args.empty? - options[:highlighter] = args[0] || '<strong class="highlight">\1</strong>' + options[:highlighter] = args[0] || '<mark>\1</mark>' end - options.reverse_merge!(:highlighter => '<strong class="highlight">\1</strong>') + options.reverse_merge!(:highlighter => '<mark>\1</mark>') text = sanitize(text) unless options[:sanitize] == false if text.blank? || phrases.blank? diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index ebd1f280a8..b5fc882e31 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -323,33 +323,24 @@ module ActionView # # def button_to(name, options = {}, html_options = {}) html_options = html_options.stringify_keys - convert_boolean_attributes!(html_options, %w( disabled )) + convert_boolean_attributes!(html_options, %w(disabled)) - method_tag = '' - if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s) - method_tag = tag('input', :type => 'hidden', :name => '_method', :value => method.to_s) - end + url = options.is_a?(String) ? options : url_for(options) + remote = html_options.delete('remote') + + method = html_options.delete('method').to_s + method_tag = %w{put delete}.include?(method) ? method_tag(method) : "" - form_method = method.to_s == 'get' ? 'get' : 'post' + form_method = method == 'get' ? 'get' : 'post' form_options = html_options.delete('form') || {} form_options[:class] ||= html_options.delete('form_class') || 'button_to' + form_options.merge!(:method => form_method, :action => url) + form_options.merge!("data-remote" => "true") if remote - remote = html_options.delete('remote') - - request_token_tag = '' - if form_method == 'post' && protect_against_forgery? - request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) - end - - url = options.is_a?(String) ? options : self.url_for(options) - name ||= url + request_token_tag = form_method == 'post' ? token_tag : '' html_options = convert_options_to_data_attributes(options, html_options) - - html_options.merge!("type" => "submit", "value" => name) - - form_options.merge!(:method => form_method, :action => url) - form_options.merge!("data-remote" => "true") if remote + html_options.merge!("type" => "submit", "value" => name || url) "#{tag(:form, form_options, true)}<div>#{method_tag}#{tag("input", html_options)}#{request_token_tag}</div></form>".html_safe end @@ -476,7 +467,7 @@ module ActionView # string given as the value. # * <tt>:subject</tt> - Preset the subject line of the email. # * <tt>:body</tt> - Preset the body of the email. - # * <tt>:cc</tt> - Carbon Copy addition recipients on the email. + # * <tt>:cc</tt> - Carbon Copy additional recipients on the email. # * <tt>:bcc</tt> - Blind Carbon Copy additional recipients on the email. # # ==== Examples @@ -599,11 +590,7 @@ module ActionView # We ignore any extra parameters in the request_uri if the # submitted url doesn't have any either. This lets the function # work with things like ?order=asc - if url_string.index("?") - request_uri = request.fullpath - else - request_uri = request.path - end + request_uri = url_string.index("?") ? request.fullpath : request.path if url_string =~ /^\w+:\/\// url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}" @@ -633,12 +620,12 @@ module ActionView end def link_to_remote_options?(options) - options.is_a?(Hash) && options.key?('remote') && options.delete('remote') + options.is_a?(Hash) && options.delete('remote') end def add_method_to_attributes!(html_options, method) if method && method.to_s.downcase != "get" && html_options["rel"] !~ /nofollow/ - html_options["rel"] = "#{html_options["rel"]} nofollow".strip + html_options["rel"] = "#{html_options["rel"]} nofollow".lstrip end html_options["data-method"] = method end @@ -670,6 +657,19 @@ module ActionView bool_attrs.each { |x| html_options[x] = x if html_options.delete(x) } html_options end + + def token_tag(token=nil) + if token == false || !protect_against_forgery? + '' + else + token ||= form_authenticity_token + tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => token) + end + end + + def method_tag(method) + tag('input', :type => 'hidden', :name => '_method', :value => method.to_s) + end end end end diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml index f2a83b92a9..7cca7d969a 100644 --- a/actionpack/lib/action_view/locale/en.yml +++ b/actionpack/lib/action_view/locale/en.yml @@ -37,6 +37,7 @@ # precision: # significant: false # strip_insignificant_zeros: false + format: "%n%" # Used in number_to_precision() precision: diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index e231aade01..3033294883 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -85,8 +85,7 @@ module ActionView # == Rendering objects that respond to `to_partial_path` # # Instead of explicitly naming the location of a partial, you can also let PartialRenderer do the work - # and pick the proper path by checking `to_proper_path` method. If the object passed to render is a collection, - # all objects must return the same path. + # and pick the proper path by checking `to_partial_path` method. # # # @account.to_partial_path returns 'accounts/account', so it can be used to replace: # # <%= render :partial => "accounts/account", :locals => { :account => @account} %> diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 593eaa2abf..edb3d427d5 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -288,7 +288,7 @@ module ActionView logger.debug "Backtrace: #{e.backtrace.join("\n")}" end - raise ActionView::Template::Error.new(self, {}, e) + raise ActionView::Template::Error.new(self, e) end end @@ -297,13 +297,12 @@ module ActionView e.sub_template_of(self) raise e else - assigns = view.respond_to?(:assigns) ? view.assigns : {} template = self unless template.source template = refresh(view) template.encode! end - raise Template::Error.new(template, assigns, e) + raise Template::Error.new(template, e) end end diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index 83df2604bb..d8258f7b11 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -55,9 +55,9 @@ module ActionView attr_reader :original_exception, :backtrace - def initialize(template, assigns, original_exception) + def initialize(template, original_exception) super(original_exception.message) - @template, @assigns, @original_exception = template, assigns.dup, original_exception + @template, @original_exception = template, original_exception @sub_templates = nil @backtrace = original_exception.backtrace end diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb index aa693335e3..67978ada7e 100644 --- a/actionpack/lib/action_view/template/handlers.rb +++ b/actionpack/lib/action_view/template/handlers.rb @@ -17,15 +17,12 @@ module ActionView #:nodoc: @@template_extensions ||= @@template_handlers.keys end - # Register a class that knows how to handle template files with the given + # Register an object that knows how to handle template files with the given # extension. This can be used to implement new template types. - # The constructor for the class must take the ActiveView::Base instance - # as a parameter, and the class must implement a +render+ method that - # takes the contents of the template to render as well as the Hash of - # local assigns available to the template. The +render+ method ought to - # return the rendered template as a string. - def register_template_handler(extension, klass) - @@template_handlers[extension.to_sym] = klass + # The handler must respond to `:call`, which will be passed the template + # and should return the rendered template as a String. + def register_template_handler(extension, handler) + @@template_handlers[extension.to_sym] = handler end def template_handler_extensions diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index b00f69e636..fece499c94 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -59,8 +59,10 @@ module ActionView end def determine_default_helper_class(name) - mod = name.sub(/Test$/, '').safe_constantize + mod = name.sub(/Test$/, '').constantize mod.is_a?(Class) ? nil : mod + rescue NameError + nil end def helper_method(*methods) diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake index f3547359cd..2e92fe416b 100644 --- a/actionpack/lib/sprockets/assets.rake +++ b/actionpack/lib/sprockets/assets.rake @@ -6,7 +6,11 @@ namespace :assets do groups = ENV['RAILS_GROUPS'] || 'assets' args = [$0, task,"RAILS_ENV=#{env}","RAILS_GROUPS=#{groups}"] args << "--trace" if Rake.application.options.trace - fork ? ruby(*args) : Kernel.exec(FileUtils::RUBY, *args) + if $0 =~ /rake\.bat\Z/i + Kernel.exec $0, *args + else + fork ? ruby(*args) : Kernel.exec(FileUtils::RUBY, *args) + end end # We are currently running with no explicit bundler group diff --git a/actionpack/lib/sprockets/compressors.rb b/actionpack/lib/sprockets/compressors.rb index cb3e13314b..8b728d6570 100644 --- a/actionpack/lib/sprockets/compressors.rb +++ b/actionpack/lib/sprockets/compressors.rb @@ -1,38 +1,28 @@ module Sprockets module Compressors + extend self + @@css_compressors = {} @@js_compressors = {} @@default_css_compressor = nil @@default_js_compressor = nil - def self.register_css_compressor(name, klass, options = {}) + def register_css_compressor(name, klass, options = {}) @@default_css_compressor = name.to_sym if options[:default] || @@default_css_compressor.nil? - @@css_compressors[name.to_sym] = {:klass => klass.to_s, :require => options[:require]} + @@css_compressors[name.to_sym] = { :klass => klass.to_s, :require => options[:require] } end - def self.register_js_compressor(name, klass, options = {}) + def register_js_compressor(name, klass, options = {}) @@default_js_compressor = name.to_sym if options[:default] || @@default_js_compressor.nil? - @@js_compressors[name.to_sym] = {:klass => klass.to_s, :require => options[:require]} + @@js_compressors[name.to_sym] = { :klass => klass.to_s, :require => options[:require] } end - def self.registered_css_compressor(name) - if name.respond_to?(:to_sym) - compressor = @@css_compressors[name.to_sym] || @@css_compressors[@@default_css_compressor] - require compressor[:require] if compressor[:require] - compressor[:klass].constantize.new - else - name - end + def registered_css_compressor(name) + find_registered_compressor name, @@css_compressors, @@default_css_compressor end - def self.registered_js_compressor(name) - if name.respond_to?(:to_sym) - compressor = @@js_compressors[name.to_sym] || @@js_compressors[@@default_js_compressor] - require compressor[:require] if compressor[:require] - compressor[:klass].constantize.new - else - name - end + def registered_js_compressor(name) + find_registered_compressor name, @@js_compressors, @@default_js_compressor end # The default compressors must be registered in default plugins (ex. Sass-Rails) @@ -43,6 +33,18 @@ module Sprockets register_css_compressor(:yui, 'YUI::CssCompressor', :require => 'yui/compressor') register_js_compressor(:closure, 'Closure::Compiler', :require => 'closure-compiler') register_js_compressor(:yui, 'YUI::JavaScriptCompressor', :require => 'yui/compressor') + + private + + def find_registered_compressor(name, compressors_hash, default_compressor_name) + if name.respond_to?(:to_sym) + compressor = compressors_hash[name.to_sym] || compressors_hash[default_compressor_name] + require compressor[:require] if compressor[:require] + compressor[:klass].constantize.new + else + name + end + end end # An asset compressor which does nothing. diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb index 44ddab0950..2bc482a39d 100644 --- a/actionpack/lib/sprockets/railtie.rb +++ b/actionpack/lib/sprockets/railtie.rb @@ -24,7 +24,7 @@ module Sprockets env.version = ::Rails.env + "-#{config.assets.version}" if config.assets.logger != false - env.logger = config.assets.logger || ::Rails.logger + env.logger = config.assets.logger || ::Rails.logger end if config.assets.cache_store != false diff --git a/actionpack/lib/sprockets/static_compiler.rb b/actionpack/lib/sprockets/static_compiler.rb index 719df0bd51..9bbb464474 100644 --- a/actionpack/lib/sprockets/static_compiler.rb +++ b/actionpack/lib/sprockets/static_compiler.rb @@ -8,8 +8,8 @@ module Sprockets @env = env @target = target @paths = paths - @digest = options.key?(:digest) ? options.delete(:digest) : true - @manifest = options.key?(:manifest) ? options.delete(:manifest) : true + @digest = options.fetch(:digest, true) + @manifest = options.fetch(:manifest, true) @manifest_path = options.delete(:manifest_path) || target @zip_files = options.delete(:zip_files) || /\.(?:css|html|js|svg|txt|xml)$/ end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 0a25d7ba47..b1a5356ddd 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -344,6 +344,21 @@ module ActionDispatch end end +module ActionDispatch + module RoutingVerbs + def get(uri_or_host, path = nil, port = nil) + host = uri_or_host.host unless path + path ||= uri_or_host.path + + params = {'PATH_INFO' => path, + 'REQUEST_METHOD' => 'GET', + 'HTTP_HOST' => host} + + routes.call(params)[2].join + end + end +end + module RoutingTestHelpers def url_for(set, options, recall = nil) set.send(:url_for, options.merge(:only_path => true, :_path_segments => recall)) diff --git a/actionpack/test/controller/addresses_render_test.rb b/actionpack/test/controller/addresses_render_test.rb deleted file mode 100644 index 0b5f2d7679..0000000000 --- a/actionpack/test/controller/addresses_render_test.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'abstract_unit' -require 'active_support/logger' -require 'controller/fake_controllers' - -class Address - def Address.count(conditions = nil, join = nil) - nil - end - - def Address.find_all(arg1, arg2, arg3, arg4) - [] - end - - def self.find(*args) - [] - end -end - -class AddressesTest < ActionController::TestCase - tests AddressesController - - def setup - super - # enable a logger so that (e.g.) the benchmarking stuff runs, so we can get - # a more accurate simulation of what happens in "real life". - @controller.logger = ActiveSupport::Logger.new(nil) - - @request.host = "www.nextangle.com" - end - - def test_list - get :list - assert_equal "We only need to get this far!", @response.body.chomp - end -end diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index b95a524612..791edb9069 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -93,6 +93,12 @@ class ControllerInstanceTests < ActiveSupport::TestCase Submodule::ContainedNonEmptyController.new] end + def test_performed? + assert !@empty.performed? + @empty.response_body = ["sweet"] + assert @empty.performed? + end + def test_action_methods @empty_controllers.each do |c| assert_equal Set.new, c.class.action_methods, "#{c.controller_path} should be empty!" @@ -152,6 +158,22 @@ class UrlOptionsTest < ActionController::TestCase rescue_action_in_public! end + def test_url_for_query_params_included + rs = ActionDispatch::Routing::RouteSet.new + rs.draw do + match 'home' => 'pages#home' + end + + options = { + :action => "home", + :controller => "pages", + :only_path => true, + :params => { "token" => "secret" } + } + + assert_equal '/home?token=secret', rs.url_for(options) + end + def test_url_options_override with_routing do |set| set.draw do diff --git a/actionpack/test/controller/force_ssl_test.rb b/actionpack/test/controller/force_ssl_test.rb index 125012631e..b681a19fe0 100644 --- a/actionpack/test/controller/force_ssl_test.rb +++ b/actionpack/test/controller/force_ssl_test.rb @@ -39,10 +39,8 @@ class ForceSSLFlash < ForceSSLController @flashy = flash["that"] render :inline => "hello" end - end - class ForceSSLControllerLevelTest < ActionController::TestCase tests ForceSSLControllerLevel @@ -52,6 +50,12 @@ class ForceSSLControllerLevelTest < ActionController::TestCase assert_equal "https://test.host/force_ssl_controller_level/banana", redirect_to_url end + def test_banana_redirects_to_https_with_extra_params + get :banana, :token => "secret" + assert_response 301 + assert_equal "https://test.host/force_ssl_controller_level/banana?token=secret", redirect_to_url + end + def test_cheeseburger_redirects_to_https get :cheeseburger assert_response 301 @@ -135,5 +139,4 @@ class ForceSSLFlashTest < ActionController::TestCase assert_equal "hello", assigns["flash_copy"]["that"] assert_equal "hello", assigns["flashy"] end - end diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 60498822ff..69a8f4f213 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -593,6 +593,19 @@ class RenderJsonRespondWithController < RespondWithController format.json { render :json => RenderJsonTestException.new('boom') } end end + + def create + resource = ValidatedCustomer.new(params[:name], 1) + respond_with(resource) do |format| + format.json do + if resource.errors.empty? + render :json => { :valid => true } + else + render :json => { :valid => false } + end + end + end + end end class EmptyRespondWithController < ActionController::Base @@ -964,6 +977,18 @@ class RespondWithControllerTest < ActionController::TestCase assert_match(/"error":"RenderJsonTestException"/, @response.body) end + def test_api_response_with_valid_resource_respect_override_block + @controller = RenderJsonRespondWithController.new + post :create, :name => "sikachu", :format => :json + assert_equal '{"valid":true}', @response.body + end + + def test_api_response_with_invalid_resource_respect_override_block + @controller = RenderJsonRespondWithController.new + post :create, :name => "david", :format => :json + assert_equal '{"valid":false}', @response.body + end + def test_no_double_render_is_raised @request.accept = "text/html" assert_raise ActionView::MissingTemplate do diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb index 4a291582d8..e6d3fa74f2 100644 --- a/actionpack/test/controller/request_forgery_protection_test.rb +++ b/actionpack/test/controller/request_forgery_protection_test.rb @@ -1,6 +1,5 @@ require 'abstract_unit' require 'digest/sha1' -require 'active_support/core_ext/string/strip' require "active_support/log_subscriber/test_helper" # common controller actions @@ -72,9 +71,7 @@ class CustomAuthenticityParamController < RequestForgeryProtectionController end end - # common test methods - module RequestForgeryProtectionTests def setup @token = "cf50faa3fe97702ca1ae" @@ -246,10 +243,6 @@ class FreeCookieControllerTest < ActionController::TestCase end end - - - - class CustomAuthenticityParamControllerTest < ActionController::TestCase def setup ActionController::Base.request_forgery_protection_token = :custom_token_name diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb index 86d6737cbb..9c51db135b 100644 --- a/actionpack/test/controller/rescue_test.rb +++ b/actionpack/test/controller/rescue_test.rb @@ -137,11 +137,11 @@ class RescueController < ActionController::Base end def io_error_in_view - raise ActionView::TemplateError.new(nil, {}, IOError.new('this is io error')) + raise ActionView::TemplateError.new(nil, IOError.new('this is io error')) end def zero_division_error_in_view - raise ActionView::TemplateError.new(nil, {}, ZeroDivisionError.new('this is zero division error')) + raise ActionView::TemplateError.new(nil, ZeroDivisionError.new('this is zero division error')) end protected diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index bec9eb16f3..d403494261 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -73,23 +73,76 @@ end class LegacyRouteSetTests < ActiveSupport::TestCase include RoutingTestHelpers + include ActionDispatch::RoutingVerbs attr_reader :rs + alias :routes :rs def setup @rs = ::ActionDispatch::Routing::RouteSet.new @response = nil end - def get(uri_or_host, path = nil, port = nil) - host = uri_or_host.host unless path - path ||= uri_or_host.path + def test_symbols_with_dashes + rs.draw do + match '/:artist/:song-omg', :to => lambda { |env| + resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] + [200, {}, [resp]] + } + end + + hash = JSON.load get(URI('http://example.org/journey/faithfully-omg')) + assert_equal({"artist"=>"journey", "song"=>"faithfully"}, hash) + end + + def test_id_with_dash + rs.draw do + match '/journey/:id', :to => lambda { |env| + resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] + [200, {}, [resp]] + } + end + + hash = JSON.load get(URI('http://example.org/journey/faithfully-omg')) + assert_equal({"id"=>"faithfully-omg"}, hash) + end + + def test_dash_with_custom_regexp + rs.draw do + match '/:artist/:song-omg', :constraints => { :song => /\d+/ }, :to => lambda { |env| + resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] + [200, {}, [resp]] + } + end - params = {'PATH_INFO' => path, - 'REQUEST_METHOD' => 'GET', - 'HTTP_HOST' => host} + hash = JSON.load get(URI('http://example.org/journey/123-omg')) + assert_equal({"artist"=>"journey", "song"=>"123"}, hash) + assert_equal 'Not Found', get(URI('http://example.org/journey/faithfully-omg')) + end + + def test_pre_dash + rs.draw do + match '/:artist/omg-:song', :to => lambda { |env| + resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] + [200, {}, [resp]] + } + end - @rs.call(params)[2].join + hash = JSON.load get(URI('http://example.org/journey/omg-faithfully')) + assert_equal({"artist"=>"journey", "song"=>"faithfully"}, hash) + end + + def test_pre_dash_with_custom_regexp + rs.draw do + match '/:artist/omg-:song', :constraints => { :song => /\d+/ }, :to => lambda { |env| + resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] + [200, {}, [resp]] + } + end + + hash = JSON.load get(URI('http://example.org/journey/omg-123')) + assert_equal({"artist"=>"journey", "song"=>"123"}, hash) + assert_equal 'Not Found', get(URI('http://example.org/journey/omg-faithfully')) end def test_regexp_precidence @@ -189,36 +242,6 @@ class LegacyRouteSetTests < ActiveSupport::TestCase test_default_setup end - def test_time_recognition - # We create many routes to make situation more realistic - @rs = ::ActionDispatch::Routing::RouteSet.new - @rs.draw { - root :to => "search#new", :as => "frontpage" - resources :videos do - resources :comments - resource :file, :controller => 'video_file' - resource :share, :controller => 'video_shares' - resource :abuse, :controller => 'video_abuses' - end - resources :abuses, :controller => 'video_abuses' - resources :video_uploads - resources :video_visits - - resources :users do - resource :settings - resources :videos - end - resources :channels do - resources :videos, :controller => 'channel_videos' - end - resource :session - resource :lost_password - match 'search' => 'search#index', :as => 'search' - resources :pages - match ':controller/:action/:id' - } - end - def test_route_with_colon_first rs.draw do match '/:controller/:action/:id', :action => 'index', :id => nil @@ -1327,7 +1350,20 @@ class RouteSetTest < ActiveSupport::TestCase end end end - + + def test_route_with_subdomain_and_constraints_must_receive_params + name_param = nil + set.draw do + match 'page/:name' => 'pages#show', :constraints => lambda {|request| + name_param = request.params[:name] + return true + } + end + assert_equal({:controller => 'pages', :action => 'show', :name => 'mypage'}, + set.recognize_path('http://subdomain.example.org/page/mypage')) + assert_equal(name_param, 'mypage') + end + def test_route_requirement_recognize_with_ignore_case set.draw do match 'page/:name' => 'pages#show', diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb index caf76c7e61..c957df88b3 100644 --- a/actionpack/test/controller/test_case_test.rb +++ b/actionpack/test/controller/test_case_test.rb @@ -1,6 +1,5 @@ require 'abstract_unit' require 'controller/fake_controllers' -require 'active_support/ordered_hash' class TestCaseTest < ActionController::TestCase class TestController < ActionController::Base @@ -155,14 +154,14 @@ XML end def test_raw_post_handling - params = ActiveSupport::OrderedHash[:page, {:name => 'page name'}, 'some key', 123] + params = Hash[:page, {:name => 'page name'}, 'some key', 123] post :render_raw_post, params.dup assert_equal params.to_query, @response.body end def test_body_stream - params = ActiveSupport::OrderedHash[:page, { :name => 'page name' }, 'some key', 123] + params = Hash[:page, { :name => 'page name' }, 'some key', 123] post :render_body, params.dup diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb index 6ebd02e85c..3e48d97e67 100644 --- a/actionpack/test/dispatch/cookies_test.rb +++ b/actionpack/test/dispatch/cookies_test.rb @@ -245,6 +245,17 @@ class CookiesTest < ActionController::TestCase assert_cookie_header "user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT" end + def test_deleted_cookie_predicate + cookies.delete("user_name") + assert cookies.deleted?("user_name") + assert_equal false, cookies.deleted?("another") + end + + def test_deleted_cookie_predicate_with_mismatching_options + cookies.delete("user_name", :path => "/path") + assert_equal false, cookies.deleted?("user_name", :path => "/different") + end + def test_cookies_persist_throughout_request response = get :authenticate assert response.headers["Set-Cookie"] =~ /user_name=david/ diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb index c3a565990e..11c292d61a 100644 --- a/actionpack/test/dispatch/debug_exceptions_test.rb +++ b/actionpack/test/dispatch/debug_exceptions_test.rb @@ -34,7 +34,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest when "/unprocessable_entity" raise ActionController::InvalidAuthenticityToken when "/not_found_original_exception" - raise ActionView::Template::Error.new('template', {}, AbstractController::ActionNotFound.new) + raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new) else raise "puke!" end diff --git a/actionpack/test/dispatch/middleware_stack_test.rb b/actionpack/test/dispatch/middleware_stack_test.rb index 831f3db3e2..4191ed1ff4 100644 --- a/actionpack/test/dispatch/middleware_stack_test.rb +++ b/actionpack/test/dispatch/middleware_stack_test.rb @@ -81,6 +81,12 @@ class MiddlewareStackTest < ActiveSupport::TestCase assert_equal BazMiddleware, @stack[0].klass end + test "swaps one middleware out for same middleware class" do + assert_equal FooMiddleware, @stack[0].klass + @stack.swap(FooMiddleware, FooMiddleware, Proc.new { |env| [500, {}, ['error!']] }) + assert_equal FooMiddleware, @stack[0].klass + end + test "raise an error on invalid index" do assert_raise RuntimeError do @stack.insert("HiyaMiddleware", BazMiddleware) diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index db21080c42..0372c42920 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -69,6 +69,12 @@ class MimeTypeTest < ActiveSupport::TestCase assert_equal expect, Mime::Type.parse(accept) end + test "parse single media range with q" do + accept = "text/html;q=0.9" + expect = [Mime::HTML] + assert_equal expect, Mime::Type.parse(accept) + end + # Accept header send with user HTTP_USER_AGENT: Sunrise/0.42j (Windows XP) test "parse broken acceptlines" do accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/*,,*/*;q=0.5" diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index 5b3d38c48c..8f0ac5310e 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -42,7 +42,7 @@ class RequestTest < ActiveSupport::TestCase 'HTTP_X_FORWARDED_FOR' => '3.4.5.6' assert_equal '3.4.5.6', request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,3.4.5.6' + request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,unknown' assert_equal '3.4.5.6', request.remote_ip request = stub_request 'HTTP_X_FORWARDED_FOR' => '172.16.0.1,3.4.5.6' @@ -63,7 +63,7 @@ class RequestTest < ActiveSupport::TestCase request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1' assert_equal 'unknown', request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4' + request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6, 9.9.9.9, 10.0.0.1, 172.31.4.4' assert_equal '3.4.5.6', request.remote_ip request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1', @@ -85,7 +85,7 @@ class RequestTest < ActiveSupport::TestCase :ip_spoofing_check => false assert_equal '2.2.2.2', request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, 9.9.9.9' + request = stub_request 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 8.8.8.8' assert_equal '9.9.9.9', request.remote_ip end @@ -94,8 +94,8 @@ class RequestTest < ActiveSupport::TestCase assert_equal '127.0.0.1', request.remote_ip end - test "remote ip with user specified trusted proxies" do - @trusted_proxies = /^67\.205\.106\.73$/i + test "remote ip with user specified trusted proxies String" do + @trusted_proxies = "67.205.106.73" request = stub_request 'REMOTE_ADDR' => '67.205.106.73', 'HTTP_X_FORWARDED_FOR' => '3.4.5.6' @@ -116,10 +116,21 @@ class RequestTest < ActiveSupport::TestCase request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,67.205.106.73' assert_equal 'unknown', request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 10.0.0.1, 67.205.106.73' + request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6, 9.9.9.9, 10.0.0.1, 67.205.106.73' assert_equal '3.4.5.6', request.remote_ip end + test "remote ip with user specified trusted proxies Regexp" do + @trusted_proxies = /^67\.205\.106\.73$/i + + request = stub_request 'REMOTE_ADDR' => '67.205.106.73', + 'HTTP_X_FORWARDED_FOR' => '3.4.5.6' + assert_equal '3.4.5.6', request.remote_ip + + request = stub_request 'HTTP_X_FORWARDED_FOR' => '67.205.106.73, 10.0.0.1, 9.9.9.9, 3.4.5.6' + assert_equal '10.0.0.1', request.remote_ip + end + test "domains" do request = stub_request 'HTTP_HOST' => 'www.rubyonrails.org' assert_equal "rubyonrails.org", request.domain diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index c6e6ed4d6b..c3c1c12e82 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 require 'erb' require 'abstract_unit' require 'controller/fake_controllers' @@ -578,52 +579,42 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest include Routes.url_helpers def test_logout - with_test_routes do - delete '/logout' - assert_equal 'sessions#destroy', @response.body + delete '/logout' + assert_equal 'sessions#destroy', @response.body - assert_equal '/logout', logout_path - assert_equal '/logout', url_for(:controller => 'sessions', :action => 'destroy', :only_path => true) - end + assert_equal '/logout', logout_path + assert_equal '/logout', url_for(:controller => 'sessions', :action => 'destroy', :only_path => true) end def test_login - with_test_routes do - get '/login' - assert_equal 'sessions#new', @response.body - assert_equal '/login', login_path + get '/login' + assert_equal 'sessions#new', @response.body + assert_equal '/login', login_path - post '/login' - assert_equal 'sessions#create', @response.body + post '/login' + assert_equal 'sessions#create', @response.body - assert_equal '/login', url_for(:controller => 'sessions', :action => 'create', :only_path => true) - assert_equal '/login', url_for(:controller => 'sessions', :action => 'new', :only_path => true) + assert_equal '/login', url_for(:controller => 'sessions', :action => 'create', :only_path => true) + assert_equal '/login', url_for(:controller => 'sessions', :action => 'new', :only_path => true) - assert_equal 'http://rubyonrails.org/login', Routes.url_for(:controller => 'sessions', :action => 'create') - assert_equal 'http://rubyonrails.org/login', Routes.url_helpers.login_url - end + assert_equal 'http://rubyonrails.org/login', Routes.url_for(:controller => 'sessions', :action => 'create') + assert_equal 'http://rubyonrails.org/login', Routes.url_helpers.login_url end def test_login_redirect - with_test_routes do - get '/account/login' - verify_redirect 'http://www.example.com/login' - end + get '/account/login' + verify_redirect 'http://www.example.com/login' end def test_logout_redirect_without_to - with_test_routes do - assert_equal '/account/logout', logout_redirect_path - get '/account/logout' - verify_redirect 'http://www.example.com/logout' - end + assert_equal '/account/logout', logout_redirect_path + get '/account/logout' + verify_redirect 'http://www.example.com/logout' end def test_namespace_redirect - with_test_routes do - get '/private' - verify_redirect 'http://www.example.com/private/index' - end + get '/private' + verify_redirect 'http://www.example.com/private/index' end def test_namespace_with_controller_segment @@ -639,189 +630,159 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end def test_session_singleton_resource - with_test_routes do - get '/session' - assert_equal 'sessions#create', @response.body - assert_equal '/session', session_path + get '/session' + assert_equal 'sessions#create', @response.body + assert_equal '/session', session_path - post '/session' - assert_equal 'sessions#create', @response.body + post '/session' + assert_equal 'sessions#create', @response.body - put '/session' - assert_equal 'sessions#update', @response.body + put '/session' + assert_equal 'sessions#update', @response.body - delete '/session' - assert_equal 'sessions#destroy', @response.body + delete '/session' + assert_equal 'sessions#destroy', @response.body - get '/session/new' - assert_equal 'sessions#new', @response.body - assert_equal '/session/new', new_session_path + get '/session/new' + assert_equal 'sessions#new', @response.body + assert_equal '/session/new', new_session_path - get '/session/edit' - assert_equal 'sessions#edit', @response.body - assert_equal '/session/edit', edit_session_path + get '/session/edit' + assert_equal 'sessions#edit', @response.body + assert_equal '/session/edit', edit_session_path - post '/session/reset' - assert_equal 'sessions#reset', @response.body - assert_equal '/session/reset', reset_session_path - end + post '/session/reset' + assert_equal 'sessions#reset', @response.body + assert_equal '/session/reset', reset_session_path end def test_session_info_nested_singleton_resource - with_test_routes do - get '/session/info' - assert_equal 'infos#show', @response.body - assert_equal '/session/info', session_info_path - end + get '/session/info' + assert_equal 'infos#show', @response.body + assert_equal '/session/info', session_info_path end def test_member_on_resource - with_test_routes do - get '/session/crush' - assert_equal 'sessions#crush', @response.body - assert_equal '/session/crush', crush_session_path - end + get '/session/crush' + assert_equal 'sessions#crush', @response.body + assert_equal '/session/crush', crush_session_path end def test_redirect_modulo - with_test_routes do - get '/account/modulo/name' - verify_redirect 'http://www.example.com/names' - end + get '/account/modulo/name' + verify_redirect 'http://www.example.com/names' end def test_redirect_proc - with_test_routes do - get '/account/proc/person' - verify_redirect 'http://www.example.com/people' - end + get '/account/proc/person' + verify_redirect 'http://www.example.com/people' end def test_redirect_proc_with_request - with_test_routes do - get '/account/proc_req' - verify_redirect 'http://www.example.com/GET' - end + get '/account/proc_req' + verify_redirect 'http://www.example.com/GET' end def test_redirect_hash_with_subdomain - with_test_routes do - get '/mobile' - verify_redirect 'http://mobile.example.com/mobile' - end + get '/mobile' + verify_redirect 'http://mobile.example.com/mobile' end def test_redirect_hash_with_host - with_test_routes do - get '/super_new_documentation?section=top' - verify_redirect 'http://super-docs.com/super_new_documentation?section=top' - end + get '/super_new_documentation?section=top' + verify_redirect 'http://super-docs.com/super_new_documentation?section=top' end def test_redirect_class - with_test_routes do - get '/youtube_favorites/oHg5SJYRHA0/rick-rolld' - verify_redirect 'http://www.youtube.com/watch?v=oHg5SJYRHA0' - end + get '/youtube_favorites/oHg5SJYRHA0/rick-rolld' + verify_redirect 'http://www.youtube.com/watch?v=oHg5SJYRHA0' end def test_openid - with_test_routes do - get '/openid/login' - assert_equal 'openid#login', @response.body + get '/openid/login' + assert_equal 'openid#login', @response.body - post '/openid/login' - assert_equal 'openid#login', @response.body - end + post '/openid/login' + assert_equal 'openid#login', @response.body end def test_bookmarks - with_test_routes do - get '/bookmark/build' - assert_equal 'bookmarks#new', @response.body - assert_equal '/bookmark/build', bookmark_new_path - - post '/bookmark/create' - assert_equal 'bookmarks#create', @response.body - assert_equal '/bookmark/create', bookmark_path - - put '/bookmark/update' - assert_equal 'bookmarks#update', @response.body - assert_equal '/bookmark/update', bookmark_update_path - - get '/bookmark/remove' - assert_equal 'bookmarks#destroy', @response.body - assert_equal '/bookmark/remove', bookmark_remove_path - end + get '/bookmark/build' + assert_equal 'bookmarks#new', @response.body + assert_equal '/bookmark/build', bookmark_new_path + + post '/bookmark/create' + assert_equal 'bookmarks#create', @response.body + assert_equal '/bookmark/create', bookmark_path + + put '/bookmark/update' + assert_equal 'bookmarks#update', @response.body + assert_equal '/bookmark/update', bookmark_update_path + + get '/bookmark/remove' + assert_equal 'bookmarks#destroy', @response.body + assert_equal '/bookmark/remove', bookmark_remove_path end def test_pagemarks - with_test_routes do - get '/pagemark/build' - assert_equal 'pagemarks#new', @response.body - assert_equal '/pagemark/build', pagemark_new_path - - post '/pagemark/create' - assert_equal 'pagemarks#create', @response.body - assert_equal '/pagemark/create', pagemark_path - - put '/pagemark/update' - assert_equal 'pagemarks#update', @response.body - assert_equal '/pagemark/update', pagemark_update_path - - get '/pagemark/remove' - assert_equal 'pagemarks#destroy', @response.body - assert_equal '/pagemark/remove', pagemark_remove_path - end + get '/pagemark/build' + assert_equal 'pagemarks#new', @response.body + assert_equal '/pagemark/build', pagemark_new_path + + post '/pagemark/create' + assert_equal 'pagemarks#create', @response.body + assert_equal '/pagemark/create', pagemark_path + + put '/pagemark/update' + assert_equal 'pagemarks#update', @response.body + assert_equal '/pagemark/update', pagemark_update_path + + get '/pagemark/remove' + assert_equal 'pagemarks#destroy', @response.body + assert_equal '/pagemark/remove', pagemark_remove_path end def test_admin - with_test_routes do - get '/admin', {}, {'REMOTE_ADDR' => '192.168.1.100'} - assert_equal 'queenbee#index', @response.body + get '/admin', {}, {'REMOTE_ADDR' => '192.168.1.100'} + assert_equal 'queenbee#index', @response.body - get '/admin', {}, {'REMOTE_ADDR' => '10.0.0.100'} - assert_equal 'pass', @response.headers['X-Cascade'] + get '/admin', {}, {'REMOTE_ADDR' => '10.0.0.100'} + assert_equal 'pass', @response.headers['X-Cascade'] - get '/admin/accounts', {}, {'REMOTE_ADDR' => '192.168.1.100'} - assert_equal 'queenbee#accounts', @response.body + get '/admin/accounts', {}, {'REMOTE_ADDR' => '192.168.1.100'} + assert_equal 'queenbee#accounts', @response.body - get '/admin/accounts', {}, {'REMOTE_ADDR' => '10.0.0.100'} - assert_equal 'pass', @response.headers['X-Cascade'] + get '/admin/accounts', {}, {'REMOTE_ADDR' => '10.0.0.100'} + assert_equal 'pass', @response.headers['X-Cascade'] - get '/admin/passwords', {}, {'REMOTE_ADDR' => '192.168.1.100'} - assert_equal 'queenbee#passwords', @response.body + get '/admin/passwords', {}, {'REMOTE_ADDR' => '192.168.1.100'} + assert_equal 'queenbee#passwords', @response.body - get '/admin/passwords', {}, {'REMOTE_ADDR' => '10.0.0.100'} - assert_equal 'pass', @response.headers['X-Cascade'] - end + get '/admin/passwords', {}, {'REMOTE_ADDR' => '10.0.0.100'} + assert_equal 'pass', @response.headers['X-Cascade'] end def test_global - with_test_routes do - get '/global/dashboard' - assert_equal 'global#dashboard', @response.body + get '/global/dashboard' + assert_equal 'global#dashboard', @response.body - get '/global/export' - assert_equal 'global#export', @response.body + get '/global/export' + assert_equal 'global#export', @response.body - get '/global/hide_notice' - assert_equal 'global#hide_notice', @response.body + get '/global/hide_notice' + assert_equal 'global#hide_notice', @response.body - get '/export/123/foo.txt' - assert_equal 'global#export', @response.body + get '/export/123/foo.txt' + assert_equal 'global#export', @response.body - assert_equal '/global/export', export_request_path - assert_equal '/global/hide_notice', global_hide_notice_path - assert_equal '/export/123/foo.txt', export_download_path(:id => 123, :file => 'foo.txt') - end + assert_equal '/global/export', export_request_path + assert_equal '/global/hide_notice', global_hide_notice_path + assert_equal '/export/123/foo.txt', export_download_path(:id => 123, :file => 'foo.txt') end def test_local - with_test_routes do - get '/local/dashboard' - assert_equal 'local#dashboard', @response.body - end + get '/local/dashboard' + assert_equal 'local#dashboard', @response.body end # tests the use of dup in url_for @@ -848,648 +809,553 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end def test_projects_status - with_test_routes do - assert_equal '/projects/status', url_for(:controller => 'projects', :action => 'status', :only_path => true) - assert_equal '/projects/status.json', url_for(:controller => 'projects', :action => 'status', :format => 'json', :only_path => true) - end + assert_equal '/projects/status', url_for(:controller => 'projects', :action => 'status', :only_path => true) + assert_equal '/projects/status.json', url_for(:controller => 'projects', :action => 'status', :format => 'json', :only_path => true) end def test_projects - with_test_routes do - get '/projects' - assert_equal 'project#index', @response.body - assert_equal '/projects', projects_path + get '/projects' + assert_equal 'project#index', @response.body + assert_equal '/projects', projects_path - post '/projects' - assert_equal 'project#create', @response.body + post '/projects' + assert_equal 'project#create', @response.body - get '/projects.xml' - assert_equal 'project#index', @response.body - assert_equal '/projects.xml', projects_path(:format => 'xml') + get '/projects.xml' + assert_equal 'project#index', @response.body + assert_equal '/projects.xml', projects_path(:format => 'xml') - get '/projects/new' - assert_equal 'project#new', @response.body - assert_equal '/projects/new', new_project_path + get '/projects/new' + assert_equal 'project#new', @response.body + assert_equal '/projects/new', new_project_path - get '/projects/new.xml' - assert_equal 'project#new', @response.body - assert_equal '/projects/new.xml', new_project_path(:format => 'xml') + get '/projects/new.xml' + assert_equal 'project#new', @response.body + assert_equal '/projects/new.xml', new_project_path(:format => 'xml') - get '/projects/1' - assert_equal 'project#show', @response.body - assert_equal '/projects/1', project_path(:id => '1') + get '/projects/1' + assert_equal 'project#show', @response.body + assert_equal '/projects/1', project_path(:id => '1') - get '/projects/1.xml' - assert_equal 'project#show', @response.body - assert_equal '/projects/1.xml', project_path(:id => '1', :format => 'xml') + get '/projects/1.xml' + assert_equal 'project#show', @response.body + assert_equal '/projects/1.xml', project_path(:id => '1', :format => 'xml') - get '/projects/1/edit' - assert_equal 'project#edit', @response.body - assert_equal '/projects/1/edit', edit_project_path(:id => '1') - end + get '/projects/1/edit' + assert_equal 'project#edit', @response.body + assert_equal '/projects/1/edit', edit_project_path(:id => '1') end def test_projects_involvements - with_test_routes do - get '/projects/1/involvements' - assert_equal 'involvements#index', @response.body - assert_equal '/projects/1/involvements', project_involvements_path(:project_id => '1') + get '/projects/1/involvements' + assert_equal 'involvements#index', @response.body + assert_equal '/projects/1/involvements', project_involvements_path(:project_id => '1') - get '/projects/1/involvements/new' - assert_equal 'involvements#new', @response.body - assert_equal '/projects/1/involvements/new', new_project_involvement_path(:project_id => '1') + get '/projects/1/involvements/new' + assert_equal 'involvements#new', @response.body + assert_equal '/projects/1/involvements/new', new_project_involvement_path(:project_id => '1') - get '/projects/1/involvements/1' - assert_equal 'involvements#show', @response.body - assert_equal '/projects/1/involvements/1', project_involvement_path(:project_id => '1', :id => '1') + get '/projects/1/involvements/1' + assert_equal 'involvements#show', @response.body + assert_equal '/projects/1/involvements/1', project_involvement_path(:project_id => '1', :id => '1') - put '/projects/1/involvements/1' - assert_equal 'involvements#update', @response.body + put '/projects/1/involvements/1' + assert_equal 'involvements#update', @response.body - delete '/projects/1/involvements/1' - assert_equal 'involvements#destroy', @response.body + delete '/projects/1/involvements/1' + assert_equal 'involvements#destroy', @response.body - get '/projects/1/involvements/1/edit' - assert_equal 'involvements#edit', @response.body - assert_equal '/projects/1/involvements/1/edit', edit_project_involvement_path(:project_id => '1', :id => '1') - end + get '/projects/1/involvements/1/edit' + assert_equal 'involvements#edit', @response.body + assert_equal '/projects/1/involvements/1/edit', edit_project_involvement_path(:project_id => '1', :id => '1') end def test_projects_attachments - with_test_routes do - get '/projects/1/attachments' - assert_equal 'attachments#index', @response.body - assert_equal '/projects/1/attachments', project_attachments_path(:project_id => '1') - end + get '/projects/1/attachments' + assert_equal 'attachments#index', @response.body + assert_equal '/projects/1/attachments', project_attachments_path(:project_id => '1') end def test_projects_participants - with_test_routes do - get '/projects/1/participants' - assert_equal 'participants#index', @response.body - assert_equal '/projects/1/participants', project_participants_path(:project_id => '1') - - put '/projects/1/participants/update_all' - assert_equal 'participants#update_all', @response.body - assert_equal '/projects/1/participants/update_all', update_all_project_participants_path(:project_id => '1') - end + get '/projects/1/participants' + assert_equal 'participants#index', @response.body + assert_equal '/projects/1/participants', project_participants_path(:project_id => '1') + + put '/projects/1/participants/update_all' + assert_equal 'participants#update_all', @response.body + assert_equal '/projects/1/participants/update_all', update_all_project_participants_path(:project_id => '1') end def test_projects_companies - with_test_routes do - get '/projects/1/companies' - assert_equal 'companies#index', @response.body - assert_equal '/projects/1/companies', project_companies_path(:project_id => '1') - - get '/projects/1/companies/1/people' - assert_equal 'people#index', @response.body - assert_equal '/projects/1/companies/1/people', project_company_people_path(:project_id => '1', :company_id => '1') - - get '/projects/1/companies/1/avatar' - assert_equal 'avatar#show', @response.body - assert_equal '/projects/1/companies/1/avatar', project_company_avatar_path(:project_id => '1', :company_id => '1') - end + get '/projects/1/companies' + assert_equal 'companies#index', @response.body + assert_equal '/projects/1/companies', project_companies_path(:project_id => '1') + + get '/projects/1/companies/1/people' + assert_equal 'people#index', @response.body + assert_equal '/projects/1/companies/1/people', project_company_people_path(:project_id => '1', :company_id => '1') + + get '/projects/1/companies/1/avatar' + assert_equal 'avatar#show', @response.body + assert_equal '/projects/1/companies/1/avatar', project_company_avatar_path(:project_id => '1', :company_id => '1') end def test_project_manager - with_test_routes do - get '/projects/1/manager' - assert_equal 'managers#show', @response.body - assert_equal '/projects/1/manager', project_super_manager_path(:project_id => '1') - - get '/projects/1/manager/new' - assert_equal 'managers#new', @response.body - assert_equal '/projects/1/manager/new', new_project_super_manager_path(:project_id => '1') - - post '/projects/1/manager/fire' - assert_equal 'managers#fire', @response.body - assert_equal '/projects/1/manager/fire', fire_project_super_manager_path(:project_id => '1') - end + get '/projects/1/manager' + assert_equal 'managers#show', @response.body + assert_equal '/projects/1/manager', project_super_manager_path(:project_id => '1') + + get '/projects/1/manager/new' + assert_equal 'managers#new', @response.body + assert_equal '/projects/1/manager/new', new_project_super_manager_path(:project_id => '1') + + post '/projects/1/manager/fire' + assert_equal 'managers#fire', @response.body + assert_equal '/projects/1/manager/fire', fire_project_super_manager_path(:project_id => '1') end def test_project_images - with_test_routes do - get '/projects/1/images' - assert_equal 'images#index', @response.body - assert_equal '/projects/1/images', project_funny_images_path(:project_id => '1') - - get '/projects/1/images/new' - assert_equal 'images#new', @response.body - assert_equal '/projects/1/images/new', new_project_funny_image_path(:project_id => '1') - - post '/projects/1/images/1/revise' - assert_equal 'images#revise', @response.body - assert_equal '/projects/1/images/1/revise', revise_project_funny_image_path(:project_id => '1', :id => '1') - end + get '/projects/1/images' + assert_equal 'images#index', @response.body + assert_equal '/projects/1/images', project_funny_images_path(:project_id => '1') + + get '/projects/1/images/new' + assert_equal 'images#new', @response.body + assert_equal '/projects/1/images/new', new_project_funny_image_path(:project_id => '1') + + post '/projects/1/images/1/revise' + assert_equal 'images#revise', @response.body + assert_equal '/projects/1/images/1/revise', revise_project_funny_image_path(:project_id => '1', :id => '1') end def test_projects_people - with_test_routes do - get '/projects/1/people' - assert_equal 'people#index', @response.body - assert_equal '/projects/1/people', project_people_path(:project_id => '1') - - get '/projects/1/people/1' - assert_equal 'people#show', @response.body - assert_equal '/projects/1/people/1', project_person_path(:project_id => '1', :id => '1') - - get '/projects/1/people/1/7a2dec8/avatar' - assert_equal 'avatars#show', @response.body - assert_equal '/projects/1/people/1/7a2dec8/avatar', project_person_avatar_path(:project_id => '1', :person_id => '1', :access_token => '7a2dec8') - - put '/projects/1/people/1/accessible_projects' - assert_equal 'people#accessible_projects', @response.body - assert_equal '/projects/1/people/1/accessible_projects', accessible_projects_project_person_path(:project_id => '1', :id => '1') - - post '/projects/1/people/1/resend' - assert_equal 'people#resend', @response.body - assert_equal '/projects/1/people/1/resend', resend_project_person_path(:project_id => '1', :id => '1') - - post '/projects/1/people/1/generate_new_password' - assert_equal 'people#generate_new_password', @response.body - assert_equal '/projects/1/people/1/generate_new_password', generate_new_password_project_person_path(:project_id => '1', :id => '1') - end + get '/projects/1/people' + assert_equal 'people#index', @response.body + assert_equal '/projects/1/people', project_people_path(:project_id => '1') + + get '/projects/1/people/1' + assert_equal 'people#show', @response.body + assert_equal '/projects/1/people/1', project_person_path(:project_id => '1', :id => '1') + + get '/projects/1/people/1/7a2dec8/avatar' + assert_equal 'avatars#show', @response.body + assert_equal '/projects/1/people/1/7a2dec8/avatar', project_person_avatar_path(:project_id => '1', :person_id => '1', :access_token => '7a2dec8') + + put '/projects/1/people/1/accessible_projects' + assert_equal 'people#accessible_projects', @response.body + assert_equal '/projects/1/people/1/accessible_projects', accessible_projects_project_person_path(:project_id => '1', :id => '1') + + post '/projects/1/people/1/resend' + assert_equal 'people#resend', @response.body + assert_equal '/projects/1/people/1/resend', resend_project_person_path(:project_id => '1', :id => '1') + + post '/projects/1/people/1/generate_new_password' + assert_equal 'people#generate_new_password', @response.body + assert_equal '/projects/1/people/1/generate_new_password', generate_new_password_project_person_path(:project_id => '1', :id => '1') end def test_projects_with_resources_path_names - with_test_routes do - get '/projects/info_about_correlation_indexes' - assert_equal 'project#correlation_indexes', @response.body - assert_equal '/projects/info_about_correlation_indexes', correlation_indexes_projects_path - end + get '/projects/info_about_correlation_indexes' + assert_equal 'project#correlation_indexes', @response.body + assert_equal '/projects/info_about_correlation_indexes', correlation_indexes_projects_path end def test_projects_posts - with_test_routes do - get '/projects/1/posts' - assert_equal 'posts#index', @response.body - assert_equal '/projects/1/posts', project_posts_path(:project_id => '1') - - get '/projects/1/posts/archive' - assert_equal 'posts#archive', @response.body - assert_equal '/projects/1/posts/archive', archive_project_posts_path(:project_id => '1') - - get '/projects/1/posts/toggle_view' - assert_equal 'posts#toggle_view', @response.body - assert_equal '/projects/1/posts/toggle_view', toggle_view_project_posts_path(:project_id => '1') - - post '/projects/1/posts/1/preview' - assert_equal 'posts#preview', @response.body - assert_equal '/projects/1/posts/1/preview', preview_project_post_path(:project_id => '1', :id => '1') - - get '/projects/1/posts/1/subscription' - assert_equal 'subscriptions#show', @response.body - assert_equal '/projects/1/posts/1/subscription', project_post_subscription_path(:project_id => '1', :post_id => '1') - - get '/projects/1/posts/1/comments' - assert_equal 'comments#index', @response.body - assert_equal '/projects/1/posts/1/comments', project_post_comments_path(:project_id => '1', :post_id => '1') - - post '/projects/1/posts/1/comments/preview' - assert_equal 'comments#preview', @response.body - assert_equal '/projects/1/posts/1/comments/preview', preview_project_post_comments_path(:project_id => '1', :post_id => '1') - end + get '/projects/1/posts' + assert_equal 'posts#index', @response.body + assert_equal '/projects/1/posts', project_posts_path(:project_id => '1') + + get '/projects/1/posts/archive' + assert_equal 'posts#archive', @response.body + assert_equal '/projects/1/posts/archive', archive_project_posts_path(:project_id => '1') + + get '/projects/1/posts/toggle_view' + assert_equal 'posts#toggle_view', @response.body + assert_equal '/projects/1/posts/toggle_view', toggle_view_project_posts_path(:project_id => '1') + + post '/projects/1/posts/1/preview' + assert_equal 'posts#preview', @response.body + assert_equal '/projects/1/posts/1/preview', preview_project_post_path(:project_id => '1', :id => '1') + + get '/projects/1/posts/1/subscription' + assert_equal 'subscriptions#show', @response.body + assert_equal '/projects/1/posts/1/subscription', project_post_subscription_path(:project_id => '1', :post_id => '1') + + get '/projects/1/posts/1/comments' + assert_equal 'comments#index', @response.body + assert_equal '/projects/1/posts/1/comments', project_post_comments_path(:project_id => '1', :post_id => '1') + + post '/projects/1/posts/1/comments/preview' + assert_equal 'comments#preview', @response.body + assert_equal '/projects/1/posts/1/comments/preview', preview_project_post_comments_path(:project_id => '1', :post_id => '1') end def test_replies - with_test_routes do - put '/replies/1/answer' - assert_equal 'replies#mark_as_answer', @response.body + put '/replies/1/answer' + assert_equal 'replies#mark_as_answer', @response.body - delete '/replies/1/answer' - assert_equal 'replies#unmark_as_answer', @response.body - end + delete '/replies/1/answer' + assert_equal 'replies#unmark_as_answer', @response.body end def test_resource_routes_with_only_and_except - with_test_routes do - get '/posts' - assert_equal 'posts#index', @response.body - assert_equal '/posts', posts_path - - get '/posts/1' - assert_equal 'posts#show', @response.body - assert_equal '/posts/1', post_path(:id => 1) - - get '/posts/1/comments' - assert_equal 'comments#index', @response.body - assert_equal '/posts/1/comments', post_comments_path(:post_id => 1) - - post '/posts' - assert_equal 'pass', @response.headers['X-Cascade'] - put '/posts/1' - assert_equal 'pass', @response.headers['X-Cascade'] - delete '/posts/1' - assert_equal 'pass', @response.headers['X-Cascade'] - delete '/posts/1/comments' - assert_equal 'pass', @response.headers['X-Cascade'] - end + get '/posts' + assert_equal 'posts#index', @response.body + assert_equal '/posts', posts_path + + get '/posts/1' + assert_equal 'posts#show', @response.body + assert_equal '/posts/1', post_path(:id => 1) + + get '/posts/1/comments' + assert_equal 'comments#index', @response.body + assert_equal '/posts/1/comments', post_comments_path(:post_id => 1) + + post '/posts' + assert_equal 'pass', @response.headers['X-Cascade'] + put '/posts/1' + assert_equal 'pass', @response.headers['X-Cascade'] + delete '/posts/1' + assert_equal 'pass', @response.headers['X-Cascade'] + delete '/posts/1/comments' + assert_equal 'pass', @response.headers['X-Cascade'] end def test_resource_routes_only_create_update_destroy - with_test_routes do - delete '/past' - assert_equal 'pasts#destroy', @response.body - assert_equal '/past', past_path - - put '/present' - assert_equal 'presents#update', @response.body - assert_equal '/present', present_path - - post '/future' - assert_equal 'futures#create', @response.body - assert_equal '/future', future_path - end + delete '/past' + assert_equal 'pasts#destroy', @response.body + assert_equal '/past', past_path + + put '/present' + assert_equal 'presents#update', @response.body + assert_equal '/present', present_path + + post '/future' + assert_equal 'futures#create', @response.body + assert_equal '/future', future_path end def test_resources_routes_only_create_update_destroy - with_test_routes do - post '/relationships' - assert_equal 'relationships#create', @response.body - assert_equal '/relationships', relationships_path - - delete '/relationships/1' - assert_equal 'relationships#destroy', @response.body - assert_equal '/relationships/1', relationship_path(1) - - put '/friendships/1' - assert_equal 'friendships#update', @response.body - assert_equal '/friendships/1', friendship_path(1) - end + post '/relationships' + assert_equal 'relationships#create', @response.body + assert_equal '/relationships', relationships_path + + delete '/relationships/1' + assert_equal 'relationships#destroy', @response.body + assert_equal '/relationships/1', relationship_path(1) + + put '/friendships/1' + assert_equal 'friendships#update', @response.body + assert_equal '/friendships/1', friendship_path(1) end def test_resource_with_slugs_in_ids - with_test_routes do - get '/posts/rails-rocks' - assert_equal 'posts#show', @response.body - assert_equal '/posts/rails-rocks', post_path(:id => 'rails-rocks') - end + get '/posts/rails-rocks' + assert_equal 'posts#show', @response.body + assert_equal '/posts/rails-rocks', post_path(:id => 'rails-rocks') end def test_resources_for_uncountable_names - with_test_routes do - assert_equal '/sheep', sheep_index_path - assert_equal '/sheep/1', sheep_path(1) - assert_equal '/sheep/new', new_sheep_path - assert_equal '/sheep/1/edit', edit_sheep_path(1) - assert_equal '/sheep/1/_it', _it_sheep_path(1) - end + assert_equal '/sheep', sheep_index_path + assert_equal '/sheep/1', sheep_path(1) + assert_equal '/sheep/new', new_sheep_path + assert_equal '/sheep/1/edit', edit_sheep_path(1) + assert_equal '/sheep/1/_it', _it_sheep_path(1) end def test_path_names - with_test_routes do - get '/pt/projetos' - assert_equal 'projects#index', @response.body - assert_equal '/pt/projetos', pt_projects_path - - get '/pt/projetos/1/editar' - assert_equal 'projects#edit', @response.body - assert_equal '/pt/projetos/1/editar', edit_pt_project_path(1) - - get '/pt/administrador' - assert_equal 'admins#show', @response.body - assert_equal '/pt/administrador', pt_admin_path - - get '/pt/administrador/novo' - assert_equal 'admins#new', @response.body - assert_equal '/pt/administrador/novo', new_pt_admin_path - - put '/pt/administrador/ativar' - assert_equal 'admins#activate', @response.body - assert_equal '/pt/administrador/ativar', activate_pt_admin_path - end + get '/pt/projetos' + assert_equal 'projects#index', @response.body + assert_equal '/pt/projetos', pt_projects_path + + get '/pt/projetos/1/editar' + assert_equal 'projects#edit', @response.body + assert_equal '/pt/projetos/1/editar', edit_pt_project_path(1) + + get '/pt/administrador' + assert_equal 'admins#show', @response.body + assert_equal '/pt/administrador', pt_admin_path + + get '/pt/administrador/novo' + assert_equal 'admins#new', @response.body + assert_equal '/pt/administrador/novo', new_pt_admin_path + + put '/pt/administrador/ativar' + assert_equal 'admins#activate', @response.body + assert_equal '/pt/administrador/ativar', activate_pt_admin_path end def test_path_option_override - with_test_routes do - get '/pt/projetos/novo/abrir' - assert_equal 'projects#open', @response.body - assert_equal '/pt/projetos/novo/abrir', open_new_pt_project_path - - put '/pt/projetos/1/fechar' - assert_equal 'projects#close', @response.body - assert_equal '/pt/projetos/1/fechar', close_pt_project_path(1) - end + get '/pt/projetos/novo/abrir' + assert_equal 'projects#open', @response.body + assert_equal '/pt/projetos/novo/abrir', open_new_pt_project_path + + put '/pt/projetos/1/fechar' + assert_equal 'projects#close', @response.body + assert_equal '/pt/projetos/1/fechar', close_pt_project_path(1) end def test_sprockets - with_test_routes do - get '/sprockets.js' - assert_equal 'javascripts', @response.body - end + get '/sprockets.js' + assert_equal 'javascripts', @response.body end def test_update_person_route - with_test_routes do - get '/people/1/update' - assert_equal 'people#update', @response.body + get '/people/1/update' + assert_equal 'people#update', @response.body - assert_equal '/people/1/update', update_person_path(:id => 1) - end + assert_equal '/people/1/update', update_person_path(:id => 1) end def test_update_project_person - with_test_routes do - get '/projects/1/people/2/update' - assert_equal 'people#update', @response.body + get '/projects/1/people/2/update' + assert_equal 'people#update', @response.body - assert_equal '/projects/1/people/2/update', update_project_person_path(:project_id => 1, :id => 2) - end + assert_equal '/projects/1/people/2/update', update_project_person_path(:project_id => 1, :id => 2) end def test_forum_products - with_test_routes do - get '/forum' - assert_equal 'forum/products#index', @response.body - assert_equal '/forum', forum_products_path - - get '/forum/basecamp' - assert_equal 'forum/products#show', @response.body - assert_equal '/forum/basecamp', forum_product_path(:id => 'basecamp') - - get '/forum/basecamp/questions' - assert_equal 'forum/questions#index', @response.body - assert_equal '/forum/basecamp/questions', forum_product_questions_path(:product_id => 'basecamp') - - get '/forum/basecamp/questions/1' - assert_equal 'forum/questions#show', @response.body - assert_equal '/forum/basecamp/questions/1', forum_product_question_path(:product_id => 'basecamp', :id => 1) - end + get '/forum' + assert_equal 'forum/products#index', @response.body + assert_equal '/forum', forum_products_path + + get '/forum/basecamp' + assert_equal 'forum/products#show', @response.body + assert_equal '/forum/basecamp', forum_product_path(:id => 'basecamp') + + get '/forum/basecamp/questions' + assert_equal 'forum/questions#index', @response.body + assert_equal '/forum/basecamp/questions', forum_product_questions_path(:product_id => 'basecamp') + + get '/forum/basecamp/questions/1' + assert_equal 'forum/questions#show', @response.body + assert_equal '/forum/basecamp/questions/1', forum_product_question_path(:product_id => 'basecamp', :id => 1) end def test_articles_perma - with_test_routes do - get '/articles/2009/08/18/rails-3' - assert_equal 'articles#show', @response.body + get '/articles/2009/08/18/rails-3' + assert_equal 'articles#show', @response.body - assert_equal '/articles/2009/8/18/rails-3', article_path(:year => 2009, :month => 8, :day => 18, :title => 'rails-3') - end + assert_equal '/articles/2009/8/18/rails-3', article_path(:year => 2009, :month => 8, :day => 18, :title => 'rails-3') end def test_account_namespace - with_test_routes do - get '/account/subscription' - assert_equal 'account/subscriptions#show', @response.body - assert_equal '/account/subscription', account_subscription_path - - get '/account/credit' - assert_equal 'account/credits#show', @response.body - assert_equal '/account/credit', account_credit_path - - get '/account/credit_card' - assert_equal 'account/credit_cards#show', @response.body - assert_equal '/account/credit_card', account_credit_card_path - end + get '/account/subscription' + assert_equal 'account/subscriptions#show', @response.body + assert_equal '/account/subscription', account_subscription_path + + get '/account/credit' + assert_equal 'account/credits#show', @response.body + assert_equal '/account/credit', account_credit_path + + get '/account/credit_card' + assert_equal 'account/credit_cards#show', @response.body + assert_equal '/account/credit_card', account_credit_card_path end def test_nested_namespace - with_test_routes do - get '/account/admin/subscription' - assert_equal 'account/admin/subscriptions#show', @response.body - assert_equal '/account/admin/subscription', account_admin_subscription_path - end + get '/account/admin/subscription' + assert_equal 'account/admin/subscriptions#show', @response.body + assert_equal '/account/admin/subscription', account_admin_subscription_path end def test_namespace_nested_in_resources - with_test_routes do - get '/clients/1/google/account' - assert_equal '/clients/1/google/account', client_google_account_path(1) - assert_equal 'google/accounts#show', @response.body - - get '/clients/1/google/account/secret/info' - assert_equal '/clients/1/google/account/secret/info', client_google_account_secret_info_path(1) - assert_equal 'google/secret/infos#show', @response.body - end + get '/clients/1/google/account' + assert_equal '/clients/1/google/account', client_google_account_path(1) + assert_equal 'google/accounts#show', @response.body + + get '/clients/1/google/account/secret/info' + assert_equal '/clients/1/google/account/secret/info', client_google_account_secret_info_path(1) + assert_equal 'google/secret/infos#show', @response.body end def test_namespace_with_options - with_test_routes do - get '/usuarios' - assert_equal '/usuarios', users_root_path - assert_equal 'users/home#index', @response.body - end + get '/usuarios' + assert_equal '/usuarios', users_root_path + assert_equal 'users/home#index', @response.body end def test_articles_with_id - with_test_routes do - get '/articles/rails/1' - assert_equal 'articles#with_id', @response.body + get '/articles/rails/1' + assert_equal 'articles#with_id', @response.body - get '/articles/123/1' - assert_equal 'pass', @response.headers['X-Cascade'] + get '/articles/123/1' + assert_equal 'pass', @response.headers['X-Cascade'] - assert_equal '/articles/rails/1', article_with_title_path(:title => 'rails', :id => 1) - end + assert_equal '/articles/rails/1', article_with_title_path(:title => 'rails', :id => 1) end def test_access_token_rooms - with_test_routes do - get '/12345/rooms' - assert_equal 'rooms#index', @response.body + get '/12345/rooms' + assert_equal 'rooms#index', @response.body - get '/12345/rooms/1' - assert_equal 'rooms#show', @response.body + get '/12345/rooms/1' + assert_equal 'rooms#show', @response.body - get '/12345/rooms/1/edit' - assert_equal 'rooms#edit', @response.body - end + get '/12345/rooms/1/edit' + assert_equal 'rooms#edit', @response.body end def test_root - with_test_routes do - assert_equal '/', root_path - get '/' - assert_equal 'projects#index', @response.body - end + assert_equal '/', root_path + get '/' + assert_equal 'projects#index', @response.body end def test_index - with_test_routes do - assert_equal '/info', info_path - get '/info' - assert_equal 'projects#info', @response.body - end + assert_equal '/info', info_path + get '/info' + assert_equal 'projects#info', @response.body end def test_match_shorthand_with_no_scope - with_test_routes do - assert_equal '/account/overview', account_overview_path - get '/account/overview' - assert_equal 'account#overview', @response.body - end + assert_equal '/account/overview', account_overview_path + get '/account/overview' + assert_equal 'account#overview', @response.body end def test_match_shorthand_inside_namespace - with_test_routes do - assert_equal '/account/shorthand', account_shorthand_path - get '/account/shorthand' - assert_equal 'account#shorthand', @response.body - end + assert_equal '/account/shorthand', account_shorthand_path + get '/account/shorthand' + assert_equal 'account#shorthand', @response.body end def test_dynamically_generated_helpers_on_collection_do_not_clobber_resources_url_helper - with_test_routes do - assert_equal '/replies', replies_path - end + assert_equal '/replies', replies_path end def test_scoped_controller_with_namespace_and_action - with_test_routes do - assert_equal '/account/twitter/callback', account_callback_path("twitter") - get '/account/twitter/callback' - assert_equal 'account/callbacks#twitter', @response.body + assert_equal '/account/twitter/callback', account_callback_path("twitter") + get '/account/twitter/callback' + assert_equal 'account/callbacks#twitter', @response.body - get '/account/whatever/callback' - assert_equal 'Not Found', @response.body - end + get '/account/whatever/callback' + assert_equal 'Not Found', @response.body end def test_convention_match_nested_and_with_leading_slash - with_test_routes do - assert_equal '/account/nested/overview', account_nested_overview_path - get '/account/nested/overview' - assert_equal 'account/nested#overview', @response.body - end + assert_equal '/account/nested/overview', account_nested_overview_path + get '/account/nested/overview' + assert_equal 'account/nested#overview', @response.body end def test_convention_with_explicit_end - with_test_routes do - get '/sign_in' - assert_equal 'sessions#new', @response.body - assert_equal '/sign_in', sign_in_path - end + get '/sign_in' + assert_equal 'sessions#new', @response.body + assert_equal '/sign_in', sign_in_path end def test_redirect_with_complete_url_and_status - with_test_routes do - get '/account/google' - verify_redirect 'http://www.google.com/', 302 - end + get '/account/google' + verify_redirect 'http://www.google.com/', 302 end def test_redirect_with_port previous_host, self.host = self.host, 'www.example.com:3000' - with_test_routes do - get '/account/login' - verify_redirect 'http://www.example.com:3000/login' - end + + get '/account/login' + verify_redirect 'http://www.example.com:3000/login' ensure self.host = previous_host end def test_normalize_namespaced_matches - with_test_routes do - assert_equal '/account/description', account_description_path + assert_equal '/account/description', account_description_path - get '/account/description' - assert_equal 'account#description', @response.body - end + get '/account/description' + assert_equal 'account#description', @response.body end def test_namespaced_roots - with_test_routes do - assert_equal '/account', account_root_path - get '/account' - assert_equal 'account/account#index', @response.body - end + assert_equal '/account', account_root_path + get '/account' + assert_equal 'account/account#index', @response.body end def test_optional_scoped_root - with_test_routes do - assert_equal '/en', root_path("en") - get '/en' - assert_equal 'projects#index', @response.body - end + assert_equal '/en', root_path("en") + get '/en' + assert_equal 'projects#index', @response.body end def test_optional_scoped_path - with_test_routes do - assert_equal '/en/descriptions', descriptions_path("en") - assert_equal '/descriptions', descriptions_path(nil) - assert_equal '/en/descriptions/1', description_path("en", 1) - assert_equal '/descriptions/1', description_path(nil, 1) + assert_equal '/en/descriptions', descriptions_path("en") + assert_equal '/descriptions', descriptions_path(nil) + assert_equal '/en/descriptions/1', description_path("en", 1) + assert_equal '/descriptions/1', description_path(nil, 1) - get '/en/descriptions' - assert_equal 'descriptions#index', @response.body + get '/en/descriptions' + assert_equal 'descriptions#index', @response.body - get '/descriptions' - assert_equal 'descriptions#index', @response.body + get '/descriptions' + assert_equal 'descriptions#index', @response.body - get '/en/descriptions/1' - assert_equal 'descriptions#show', @response.body + get '/en/descriptions/1' + assert_equal 'descriptions#show', @response.body - get '/descriptions/1' - assert_equal 'descriptions#show', @response.body - end + get '/descriptions/1' + assert_equal 'descriptions#show', @response.body end def test_nested_optional_scoped_path - with_test_routes do - assert_equal '/admin/en/descriptions', admin_descriptions_path("en") - assert_equal '/admin/descriptions', admin_descriptions_path(nil) - assert_equal '/admin/en/descriptions/1', admin_description_path("en", 1) - assert_equal '/admin/descriptions/1', admin_description_path(nil, 1) + assert_equal '/admin/en/descriptions', admin_descriptions_path("en") + assert_equal '/admin/descriptions', admin_descriptions_path(nil) + assert_equal '/admin/en/descriptions/1', admin_description_path("en", 1) + assert_equal '/admin/descriptions/1', admin_description_path(nil, 1) - get '/admin/en/descriptions' - assert_equal 'admin/descriptions#index', @response.body + get '/admin/en/descriptions' + assert_equal 'admin/descriptions#index', @response.body - get '/admin/descriptions' - assert_equal 'admin/descriptions#index', @response.body + get '/admin/descriptions' + assert_equal 'admin/descriptions#index', @response.body - get '/admin/en/descriptions/1' - assert_equal 'admin/descriptions#show', @response.body + get '/admin/en/descriptions/1' + assert_equal 'admin/descriptions#show', @response.body - get '/admin/descriptions/1' - assert_equal 'admin/descriptions#show', @response.body - end + get '/admin/descriptions/1' + assert_equal 'admin/descriptions#show', @response.body end def test_nested_optional_path_shorthand - with_test_routes do - get '/registrations/new' - assert_nil @request.params[:locale] + get '/registrations/new' + assert_nil @request.params[:locale] - get '/en/registrations/new' - assert_equal 'en', @request.params[:locale] - end + get '/en/registrations/new' + assert_equal 'en', @request.params[:locale] end def test_default_params - with_test_routes do - get '/inline_pages' - assert_equal 'home', @request.params[:id] + get '/inline_pages' + assert_equal 'home', @request.params[:id] - get '/default_pages' - assert_equal 'home', @request.params[:id] + get '/default_pages' + assert_equal 'home', @request.params[:id] - get '/scoped_pages' - assert_equal 'home', @request.params[:id] - end + get '/scoped_pages' + assert_equal 'home', @request.params[:id] end def test_resource_constraints - with_test_routes do - get '/products/1' - assert_equal 'pass', @response.headers['X-Cascade'] - get '/products' - assert_equal 'products#root', @response.body - get '/products/favorite' - assert_equal 'products#favorite', @response.body - get '/products/0001' - assert_equal 'products#show', @response.body - - get '/products/1/images' - assert_equal 'pass', @response.headers['X-Cascade'] - get '/products/0001/images' - assert_equal 'images#index', @response.body - get '/products/0001/images/0001' - assert_equal 'images#show', @response.body - - get '/dashboard', {}, {'REMOTE_ADDR' => '10.0.0.100'} - assert_equal 'pass', @response.headers['X-Cascade'] - get '/dashboard', {}, {'REMOTE_ADDR' => '192.168.1.100'} - assert_equal 'dashboards#show', @response.body - end + get '/products/1' + assert_equal 'pass', @response.headers['X-Cascade'] + get '/products' + assert_equal 'products#root', @response.body + get '/products/favorite' + assert_equal 'products#favorite', @response.body + get '/products/0001' + assert_equal 'products#show', @response.body + + get '/products/1/images' + assert_equal 'pass', @response.headers['X-Cascade'] + get '/products/0001/images' + assert_equal 'images#index', @response.body + get '/products/0001/images/0001' + assert_equal 'images#show', @response.body + + get '/dashboard', {}, {'REMOTE_ADDR' => '10.0.0.100'} + assert_equal 'pass', @response.headers['X-Cascade'] + get '/dashboard', {}, {'REMOTE_ADDR' => '192.168.1.100'} + assert_equal 'dashboards#show', @response.body end def test_root_works_in_the_resources_scope @@ -1499,731 +1365,651 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end def test_module_scope - with_test_routes do - get '/token' - assert_equal 'api/tokens#show', @response.body - assert_equal '/token', token_path - end + get '/token' + assert_equal 'api/tokens#show', @response.body + assert_equal '/token', token_path end def test_path_scope - with_test_routes do - get '/api/me' - assert_equal 'mes#show', @response.body - assert_equal '/api/me', me_path + get '/api/me' + assert_equal 'mes#show', @response.body + assert_equal '/api/me', me_path - get '/api' - assert_equal 'mes#index', @response.body - end + get '/api' + assert_equal 'mes#index', @response.body end def test_url_generator_for_generic_route - with_test_routes do - get 'whatever/foo/bar' - assert_equal 'foo#bar', @response.body + get 'whatever/foo/bar' + assert_equal 'foo#bar', @response.body - assert_equal 'http://www.example.com/whatever/foo/bar/1', - url_for(:controller => "foo", :action => "bar", :id => 1) - end + assert_equal 'http://www.example.com/whatever/foo/bar/1', + url_for(:controller => "foo", :action => "bar", :id => 1) end def test_url_generator_for_namespaced_generic_route - with_test_routes do - get 'whatever/foo/bar/show' - assert_equal 'foo/bar#show', @response.body + get 'whatever/foo/bar/show' + assert_equal 'foo/bar#show', @response.body - get 'whatever/foo/bar/show/1' - assert_equal 'foo/bar#show', @response.body + get 'whatever/foo/bar/show/1' + assert_equal 'foo/bar#show', @response.body - assert_equal 'http://www.example.com/whatever/foo/bar/show', - url_for(:controller => "foo/bar", :action => "show") + assert_equal 'http://www.example.com/whatever/foo/bar/show', + url_for(:controller => "foo/bar", :action => "show") - assert_equal 'http://www.example.com/whatever/foo/bar/show/1', - url_for(:controller => "foo/bar", :action => "show", :id => '1') - end + assert_equal 'http://www.example.com/whatever/foo/bar/show/1', + url_for(:controller => "foo/bar", :action => "show", :id => '1') end def test_assert_recognizes_account_overview - with_test_routes do - assert_recognizes({:controller => "account", :action => "overview"}, "/account/overview") - end + assert_recognizes({:controller => "account", :action => "overview"}, "/account/overview") end def test_resource_new_actions - with_test_routes do - assert_equal '/replies/new/preview', preview_new_reply_path - assert_equal '/pt/projetos/novo/preview', preview_new_pt_project_path - assert_equal '/pt/administrador/novo/preview', preview_new_pt_admin_path - assert_equal '/pt/products/novo/preview', preview_new_pt_product_path - assert_equal '/profile/new/preview', preview_new_profile_path + assert_equal '/replies/new/preview', preview_new_reply_path + assert_equal '/pt/projetos/novo/preview', preview_new_pt_project_path + assert_equal '/pt/administrador/novo/preview', preview_new_pt_admin_path + assert_equal '/pt/products/novo/preview', preview_new_pt_product_path + assert_equal '/profile/new/preview', preview_new_profile_path - post '/replies/new/preview' - assert_equal 'replies#preview', @response.body + post '/replies/new/preview' + assert_equal 'replies#preview', @response.body - post '/pt/projetos/novo/preview' - assert_equal 'projects#preview', @response.body + post '/pt/projetos/novo/preview' + assert_equal 'projects#preview', @response.body - post '/pt/administrador/novo/preview' - assert_equal 'admins#preview', @response.body + post '/pt/administrador/novo/preview' + assert_equal 'admins#preview', @response.body - post '/pt/products/novo/preview' - assert_equal 'products#preview', @response.body + post '/pt/products/novo/preview' + assert_equal 'products#preview', @response.body - post '/profile/new/preview' - assert_equal 'profiles#preview', @response.body - end + post '/profile/new/preview' + assert_equal 'profiles#preview', @response.body end def test_resource_merges_options_from_scope - with_test_routes do - assert_raise(NameError) { new_account_path } + assert_raise(NameError) { new_account_path } - get '/account/new' - assert_equal 404, status - end + get '/account/new' + assert_equal 404, status end def test_resources_merges_options_from_scope - with_test_routes do - assert_raise(NoMethodError) { edit_product_path('1') } + assert_raise(NoMethodError) { edit_product_path('1') } - get '/products/1/edit' - assert_equal 404, status + get '/products/1/edit' + assert_equal 404, status - assert_raise(NoMethodError) { edit_product_image_path('1', '2') } + assert_raise(NoMethodError) { edit_product_image_path('1', '2') } - post '/products/1/images/2/edit' - assert_equal 404, status - end + post '/products/1/images/2/edit' + assert_equal 404, status end def test_shallow_nested_resources - with_test_routes do + get '/api/teams' + assert_equal 'api/teams#index', @response.body + assert_equal '/api/teams', api_teams_path - get '/api/teams' - assert_equal 'api/teams#index', @response.body - assert_equal '/api/teams', api_teams_path + get '/api/teams/new' + assert_equal 'api/teams#new', @response.body + assert_equal '/api/teams/new', new_api_team_path - get '/api/teams/new' - assert_equal 'api/teams#new', @response.body - assert_equal '/api/teams/new', new_api_team_path + get '/api/teams/1' + assert_equal 'api/teams#show', @response.body + assert_equal '/api/teams/1', api_team_path(:id => '1') - get '/api/teams/1' - assert_equal 'api/teams#show', @response.body - assert_equal '/api/teams/1', api_team_path(:id => '1') + get '/api/teams/1/edit' + assert_equal 'api/teams#edit', @response.body + assert_equal '/api/teams/1/edit', edit_api_team_path(:id => '1') - get '/api/teams/1/edit' - assert_equal 'api/teams#edit', @response.body - assert_equal '/api/teams/1/edit', edit_api_team_path(:id => '1') + get '/api/teams/1/players' + assert_equal 'api/players#index', @response.body + assert_equal '/api/teams/1/players', api_team_players_path(:team_id => '1') - get '/api/teams/1/players' - assert_equal 'api/players#index', @response.body - assert_equal '/api/teams/1/players', api_team_players_path(:team_id => '1') + get '/api/teams/1/players/new' + assert_equal 'api/players#new', @response.body + assert_equal '/api/teams/1/players/new', new_api_team_player_path(:team_id => '1') - get '/api/teams/1/players/new' - assert_equal 'api/players#new', @response.body - assert_equal '/api/teams/1/players/new', new_api_team_player_path(:team_id => '1') + get '/api/players/2' + assert_equal 'api/players#show', @response.body + assert_equal '/api/players/2', api_player_path(:id => '2') - get '/api/players/2' - assert_equal 'api/players#show', @response.body - assert_equal '/api/players/2', api_player_path(:id => '2') + get '/api/players/2/edit' + assert_equal 'api/players#edit', @response.body + assert_equal '/api/players/2/edit', edit_api_player_path(:id => '2') - get '/api/players/2/edit' - assert_equal 'api/players#edit', @response.body - assert_equal '/api/players/2/edit', edit_api_player_path(:id => '2') + get '/api/teams/1/captain' + assert_equal 'api/captains#show', @response.body + assert_equal '/api/teams/1/captain', api_team_captain_path(:team_id => '1') - get '/api/teams/1/captain' - assert_equal 'api/captains#show', @response.body - assert_equal '/api/teams/1/captain', api_team_captain_path(:team_id => '1') + get '/api/teams/1/captain/new' + assert_equal 'api/captains#new', @response.body + assert_equal '/api/teams/1/captain/new', new_api_team_captain_path(:team_id => '1') - get '/api/teams/1/captain/new' - assert_equal 'api/captains#new', @response.body - assert_equal '/api/teams/1/captain/new', new_api_team_captain_path(:team_id => '1') + get '/api/teams/1/captain/edit' + assert_equal 'api/captains#edit', @response.body + assert_equal '/api/teams/1/captain/edit', edit_api_team_captain_path(:team_id => '1') - get '/api/teams/1/captain/edit' - assert_equal 'api/captains#edit', @response.body - assert_equal '/api/teams/1/captain/edit', edit_api_team_captain_path(:team_id => '1') + get '/threads' + assert_equal 'threads#index', @response.body + assert_equal '/threads', threads_path - get '/threads' - assert_equal 'threads#index', @response.body - assert_equal '/threads', threads_path + get '/threads/new' + assert_equal 'threads#new', @response.body + assert_equal '/threads/new', new_thread_path - get '/threads/new' - assert_equal 'threads#new', @response.body - assert_equal '/threads/new', new_thread_path + get '/threads/1' + assert_equal 'threads#show', @response.body + assert_equal '/threads/1', thread_path(:id => '1') - get '/threads/1' - assert_equal 'threads#show', @response.body - assert_equal '/threads/1', thread_path(:id => '1') + get '/threads/1/edit' + assert_equal 'threads#edit', @response.body + assert_equal '/threads/1/edit', edit_thread_path(:id => '1') - get '/threads/1/edit' - assert_equal 'threads#edit', @response.body - assert_equal '/threads/1/edit', edit_thread_path(:id => '1') + get '/threads/1/owner' + assert_equal 'owners#show', @response.body + assert_equal '/threads/1/owner', thread_owner_path(:thread_id => '1') - get '/threads/1/owner' - assert_equal 'owners#show', @response.body - assert_equal '/threads/1/owner', thread_owner_path(:thread_id => '1') + get '/threads/1/messages' + assert_equal 'messages#index', @response.body + assert_equal '/threads/1/messages', thread_messages_path(:thread_id => '1') - get '/threads/1/messages' - assert_equal 'messages#index', @response.body - assert_equal '/threads/1/messages', thread_messages_path(:thread_id => '1') + get '/threads/1/messages/new' + assert_equal 'messages#new', @response.body + assert_equal '/threads/1/messages/new', new_thread_message_path(:thread_id => '1') - get '/threads/1/messages/new' - assert_equal 'messages#new', @response.body - assert_equal '/threads/1/messages/new', new_thread_message_path(:thread_id => '1') + get '/messages/2' + assert_equal 'messages#show', @response.body + assert_equal '/messages/2', message_path(:id => '2') - get '/messages/2' - assert_equal 'messages#show', @response.body - assert_equal '/messages/2', message_path(:id => '2') + get '/messages/2/edit' + assert_equal 'messages#edit', @response.body + assert_equal '/messages/2/edit', edit_message_path(:id => '2') - get '/messages/2/edit' - assert_equal 'messages#edit', @response.body - assert_equal '/messages/2/edit', edit_message_path(:id => '2') + get '/messages/2/comments' + assert_equal 'comments#index', @response.body + assert_equal '/messages/2/comments', message_comments_path(:message_id => '2') - get '/messages/2/comments' - assert_equal 'comments#index', @response.body - assert_equal '/messages/2/comments', message_comments_path(:message_id => '2') + get '/messages/2/comments/new' + assert_equal 'comments#new', @response.body + assert_equal '/messages/2/comments/new', new_message_comment_path(:message_id => '2') - get '/messages/2/comments/new' - assert_equal 'comments#new', @response.body - assert_equal '/messages/2/comments/new', new_message_comment_path(:message_id => '2') + get '/comments/3' + assert_equal 'comments#show', @response.body + assert_equal '/comments/3', comment_path(:id => '3') - get '/comments/3' - assert_equal 'comments#show', @response.body - assert_equal '/comments/3', comment_path(:id => '3') + get '/comments/3/edit' + assert_equal 'comments#edit', @response.body + assert_equal '/comments/3/edit', edit_comment_path(:id => '3') - get '/comments/3/edit' - assert_equal 'comments#edit', @response.body - assert_equal '/comments/3/edit', edit_comment_path(:id => '3') - - post '/comments/3/preview' - assert_equal 'comments#preview', @response.body - assert_equal '/comments/3/preview', preview_comment_path(:id => '3') - end + post '/comments/3/preview' + assert_equal 'comments#preview', @response.body + assert_equal '/comments/3/preview', preview_comment_path(:id => '3') end def test_shallow_nested_resources_within_scope - with_test_routes do + get '/hello/notes/1/trackbacks' + assert_equal 'trackbacks#index', @response.body + assert_equal '/hello/notes/1/trackbacks', note_trackbacks_path(:note_id => 1) - get '/hello/notes/1/trackbacks' - assert_equal 'trackbacks#index', @response.body - assert_equal '/hello/notes/1/trackbacks', note_trackbacks_path(:note_id => 1) + get '/hello/notes/1/edit' + assert_equal 'notes#edit', @response.body + assert_equal '/hello/notes/1/edit', edit_note_path(:id => '1') - get '/hello/notes/1/edit' - assert_equal 'notes#edit', @response.body - assert_equal '/hello/notes/1/edit', edit_note_path(:id => '1') + get '/hello/notes/1/trackbacks/new' + assert_equal 'trackbacks#new', @response.body + assert_equal '/hello/notes/1/trackbacks/new', new_note_trackback_path(:note_id => 1) - get '/hello/notes/1/trackbacks/new' - assert_equal 'trackbacks#new', @response.body - assert_equal '/hello/notes/1/trackbacks/new', new_note_trackback_path(:note_id => 1) + get '/hello/trackbacks/1' + assert_equal 'trackbacks#show', @response.body + assert_equal '/hello/trackbacks/1', trackback_path(:id => '1') - get '/hello/trackbacks/1' - assert_equal 'trackbacks#show', @response.body - assert_equal '/hello/trackbacks/1', trackback_path(:id => '1') + get '/hello/trackbacks/1/edit' + assert_equal 'trackbacks#edit', @response.body + assert_equal '/hello/trackbacks/1/edit', edit_trackback_path(:id => '1') - get '/hello/trackbacks/1/edit' - assert_equal 'trackbacks#edit', @response.body - assert_equal '/hello/trackbacks/1/edit', edit_trackback_path(:id => '1') + put '/hello/trackbacks/1' + assert_equal 'trackbacks#update', @response.body - put '/hello/trackbacks/1' - assert_equal 'trackbacks#update', @response.body + post '/hello/notes/1/trackbacks' + assert_equal 'trackbacks#create', @response.body - post '/hello/notes/1/trackbacks' - assert_equal 'trackbacks#create', @response.body + delete '/hello/trackbacks/1' + assert_equal 'trackbacks#destroy', @response.body - delete '/hello/trackbacks/1' - assert_equal 'trackbacks#destroy', @response.body + get '/hello/notes' + assert_equal 'notes#index', @response.body - get '/hello/notes' - assert_equal 'notes#index', @response.body + post '/hello/notes' + assert_equal 'notes#create', @response.body - post '/hello/notes' - assert_equal 'notes#create', @response.body + get '/hello/notes/new' + assert_equal 'notes#new', @response.body + assert_equal '/hello/notes/new', new_note_path - get '/hello/notes/new' - assert_equal 'notes#new', @response.body - assert_equal '/hello/notes/new', new_note_path + get '/hello/notes/1' + assert_equal 'notes#show', @response.body + assert_equal '/hello/notes/1', note_path(:id => 1) - get '/hello/notes/1' - assert_equal 'notes#show', @response.body - assert_equal '/hello/notes/1', note_path(:id => 1) + put '/hello/notes/1' + assert_equal 'notes#update', @response.body - put '/hello/notes/1' - assert_equal 'notes#update', @response.body - - delete '/hello/notes/1' - assert_equal 'notes#destroy', @response.body - end + delete '/hello/notes/1' + assert_equal 'notes#destroy', @response.body end def test_custom_resource_routes_are_scoped - with_test_routes do - assert_equal '/customers/recent', recent_customers_path - assert_equal '/customers/1/profile', profile_customer_path(:id => '1') - assert_equal '/customers/1/secret/profile', secret_profile_customer_path(:id => '1') - assert_equal '/customers/new/preview', another_preview_new_customer_path - assert_equal '/customers/1/avatar/thumbnail.jpg', thumbnail_customer_avatar_path(:customer_id => '1', :format => :jpg) - assert_equal '/customers/1/invoices/outstanding', outstanding_customer_invoices_path(:customer_id => '1') - assert_equal '/customers/1/invoices/2/print', print_customer_invoice_path(:customer_id => '1', :id => '2') - assert_equal '/customers/1/invoices/new/preview', preview_new_customer_invoice_path(:customer_id => '1') - assert_equal '/customers/1/notes/new/preview', preview_new_customer_note_path(:customer_id => '1') - assert_equal '/notes/1/print', print_note_path(:id => '1') - assert_equal '/api/customers/recent', recent_api_customers_path - assert_equal '/api/customers/1/profile', profile_api_customer_path(:id => '1') - assert_equal '/api/customers/new/preview', preview_new_api_customer_path - - get '/customers/1/invoices/overdue' - assert_equal 'invoices#overdue', @response.body - - get '/customers/1/secret/profile' - assert_equal 'customers#secret', @response.body - end + assert_equal '/customers/recent', recent_customers_path + assert_equal '/customers/1/profile', profile_customer_path(:id => '1') + assert_equal '/customers/1/secret/profile', secret_profile_customer_path(:id => '1') + assert_equal '/customers/new/preview', another_preview_new_customer_path + assert_equal '/customers/1/avatar/thumbnail.jpg', thumbnail_customer_avatar_path(:customer_id => '1', :format => :jpg) + assert_equal '/customers/1/invoices/outstanding', outstanding_customer_invoices_path(:customer_id => '1') + assert_equal '/customers/1/invoices/2/print', print_customer_invoice_path(:customer_id => '1', :id => '2') + assert_equal '/customers/1/invoices/new/preview', preview_new_customer_invoice_path(:customer_id => '1') + assert_equal '/customers/1/notes/new/preview', preview_new_customer_note_path(:customer_id => '1') + assert_equal '/notes/1/print', print_note_path(:id => '1') + assert_equal '/api/customers/recent', recent_api_customers_path + assert_equal '/api/customers/1/profile', profile_api_customer_path(:id => '1') + assert_equal '/api/customers/new/preview', preview_new_api_customer_path + + get '/customers/1/invoices/overdue' + assert_equal 'invoices#overdue', @response.body + + get '/customers/1/secret/profile' + assert_equal 'customers#secret', @response.body end def test_shallow_nested_routes_ignore_module - with_test_routes do - get '/errors/1/notices' - assert_equal 'api/notices#index', @response.body - assert_equal '/errors/1/notices', error_notices_path(:error_id => '1') - - get '/notices/1' - assert_equal 'api/notices#show', @response.body - assert_equal '/notices/1', notice_path(:id => '1') - end + get '/errors/1/notices' + assert_equal 'api/notices#index', @response.body + assert_equal '/errors/1/notices', error_notices_path(:error_id => '1') + + get '/notices/1' + assert_equal 'api/notices#show', @response.body + assert_equal '/notices/1', notice_path(:id => '1') end def test_non_greedy_regexp - with_test_routes do - get '/api/1.0/users' - assert_equal 'api/users#index', @response.body - assert_equal '/api/1.0/users', api_users_path(:version => '1.0') - - get '/api/1.0/users.json' - assert_equal 'api/users#index', @response.body - assert_equal true, @request.format.json? - assert_equal '/api/1.0/users.json', api_users_path(:version => '1.0', :format => :json) - - get '/api/1.0/users/first.last' - assert_equal 'api/users#show', @response.body - assert_equal 'first.last', @request.params[:id] - assert_equal '/api/1.0/users/first.last', api_user_path(:version => '1.0', :id => 'first.last') - - get '/api/1.0/users/first.last.xml' - assert_equal 'api/users#show', @response.body - assert_equal 'first.last', @request.params[:id] - assert_equal true, @request.format.xml? - assert_equal '/api/1.0/users/first.last.xml', api_user_path(:version => '1.0', :id => 'first.last', :format => :xml) - end + get '/api/1.0/users' + assert_equal 'api/users#index', @response.body + assert_equal '/api/1.0/users', api_users_path(:version => '1.0') + + get '/api/1.0/users.json' + assert_equal 'api/users#index', @response.body + assert_equal true, @request.format.json? + assert_equal '/api/1.0/users.json', api_users_path(:version => '1.0', :format => :json) + + get '/api/1.0/users/first.last' + assert_equal 'api/users#show', @response.body + assert_equal 'first.last', @request.params[:id] + assert_equal '/api/1.0/users/first.last', api_user_path(:version => '1.0', :id => 'first.last') + + get '/api/1.0/users/first.last.xml' + assert_equal 'api/users#show', @response.body + assert_equal 'first.last', @request.params[:id] + assert_equal true, @request.format.xml? + assert_equal '/api/1.0/users/first.last.xml', api_user_path(:version => '1.0', :id => 'first.last', :format => :xml) end def test_glob_parameter_accepts_regexp - with_test_routes do - get '/en/path/to/existing/file.html' - assert_equal 200, @response.status - end + get '/en/path/to/existing/file.html' + assert_equal 200, @response.status end def test_resources_controller_name_is_not_pluralized - with_test_routes do - get '/content' - assert_equal 'content#index', @response.body - end + get '/content' + assert_equal 'content#index', @response.body end def test_url_generator_for_optional_prefix_dynamic_segment - with_test_routes do - get '/bob/followers' - assert_equal 'followers#index', @response.body - assert_equal 'http://www.example.com/bob/followers', - url_for(:controller => "followers", :action => "index", :username => "bob") - - get '/followers' - assert_equal 'followers#index', @response.body - assert_equal 'http://www.example.com/followers', - url_for(:controller => "followers", :action => "index", :username => nil) - end + get '/bob/followers' + assert_equal 'followers#index', @response.body + assert_equal 'http://www.example.com/bob/followers', + url_for(:controller => "followers", :action => "index", :username => "bob") + + get '/followers' + assert_equal 'followers#index', @response.body + assert_equal 'http://www.example.com/followers', + url_for(:controller => "followers", :action => "index", :username => nil) end def test_url_generator_for_optional_suffix_static_and_dynamic_segment - with_test_routes do - get '/groups/user/bob' - assert_equal 'groups#index', @response.body - assert_equal 'http://www.example.com/groups/user/bob', - url_for(:controller => "groups", :action => "index", :username => "bob") - - get '/groups' - assert_equal 'groups#index', @response.body - assert_equal 'http://www.example.com/groups', - url_for(:controller => "groups", :action => "index", :username => nil) - end + get '/groups/user/bob' + assert_equal 'groups#index', @response.body + assert_equal 'http://www.example.com/groups/user/bob', + url_for(:controller => "groups", :action => "index", :username => "bob") + + get '/groups' + assert_equal 'groups#index', @response.body + assert_equal 'http://www.example.com/groups', + url_for(:controller => "groups", :action => "index", :username => nil) end def test_url_generator_for_optional_prefix_static_and_dynamic_segment - with_test_routes do - get 'user/bob/photos' - assert_equal 'photos#index', @response.body - assert_equal 'http://www.example.com/user/bob/photos', - url_for(:controller => "photos", :action => "index", :username => "bob") - - get 'photos' - assert_equal 'photos#index', @response.body - assert_equal 'http://www.example.com/photos', - url_for(:controller => "photos", :action => "index", :username => nil) - end + get 'user/bob/photos' + assert_equal 'photos#index', @response.body + assert_equal 'http://www.example.com/user/bob/photos', + url_for(:controller => "photos", :action => "index", :username => "bob") + + get 'photos' + assert_equal 'photos#index', @response.body + assert_equal 'http://www.example.com/photos', + url_for(:controller => "photos", :action => "index", :username => nil) end def test_url_recognition_for_optional_static_segments - with_test_routes do - get '/groups/discussions/messages' - assert_equal 'messages#index', @response.body + get '/groups/discussions/messages' + assert_equal 'messages#index', @response.body - get '/groups/discussions/messages/1' - assert_equal 'messages#show', @response.body + get '/groups/discussions/messages/1' + assert_equal 'messages#show', @response.body - get '/groups/messages' - assert_equal 'messages#index', @response.body + get '/groups/messages' + assert_equal 'messages#index', @response.body - get '/groups/messages/1' - assert_equal 'messages#show', @response.body + get '/groups/messages/1' + assert_equal 'messages#show', @response.body - get '/discussions/messages' - assert_equal 'messages#index', @response.body + get '/discussions/messages' + assert_equal 'messages#index', @response.body - get '/discussions/messages/1' - assert_equal 'messages#show', @response.body + get '/discussions/messages/1' + assert_equal 'messages#show', @response.body - get '/messages' - assert_equal 'messages#index', @response.body + get '/messages' + assert_equal 'messages#index', @response.body - get '/messages/1' - assert_equal 'messages#show', @response.body - end + get '/messages/1' + assert_equal 'messages#show', @response.body end def test_router_removes_invalid_conditions - with_test_routes do - get '/tickets' - assert_equal 'tickets#index', @response.body - assert_equal '/tickets', tickets_path - end + get '/tickets' + assert_equal 'tickets#index', @response.body + assert_equal '/tickets', tickets_path end def test_constraints_are_merged_from_scope - with_test_routes do - get '/movies/0001' - assert_equal 'movies#show', @response.body - assert_equal '/movies/0001', movie_path(:id => '0001') - - get '/movies/00001' - assert_equal 'Not Found', @response.body - assert_raises(ActionController::RoutingError){ movie_path(:id => '00001') } - - get '/movies/0001/reviews' - assert_equal 'reviews#index', @response.body - assert_equal '/movies/0001/reviews', movie_reviews_path(:movie_id => '0001') - - get '/movies/00001/reviews' - assert_equal 'Not Found', @response.body - assert_raises(ActionController::RoutingError){ movie_reviews_path(:movie_id => '00001') } - - get '/movies/0001/reviews/0001' - assert_equal 'reviews#show', @response.body - assert_equal '/movies/0001/reviews/0001', movie_review_path(:movie_id => '0001', :id => '0001') - - get '/movies/00001/reviews/0001' - assert_equal 'Not Found', @response.body - assert_raises(ActionController::RoutingError){ movie_path(:movie_id => '00001', :id => '00001') } - - get '/movies/0001/trailer' - assert_equal 'trailers#show', @response.body - assert_equal '/movies/0001/trailer', movie_trailer_path(:movie_id => '0001') - - get '/movies/00001/trailer' - assert_equal 'Not Found', @response.body - assert_raises(ActionController::RoutingError){ movie_trailer_path(:movie_id => '00001') } - end + get '/movies/0001' + assert_equal 'movies#show', @response.body + assert_equal '/movies/0001', movie_path(:id => '0001') + + get '/movies/00001' + assert_equal 'Not Found', @response.body + assert_raises(ActionController::RoutingError){ movie_path(:id => '00001') } + + get '/movies/0001/reviews' + assert_equal 'reviews#index', @response.body + assert_equal '/movies/0001/reviews', movie_reviews_path(:movie_id => '0001') + + get '/movies/00001/reviews' + assert_equal 'Not Found', @response.body + assert_raises(ActionController::RoutingError){ movie_reviews_path(:movie_id => '00001') } + + get '/movies/0001/reviews/0001' + assert_equal 'reviews#show', @response.body + assert_equal '/movies/0001/reviews/0001', movie_review_path(:movie_id => '0001', :id => '0001') + + get '/movies/00001/reviews/0001' + assert_equal 'Not Found', @response.body + assert_raises(ActionController::RoutingError){ movie_path(:movie_id => '00001', :id => '00001') } + + get '/movies/0001/trailer' + assert_equal 'trailers#show', @response.body + assert_equal '/movies/0001/trailer', movie_trailer_path(:movie_id => '0001') + + get '/movies/00001/trailer' + assert_equal 'Not Found', @response.body + assert_raises(ActionController::RoutingError){ movie_trailer_path(:movie_id => '00001') } end def test_only_should_be_read_from_scope - with_test_routes do - get '/only/clubs' - assert_equal 'only/clubs#index', @response.body - assert_equal '/only/clubs', only_clubs_path - - get '/only/clubs/1/edit' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_only_club_path(:id => '1') } - - get '/only/clubs/1/players' - assert_equal 'only/players#index', @response.body - assert_equal '/only/clubs/1/players', only_club_players_path(:club_id => '1') - - get '/only/clubs/1/players/2/edit' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_only_club_player_path(:club_id => '1', :id => '2') } - - get '/only/clubs/1/chairman' - assert_equal 'only/chairmen#show', @response.body - assert_equal '/only/clubs/1/chairman', only_club_chairman_path(:club_id => '1') - - get '/only/clubs/1/chairman/edit' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_only_club_chairman_path(:club_id => '1') } - end + get '/only/clubs' + assert_equal 'only/clubs#index', @response.body + assert_equal '/only/clubs', only_clubs_path + + get '/only/clubs/1/edit' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { edit_only_club_path(:id => '1') } + + get '/only/clubs/1/players' + assert_equal 'only/players#index', @response.body + assert_equal '/only/clubs/1/players', only_club_players_path(:club_id => '1') + + get '/only/clubs/1/players/2/edit' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { edit_only_club_player_path(:club_id => '1', :id => '2') } + + get '/only/clubs/1/chairman' + assert_equal 'only/chairmen#show', @response.body + assert_equal '/only/clubs/1/chairman', only_club_chairman_path(:club_id => '1') + + get '/only/clubs/1/chairman/edit' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { edit_only_club_chairman_path(:club_id => '1') } end def test_except_should_be_read_from_scope - with_test_routes do - get '/except/clubs' - assert_equal 'except/clubs#index', @response.body - assert_equal '/except/clubs', except_clubs_path - - get '/except/clubs/1/edit' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_except_club_path(:id => '1') } - - get '/except/clubs/1/players' - assert_equal 'except/players#index', @response.body - assert_equal '/except/clubs/1/players', except_club_players_path(:club_id => '1') - - get '/except/clubs/1/players/2/edit' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_except_club_player_path(:club_id => '1', :id => '2') } - - get '/except/clubs/1/chairman' - assert_equal 'except/chairmen#show', @response.body - assert_equal '/except/clubs/1/chairman', except_club_chairman_path(:club_id => '1') - - get '/except/clubs/1/chairman/edit' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_except_club_chairman_path(:club_id => '1') } - end + get '/except/clubs' + assert_equal 'except/clubs#index', @response.body + assert_equal '/except/clubs', except_clubs_path + + get '/except/clubs/1/edit' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { edit_except_club_path(:id => '1') } + + get '/except/clubs/1/players' + assert_equal 'except/players#index', @response.body + assert_equal '/except/clubs/1/players', except_club_players_path(:club_id => '1') + + get '/except/clubs/1/players/2/edit' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { edit_except_club_player_path(:club_id => '1', :id => '2') } + + get '/except/clubs/1/chairman' + assert_equal 'except/chairmen#show', @response.body + assert_equal '/except/clubs/1/chairman', except_club_chairman_path(:club_id => '1') + + get '/except/clubs/1/chairman/edit' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { edit_except_club_chairman_path(:club_id => '1') } end def test_only_option_should_override_scope - with_test_routes do - get '/only/sectors' - assert_equal 'only/sectors#index', @response.body - assert_equal '/only/sectors', only_sectors_path - - get '/only/sectors/1' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { only_sector_path(:id => '1') } - end + get '/only/sectors' + assert_equal 'only/sectors#index', @response.body + assert_equal '/only/sectors', only_sectors_path + + get '/only/sectors/1' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { only_sector_path(:id => '1') } end def test_only_option_should_not_inherit - with_test_routes do - get '/only/sectors/1/companies/2' - assert_equal 'only/companies#show', @response.body - assert_equal '/only/sectors/1/companies/2', only_sector_company_path(:sector_id => '1', :id => '2') - - get '/only/sectors/1/leader' - assert_equal 'only/leaders#show', @response.body - assert_equal '/only/sectors/1/leader', only_sector_leader_path(:sector_id => '1') - end + get '/only/sectors/1/companies/2' + assert_equal 'only/companies#show', @response.body + assert_equal '/only/sectors/1/companies/2', only_sector_company_path(:sector_id => '1', :id => '2') + + get '/only/sectors/1/leader' + assert_equal 'only/leaders#show', @response.body + assert_equal '/only/sectors/1/leader', only_sector_leader_path(:sector_id => '1') end def test_except_option_should_override_scope - with_test_routes do - get '/except/sectors' - assert_equal 'except/sectors#index', @response.body - assert_equal '/except/sectors', except_sectors_path - - get '/except/sectors/1' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { except_sector_path(:id => '1') } - end + get '/except/sectors' + assert_equal 'except/sectors#index', @response.body + assert_equal '/except/sectors', except_sectors_path + + get '/except/sectors/1' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { except_sector_path(:id => '1') } end def test_except_option_should_not_inherit - with_test_routes do - get '/except/sectors/1/companies/2' - assert_equal 'except/companies#show', @response.body - assert_equal '/except/sectors/1/companies/2', except_sector_company_path(:sector_id => '1', :id => '2') - - get '/except/sectors/1/leader' - assert_equal 'except/leaders#show', @response.body - assert_equal '/except/sectors/1/leader', except_sector_leader_path(:sector_id => '1') - end + get '/except/sectors/1/companies/2' + assert_equal 'except/companies#show', @response.body + assert_equal '/except/sectors/1/companies/2', except_sector_company_path(:sector_id => '1', :id => '2') + + get '/except/sectors/1/leader' + assert_equal 'except/leaders#show', @response.body + assert_equal '/except/sectors/1/leader', except_sector_leader_path(:sector_id => '1') end def test_except_option_should_override_scoped_only - with_test_routes do - get '/only/sectors/1/managers' - assert_equal 'only/managers#index', @response.body - assert_equal '/only/sectors/1/managers', only_sector_managers_path(:sector_id => '1') - - get '/only/sectors/1/managers/2' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { only_sector_manager_path(:sector_id => '1', :id => '2') } - end + get '/only/sectors/1/managers' + assert_equal 'only/managers#index', @response.body + assert_equal '/only/sectors/1/managers', only_sector_managers_path(:sector_id => '1') + + get '/only/sectors/1/managers/2' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { only_sector_manager_path(:sector_id => '1', :id => '2') } end def test_only_option_should_override_scoped_except - with_test_routes do - get '/except/sectors/1/managers' - assert_equal 'except/managers#index', @response.body - assert_equal '/except/sectors/1/managers', except_sector_managers_path(:sector_id => '1') - - get '/except/sectors/1/managers/2' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { except_sector_manager_path(:sector_id => '1', :id => '2') } - end + get '/except/sectors/1/managers' + assert_equal 'except/managers#index', @response.body + assert_equal '/except/sectors/1/managers', except_sector_managers_path(:sector_id => '1') + + get '/except/sectors/1/managers/2' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { except_sector_manager_path(:sector_id => '1', :id => '2') } end def test_only_scope_should_override_parent_scope - with_test_routes do - get '/only/sectors/1/companies/2/divisions' - assert_equal 'only/divisions#index', @response.body - assert_equal '/only/sectors/1/companies/2/divisions', only_sector_company_divisions_path(:sector_id => '1', :company_id => '2') - - get '/only/sectors/1/companies/2/divisions/3' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { only_sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') } - end + get '/only/sectors/1/companies/2/divisions' + assert_equal 'only/divisions#index', @response.body + assert_equal '/only/sectors/1/companies/2/divisions', only_sector_company_divisions_path(:sector_id => '1', :company_id => '2') + + get '/only/sectors/1/companies/2/divisions/3' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { only_sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') } end def test_except_scope_should_override_parent_scope - with_test_routes do - get '/except/sectors/1/companies/2/divisions' - assert_equal 'except/divisions#index', @response.body - assert_equal '/except/sectors/1/companies/2/divisions', except_sector_company_divisions_path(:sector_id => '1', :company_id => '2') - - get '/except/sectors/1/companies/2/divisions/3' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { except_sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') } - end + get '/except/sectors/1/companies/2/divisions' + assert_equal 'except/divisions#index', @response.body + assert_equal '/except/sectors/1/companies/2/divisions', except_sector_company_divisions_path(:sector_id => '1', :company_id => '2') + + get '/except/sectors/1/companies/2/divisions/3' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { except_sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') } end def test_except_scope_should_override_parent_only_scope - with_test_routes do - get '/only/sectors/1/companies/2/departments' - assert_equal 'only/departments#index', @response.body - assert_equal '/only/sectors/1/companies/2/departments', only_sector_company_departments_path(:sector_id => '1', :company_id => '2') - - get '/only/sectors/1/companies/2/departments/3' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { only_sector_company_department_path(:sector_id => '1', :company_id => '2', :id => '3') } - end + get '/only/sectors/1/companies/2/departments' + assert_equal 'only/departments#index', @response.body + assert_equal '/only/sectors/1/companies/2/departments', only_sector_company_departments_path(:sector_id => '1', :company_id => '2') + + get '/only/sectors/1/companies/2/departments/3' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { only_sector_company_department_path(:sector_id => '1', :company_id => '2', :id => '3') } end def test_only_scope_should_override_parent_except_scope - with_test_routes do - get '/except/sectors/1/companies/2/departments' - assert_equal 'except/departments#index', @response.body - assert_equal '/except/sectors/1/companies/2/departments', except_sector_company_departments_path(:sector_id => '1', :company_id => '2') - - get '/except/sectors/1/companies/2/departments/3' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { except_sector_company_department_path(:sector_id => '1', :company_id => '2', :id => '3') } - end + get '/except/sectors/1/companies/2/departments' + assert_equal 'except/departments#index', @response.body + assert_equal '/except/sectors/1/companies/2/departments', except_sector_company_departments_path(:sector_id => '1', :company_id => '2') + + get '/except/sectors/1/companies/2/departments/3' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { except_sector_company_department_path(:sector_id => '1', :company_id => '2', :id => '3') } end def test_resources_are_not_pluralized - with_test_routes do - get '/transport/taxis' - assert_equal 'transport/taxis#index', @response.body - assert_equal '/transport/taxis', transport_taxis_path + get '/transport/taxis' + assert_equal 'transport/taxis#index', @response.body + assert_equal '/transport/taxis', transport_taxis_path - get '/transport/taxis/new' - assert_equal 'transport/taxis#new', @response.body - assert_equal '/transport/taxis/new', new_transport_taxi_path + get '/transport/taxis/new' + assert_equal 'transport/taxis#new', @response.body + assert_equal '/transport/taxis/new', new_transport_taxi_path - post '/transport/taxis' - assert_equal 'transport/taxis#create', @response.body + post '/transport/taxis' + assert_equal 'transport/taxis#create', @response.body - get '/transport/taxis/1' - assert_equal 'transport/taxis#show', @response.body - assert_equal '/transport/taxis/1', transport_taxi_path(:id => '1') + get '/transport/taxis/1' + assert_equal 'transport/taxis#show', @response.body + assert_equal '/transport/taxis/1', transport_taxi_path(:id => '1') - get '/transport/taxis/1/edit' - assert_equal 'transport/taxis#edit', @response.body - assert_equal '/transport/taxis/1/edit', edit_transport_taxi_path(:id => '1') + get '/transport/taxis/1/edit' + assert_equal 'transport/taxis#edit', @response.body + assert_equal '/transport/taxis/1/edit', edit_transport_taxi_path(:id => '1') - put '/transport/taxis/1' - assert_equal 'transport/taxis#update', @response.body + put '/transport/taxis/1' + assert_equal 'transport/taxis#update', @response.body - delete '/transport/taxis/1' - assert_equal 'transport/taxis#destroy', @response.body - end + delete '/transport/taxis/1' + assert_equal 'transport/taxis#destroy', @response.body end def test_singleton_resources_are_not_singularized - with_test_routes do - get '/medical/taxis/new' - assert_equal 'medical/taxes#new', @response.body - assert_equal '/medical/taxis/new', new_medical_taxis_path + get '/medical/taxis/new' + assert_equal 'medical/taxis#new', @response.body + assert_equal '/medical/taxis/new', new_medical_taxis_path - post '/medical/taxis' - assert_equal 'medical/taxes#create', @response.body + post '/medical/taxis' + assert_equal 'medical/taxis#create', @response.body - get '/medical/taxis' - assert_equal 'medical/taxes#show', @response.body - assert_equal '/medical/taxis', medical_taxis_path + get '/medical/taxis' + assert_equal 'medical/taxis#show', @response.body + assert_equal '/medical/taxis', medical_taxis_path - get '/medical/taxis/edit' - assert_equal 'medical/taxes#edit', @response.body - assert_equal '/medical/taxis/edit', edit_medical_taxis_path + get '/medical/taxis/edit' + assert_equal 'medical/taxis#edit', @response.body + assert_equal '/medical/taxis/edit', edit_medical_taxis_path - put '/medical/taxis' - assert_equal 'medical/taxes#update', @response.body + put '/medical/taxis' + assert_equal 'medical/taxis#update', @response.body - delete '/medical/taxis' - assert_equal 'medical/taxes#destroy', @response.body - end + delete '/medical/taxis' + assert_equal 'medical/taxis#destroy', @response.body end def test_greedy_resource_id_regexp_doesnt_match_edit_and_custom_action - with_test_routes do - get '/sections/1/edit' - assert_equal 'sections#edit', @response.body - assert_equal '/sections/1/edit', edit_section_path(:id => '1') - - get '/sections/1/preview' - assert_equal 'sections#preview', @response.body - assert_equal '/sections/1/preview', preview_section_path(:id => '1') - end + get '/sections/1/edit' + assert_equal 'sections#edit', @response.body + assert_equal '/sections/1/edit', edit_section_path(:id => '1') + + get '/sections/1/preview' + assert_equal 'sections#preview', @response.body + assert_equal '/sections/1/preview', preview_section_path(:id => '1') end def test_resource_constraints_are_pushed_to_scope - with_test_routes do - get '/wiki/articles/Ruby_on_Rails_3.0' - assert_equal 'wiki/articles#show', @response.body - assert_equal '/wiki/articles/Ruby_on_Rails_3.0', wiki_article_path(:id => 'Ruby_on_Rails_3.0') - - get '/wiki/articles/Ruby_on_Rails_3.0/comments/new' - assert_equal 'wiki/comments#new', @response.body - assert_equal '/wiki/articles/Ruby_on_Rails_3.0/comments/new', new_wiki_article_comment_path(:article_id => 'Ruby_on_Rails_3.0') - - post '/wiki/articles/Ruby_on_Rails_3.0/comments' - assert_equal 'wiki/comments#create', @response.body - assert_equal '/wiki/articles/Ruby_on_Rails_3.0/comments', wiki_article_comments_path(:article_id => 'Ruby_on_Rails_3.0') - end + get '/wiki/articles/Ruby_on_Rails_3.0' + assert_equal 'wiki/articles#show', @response.body + assert_equal '/wiki/articles/Ruby_on_Rails_3.0', wiki_article_path(:id => 'Ruby_on_Rails_3.0') + + get '/wiki/articles/Ruby_on_Rails_3.0/comments/new' + assert_equal 'wiki/comments#new', @response.body + assert_equal '/wiki/articles/Ruby_on_Rails_3.0/comments/new', new_wiki_article_comment_path(:article_id => 'Ruby_on_Rails_3.0') + + post '/wiki/articles/Ruby_on_Rails_3.0/comments' + assert_equal 'wiki/comments#create', @response.body + assert_equal '/wiki/articles/Ruby_on_Rails_3.0/comments', wiki_article_comments_path(:article_id => 'Ruby_on_Rails_3.0') end def test_resources_path_can_be_a_symbol - with_test_routes do - get '/pages' - assert_equal 'wiki_pages#index', @response.body - assert_equal '/pages', wiki_pages_path - - get '/pages/Ruby_on_Rails' - assert_equal 'wiki_pages#show', @response.body - assert_equal '/pages/Ruby_on_Rails', wiki_page_path(:id => 'Ruby_on_Rails') - - get '/my_account' - assert_equal 'wiki_accounts#show', @response.body - assert_equal '/my_account', wiki_account_path - end + get '/pages' + assert_equal 'wiki_pages#index', @response.body + assert_equal '/pages', wiki_pages_path + + get '/pages/Ruby_on_Rails' + assert_equal 'wiki_pages#show', @response.body + assert_equal '/pages/Ruby_on_Rails', wiki_page_path(:id => 'Ruby_on_Rails') + + get '/my_account' + assert_equal 'wiki_accounts#show', @response.body + assert_equal '/my_account', wiki_account_path end def test_redirect_https - with_test_routes do - with_https do - get '/secure' - verify_redirect 'https://www.example.com/secure/login' - end + with_https do + get '/secure' + verify_redirect 'https://www.example.com/secure/login' end end @@ -2390,10 +2176,6 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end private - def with_test_routes - yield - end - def with_https old_https = https? https! @@ -2448,6 +2230,32 @@ class TestAppendingRoutes < ActionDispatch::IntegrationTest end end +class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest + module ::Admin + class StorageFilesController < ActionController::Base + def index + render :text => "admin/storage_files#index" + end + end + end + + DefaultScopeRoutes = ActionDispatch::Routing::RouteSet.new + DefaultScopeRoutes.draw do + namespace :admin do + resources :storage_files, :controller => "StorageFiles" + end + end + + def app + DefaultScopeRoutes + end + + def test_controller_options + get '/admin/storage_files' + assert_equal "admin/storage_files#index", @response.body + end +end + class TestDefaultScope < ActionDispatch::IntegrationTest module ::Blog class PostsController < ActionController::Base @@ -2543,3 +2351,54 @@ class TestUriPathEscaping < ActionDispatch::IntegrationTest assert_equal 'a b/c+d', @response.body end end + +class TestUnicodePaths < ActionDispatch::IntegrationTest + Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| + app.draw do + match "/#{Rack::Utils.escape("ほげ")}" => lambda { |env| + [200, { 'Content-Type' => 'text/plain' }, []] + }, :as => :unicode_path + end + end + + include Routes.url_helpers + def app; Routes end + + test 'recognizes unicode path' do + get "/#{Rack::Utils.escape("ほげ")}" + assert_equal "200", @response.code + end +end + +class TestMultipleNestedController < ActionDispatch::IntegrationTest + module ::Foo + module Bar + class BazController < ActionController::Base + def index + render :inline => "<%= url_for :controller => '/pooh', :action => 'index' %>" + end + end + end + end + + Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| + app.draw do + namespace :foo do + namespace :bar do + match "baz" => "baz#index" + end + end + match "pooh" => "pooh#index" + end + end + + include Routes.url_helpers + def app; Routes end + + test "controller option which starts with '/' from multiple nested controller" do + get "/foo/bar/baz" + assert_equal "/pooh", @response.body + end + +end + diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 4a6d5ddbf7..45f8fc11b3 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -11,7 +11,7 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest when "/method_not_allowed" raise ActionController::MethodNotAllowed when "/not_found_original_exception" - raise ActionView::Template::Error.new('template', {}, AbstractController::ActionNotFound.new) + raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new) else raise "puke!" end diff --git a/actionpack/test/dispatch/static_test.rb b/actionpack/test/dispatch/static_test.rb index 9f3cbd19ef..b7a53353a9 100644 --- a/actionpack/test/dispatch/static_test.rb +++ b/actionpack/test/dispatch/static_test.rb @@ -1,3 +1,4 @@ +# encoding: utf-8 require 'abstract_unit' module StaticTests @@ -30,6 +31,10 @@ module StaticTests assert_html "/foo/index.html", get("/foo") end + def test_served_static_file_with_non_english_filename + assert_html "means hello in Japanese\n", get("/foo/#{Rack::Utils.escape("こんにちは.html")}") + end + private def assert_html(body, response) @@ -53,4 +58,4 @@ class StaticTest < ActiveSupport::TestCase end include StaticTests -end
\ No newline at end of file +end diff --git a/actionpack/test/fixtures/addresses/list.erb b/actionpack/test/fixtures/addresses/list.erb deleted file mode 100644 index c75e01eece..0000000000 --- a/actionpack/test/fixtures/addresses/list.erb +++ /dev/null @@ -1 +0,0 @@ -We only need to get this far! diff --git a/actionpack/test/fixtures/developers.yml b/actionpack/test/fixtures/developers.yml index 308bf75de2..3656564f63 100644 --- a/actionpack/test/fixtures/developers.yml +++ b/actionpack/test/fixtures/developers.yml @@ -8,7 +8,7 @@ jamis: name: Jamis salary: 150000 -<% for digit in 3..10 %> +<% (3..10).each do |digit| %> dev_<%= digit %>: id: <%= digit %> name: fixture_<%= digit %> diff --git a/actionpack/test/fixtures/public/foo/こんにちは.html b/actionpack/test/fixtures/public/foo/こんにちは.html new file mode 100644 index 0000000000..1df9166522 --- /dev/null +++ b/actionpack/test/fixtures/public/foo/こんにちは.html @@ -0,0 +1 @@ +means hello in Japanese diff --git a/actionpack/test/lib/controller/fake_controllers.rb b/actionpack/test/lib/controller/fake_controllers.rb index 09692f77b5..1a2863b689 100644 --- a/actionpack/test/lib/controller/fake_controllers.rb +++ b/actionpack/test/lib/controller/fake_controllers.rb @@ -1,11 +1,7 @@ -class << Object; alias_method :const_available?, :const_defined?; end - class ContentController < ActionController::Base; end module Admin - class << self; alias_method :const_available?, :const_defined?; end class AccountsController < ActionController::Base; end - class NewsFeedController < ActionController::Base; end class PostsController < ActionController::Base; end class StuffController < ActionController::Base; end class UserController < ActionController::Base; end @@ -17,46 +13,23 @@ module Api class ProductsController < ActionController::Base; end end -# TODO: Reduce the number of test controllers we use class AccountController < ActionController::Base; end -class AddressesController < ActionController::Base; end class ArchiveController < ActionController::Base; end class ArticlesController < ActionController::Base; end class BarController < ActionController::Base; end class BlogController < ActionController::Base; end class BooksController < ActionController::Base; end -class BraveController < ActionController::Base; end class CarsController < ActionController::Base; end class CcController < ActionController::Base; end class CController < ActionController::Base; end -class ElsewhereController < ActionController::Base; end class FooController < ActionController::Base; end class GeocodeController < ActionController::Base; end -class HiController < ActionController::Base; end -class ImageController < ActionController::Base; end class NewsController < ActionController::Base; end class NotesController < ActionController::Base; end +class PagesController < ActionController::Base; end class PeopleController < ActionController::Base; end class PostsController < ActionController::Base; end -class SessionsController < ActionController::Base; end -class StuffController < ActionController::Base; end class SubpathBooksController < ActionController::Base; end class SymbolsController < ActionController::Base; end class UserController < ActionController::Base; end -class WeblogController < ActionController::Base; end - -# For speed test -class SpeedController < ActionController::Base; end -class SearchController < SpeedController; end -class VideosController < SpeedController; end -class VideoFileController < SpeedController; end -class VideoSharesController < SpeedController; end -class VideoAbusesController < SpeedController; end -class VideoUploadsController < SpeedController; end -class VideoVisitsController < SpeedController; end -class UsersController < SpeedController; end -class SettingsController < SpeedController; end -class ChannelsController < SpeedController; end -class ChannelVideosController < SpeedController; end -class LostPasswordsController < SpeedController; end -class PagesController < SpeedController; end +class UsersController < ActionController::Base; end diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb index f2362714d7..bbb4cc5ef3 100644 --- a/actionpack/test/lib/controller/fake_models.rb +++ b/actionpack/test/lib/controller/fake_models.rb @@ -34,6 +34,16 @@ end class GoodCustomer < Customer end +class ValidatedCustomer < Customer + def errors + if name =~ /Sikachu/i + [] + else + [{:name => "is invalid"}] + end + end +end + module Quiz class Question < Struct.new(:name, :id) extend ActiveModel::Naming diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index aa7304b3ed..3d2eeea503 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -88,6 +88,18 @@ class AssetTagHelperTest < ActionView::TestCase %(path_to_javascript("/super/xmlhr.js")) => %(/super/xmlhr.js) } + JavascriptUrlToTag = { + %(javascript_url("xmlhr")) => %(http://www.example.com/javascripts/xmlhr.js), + %(javascript_url("super/xmlhr")) => %(http://www.example.com/javascripts/super/xmlhr.js), + %(javascript_url("/super/xmlhr.js")) => %(http://www.example.com/super/xmlhr.js) + } + + UrlToJavascriptToTag = { + %(url_to_javascript("xmlhr")) => %(http://www.example.com/javascripts/xmlhr.js), + %(url_to_javascript("super/xmlhr")) => %(http://www.example.com/javascripts/super/xmlhr.js), + %(url_to_javascript("/super/xmlhr.js")) => %(http://www.example.com/super/xmlhr.js) + } + JavascriptIncludeToTag = { %(javascript_include_tag("bank")) => %(<script src="/javascripts/bank.js" type="text/javascript"></script>), %(javascript_include_tag("bank.js")) => %(<script src="/javascripts/bank.js" type="text/javascript"></script>), @@ -119,6 +131,20 @@ class AssetTagHelperTest < ActionView::TestCase %(path_to_stylesheet('/dir/file.rcss')) => %(/dir/file.rcss) } + StyleUrlToTag = { + %(stylesheet_url("bank")) => %(http://www.example.com/stylesheets/bank.css), + %(stylesheet_url("bank.css")) => %(http://www.example.com/stylesheets/bank.css), + %(stylesheet_url('subdir/subdir')) => %(http://www.example.com/stylesheets/subdir/subdir.css), + %(stylesheet_url('/subdir/subdir.css')) => %(http://www.example.com/subdir/subdir.css) + } + + UrlToStyleToTag = { + %(url_to_stylesheet("style")) => %(http://www.example.com/stylesheets/style.css), + %(url_to_stylesheet("style.css")) => %(http://www.example.com/stylesheets/style.css), + %(url_to_stylesheet('dir/file')) => %(http://www.example.com/stylesheets/dir/file.css), + %(url_to_stylesheet('/dir/file.rcss')) => %(http://www.example.com/dir/file.rcss) + } + StyleLinkToTag = { %(stylesheet_link_tag("bank")) => %(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" type="text/css" />), %(stylesheet_link_tag("bank.css")) => %(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" type="text/css" />), @@ -149,6 +175,20 @@ class AssetTagHelperTest < ActionView::TestCase %(path_to_image("/dir/xml.png")) => %(/dir/xml.png) } + ImageUrlToTag = { + %(image_url("xml")) => %(http://www.example.com/images/xml), + %(image_url("xml.png")) => %(http://www.example.com/images/xml.png), + %(image_url("dir/xml.png")) => %(http://www.example.com/images/dir/xml.png), + %(image_url("/dir/xml.png")) => %(http://www.example.com/dir/xml.png) + } + + UrlToImageToTag = { + %(url_to_image("xml")) => %(http://www.example.com/images/xml), + %(url_to_image("xml.png")) => %(http://www.example.com/images/xml.png), + %(url_to_image("dir/xml.png")) => %(http://www.example.com/images/dir/xml.png), + %(url_to_image("/dir/xml.png")) => %(http://www.example.com/dir/xml.png) + } + ImageLinkToTag = { %(image_tag("xml.png")) => %(<img alt="Xml" src="/images/xml.png" />), %(image_tag("rss.gif", :alt => "rss syndication")) => %(<img alt="rss syndication" src="/images/rss.gif" />), @@ -168,7 +208,7 @@ class AssetTagHelperTest < ActionView::TestCase } FaviconLinkToTag = { - %(favicon_link_tag) => %(<link href="/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />), + %(favicon_link_tag) => %(<link href="/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />), %(favicon_link_tag 'favicon.ico') => %(<link href="/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />), %(favicon_link_tag 'favicon.ico', :rel => 'foo') => %(<link href="/images/favicon.ico" rel="foo" type="image/vnd.microsoft.icon" />), %(favicon_link_tag 'favicon.ico', :rel => 'foo', :type => 'bar') => %(<link href="/images/favicon.ico" rel="foo" type="bar" />), @@ -189,23 +229,38 @@ class AssetTagHelperTest < ActionView::TestCase %(path_to_video("/dir/xml.ogg")) => %(/dir/xml.ogg) } + VideoUrlToTag = { + %(video_url("xml")) => %(http://www.example.com/videos/xml), + %(video_url("xml.ogg")) => %(http://www.example.com/videos/xml.ogg), + %(video_url("dir/xml.ogg")) => %(http://www.example.com/videos/dir/xml.ogg), + %(video_url("/dir/xml.ogg")) => %(http://www.example.com/dir/xml.ogg) + } + + UrlToVideoToTag = { + %(url_to_video("xml")) => %(http://www.example.com/videos/xml), + %(url_to_video("xml.ogg")) => %(http://www.example.com/videos/xml.ogg), + %(url_to_video("dir/xml.ogg")) => %(http://www.example.com/videos/dir/xml.ogg), + %(url_to_video("/dir/xml.ogg")) => %(http://www.example.com/dir/xml.ogg) + } + VideoLinkToTag = { - %(video_tag("xml.ogg")) => %(<video src="/videos/xml.ogg" />), - %(video_tag("rss.m4v", :autoplay => true, :controls => true)) => %(<video autoplay="autoplay" controls="controls" src="/videos/rss.m4v" />), - %(video_tag("rss.m4v", :autobuffer => true)) => %(<video autobuffer="autobuffer" src="/videos/rss.m4v" />), - %(video_tag("gold.m4v", :size => "160x120")) => %(<video height="120" src="/videos/gold.m4v" width="160" />), - %(video_tag("gold.m4v", "size" => "320x240")) => %(<video height="240" src="/videos/gold.m4v" width="320" />), - %(video_tag("trailer.ogg", :poster => "screenshot.png")) => %(<video poster="/images/screenshot.png" src="/videos/trailer.ogg" />), - %(video_tag("error.avi", "size" => "100")) => %(<video src="/videos/error.avi" />), - %(video_tag("error.avi", "size" => "100 x 100")) => %(<video src="/videos/error.avi" />), - %(video_tag("error.avi", "size" => "x")) => %(<video src="/videos/error.avi" />), - %(video_tag("http://media.rubyonrails.org/video/rails_blog_2.mov")) => %(<video src="http://media.rubyonrails.org/video/rails_blog_2.mov" />), - %(video_tag("//media.rubyonrails.org/video/rails_blog_2.mov")) => %(<video src="//media.rubyonrails.org/video/rails_blog_2.mov" />), - %(video_tag(["multiple.ogg", "multiple.avi"])) => %(<video><source src="multiple.ogg" /><source src="multiple.avi" /></video>), - %(video_tag(["multiple.ogg", "multiple.avi"], :size => "160x120", :controls => true)) => %(<video controls="controls" height="120" width="160"><source src="multiple.ogg" /><source src="multiple.avi" /></video>) + %(video_tag("xml.ogg")) => %(<video src="/videos/xml.ogg"></video>), + %(video_tag("rss.m4v", :autoplay => true, :controls => true)) => %(<video autoplay="autoplay" controls="controls" src="/videos/rss.m4v"></video>), + %(video_tag("rss.m4v", :autobuffer => true)) => %(<video autobuffer="autobuffer" src="/videos/rss.m4v"></video>), + %(video_tag("gold.m4v", :size => "160x120")) => %(<video height="120" src="/videos/gold.m4v" width="160"></video>), + %(video_tag("gold.m4v", "size" => "320x240")) => %(<video height="240" src="/videos/gold.m4v" width="320"></video>), + %(video_tag("trailer.ogg", :poster => "screenshot.png")) => %(<video poster="/images/screenshot.png" src="/videos/trailer.ogg"></video>), + %(video_tag("error.avi", "size" => "100")) => %(<video src="/videos/error.avi"></video>), + %(video_tag("error.avi", "size" => "100 x 100")) => %(<video src="/videos/error.avi"></video>), + %(video_tag("error.avi", "size" => "x")) => %(<video src="/videos/error.avi"></video>), + %(video_tag("http://media.rubyonrails.org/video/rails_blog_2.mov")) => %(<video src="http://media.rubyonrails.org/video/rails_blog_2.mov"></video>), + %(video_tag("//media.rubyonrails.org/video/rails_blog_2.mov")) => %(<video src="//media.rubyonrails.org/video/rails_blog_2.mov"></video>), + %(video_tag("multiple.ogg", "multiple.avi")) => %(<video><source src="/videos/multiple.ogg" /><source src="/videos/multiple.avi" /></video>), + %(video_tag(["multiple.ogg", "multiple.avi"])) => %(<video><source src="/videos/multiple.ogg" /><source src="/videos/multiple.avi" /></video>), + %(video_tag(["multiple.ogg", "multiple.avi"], :size => "160x120", :controls => true)) => %(<video controls="controls" height="120" width="160"><source src="/videos/multiple.ogg" /><source src="/videos/multiple.avi" /></video>) } - AudioPathToTag = { + AudioPathToTag = { %(audio_path("xml")) => %(/audios/xml), %(audio_path("xml.wav")) => %(/audios/xml.wav), %(audio_path("dir/xml.wav")) => %(/audios/dir/xml.wav), @@ -219,11 +274,28 @@ class AssetTagHelperTest < ActionView::TestCase %(path_to_audio("/dir/xml.wav")) => %(/dir/xml.wav) } + AudioUrlToTag = { + %(audio_url("xml")) => %(http://www.example.com/audios/xml), + %(audio_url("xml.wav")) => %(http://www.example.com/audios/xml.wav), + %(audio_url("dir/xml.wav")) => %(http://www.example.com/audios/dir/xml.wav), + %(audio_url("/dir/xml.wav")) => %(http://www.example.com/dir/xml.wav) + } + + UrlToAudioToTag = { + %(url_to_audio("xml")) => %(http://www.example.com/audios/xml), + %(url_to_audio("xml.wav")) => %(http://www.example.com/audios/xml.wav), + %(url_to_audio("dir/xml.wav")) => %(http://www.example.com/audios/dir/xml.wav), + %(url_to_audio("/dir/xml.wav")) => %(http://www.example.com/dir/xml.wav) + } + AudioLinkToTag = { - %(audio_tag("xml.wav")) => %(<audio src="/audios/xml.wav" />), - %(audio_tag("rss.wav", :autoplay => true, :controls => true)) => %(<audio autoplay="autoplay" controls="controls" src="/audios/rss.wav" />), - %(audio_tag("http://media.rubyonrails.org/audio/rails_blog_2.mov")) => %(<audio src="http://media.rubyonrails.org/audio/rails_blog_2.mov" />), - %(audio_tag("//media.rubyonrails.org/audio/rails_blog_2.mov")) => %(<audio src="//media.rubyonrails.org/audio/rails_blog_2.mov" />), + %(audio_tag("xml.wav")) => %(<audio src="/audios/xml.wav"></audio>), + %(audio_tag("rss.wav", :autoplay => true, :controls => true)) => %(<audio autoplay="autoplay" controls="controls" src="/audios/rss.wav"></audio>), + %(audio_tag("http://media.rubyonrails.org/audio/rails_blog_2.mov")) => %(<audio src="http://media.rubyonrails.org/audio/rails_blog_2.mov"></audio>), + %(audio_tag("//media.rubyonrails.org/audio/rails_blog_2.mov")) => %(<audio src="//media.rubyonrails.org/audio/rails_blog_2.mov"></audio>), + %(audio_tag("audio.mp3", "audio.ogg")) => %(<audio><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>), + %(audio_tag(["audio.mp3", "audio.ogg"])) => %(<audio><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>), + %(audio_tag(["audio.mp3", "audio.ogg"], :autobuffer => true, :controls => true)) => %(<audio autobuffer="autobuffer" controls="controls"><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>) } def test_auto_discovery_link_tag @@ -238,6 +310,14 @@ class AssetTagHelperTest < ActionView::TestCase PathToJavascriptToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end + def test_javascript_url + JavascriptUrlToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_url_to_javascript_alias_for_javascript_url + UrlToJavascriptToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + def test_javascript_include_tag_with_blank_asset_id ENV["RAILS_ASSET_ID"] = "" JavascriptIncludeToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } @@ -345,6 +425,15 @@ class AssetTagHelperTest < ActionView::TestCase PathToStyleToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end + def test_stylesheet_url + ENV["RAILS_ASSET_ID"] = "" + StyleUrlToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_url_to_stylesheet_alias_for_stylesheet_url + UrlToStyleToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + def test_stylesheet_link_tag ENV["RAILS_ASSET_ID"] = "" StyleLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } @@ -429,6 +518,14 @@ class AssetTagHelperTest < ActionView::TestCase PathToImageToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end + def test_image_url + ImageUrlToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_url_to_image_alias_for_image_url + UrlToImageToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + def test_image_alt [nil, '/', '/foo/bar/', 'foo/bar/'].each do |prefix| assert_equal 'Rails', image_alt("#{prefix}rails.png") @@ -441,6 +538,12 @@ class AssetTagHelperTest < ActionView::TestCase ImageLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end + def test_image_tag_does_not_modify_options + options = {:size => '16x10'} + image_tag('icon', options) + assert_equal({:size => '16x10'}, options) + end + def test_favicon_link_tag FaviconLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end @@ -468,6 +571,14 @@ class AssetTagHelperTest < ActionView::TestCase PathToVideoToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end + def test_video_url + VideoUrlToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_url_to_video_alias_for_video_url + UrlToVideoToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + def test_video_tag VideoLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end @@ -480,10 +591,26 @@ class AssetTagHelperTest < ActionView::TestCase PathToAudioToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end + def test_audio_url + AudioUrlToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_url_to_audio_alias_for_audio_url + UrlToAudioToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + def test_audio_tag AudioLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end + def test_video_audio_tag_does_not_modify_options + options = {:autoplay => true} + video_tag('video', options) + assert_equal({:autoplay => true}, options) + audio_tag('audio', options) + assert_equal({:autoplay => true}, options) + end + def test_timebased_asset_id expected_time = File.mtime(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).to_i.to_s assert_equal %(<img alt="Rails" src="/images/rails.png?#{expected_time}" />), image_tag("rails.png") @@ -555,7 +682,6 @@ class AssetTagHelperTest < ActionView::TestCase end end - @controller.request.stubs(:ssl?).returns(false) assert_equal "http://assets15.example.com/images/xml.png", image_path("xml.png") @@ -1123,6 +1249,22 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase assert_dom_equal(%(<img alt="Mouse2" onmouseover="this.src='gopher://assets.example.com/collaboration/hieraki/images/mouse_over2.png'" onmouseout="this.src='gopher://assets.example.com/collaboration/hieraki/images/mouse2.png'" src="gopher://assets.example.com/collaboration/hieraki/images/mouse2.png" />), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png"))) end + def test_should_compute_proper_url_with_asset_host + @controller.config.asset_host = "assets.example.com" + assert_dom_equal(%(<link href="http://www.example.com/collaboration/hieraki" rel="alternate" title="RSS" type="application/rss+xml" />), auto_discovery_link_tag) + assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_url("xmlhr")) + assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/stylesheets/style.css), stylesheet_url("style")) + assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/images/xml.png), image_url("xml.png")) + end + + def test_should_compute_proper_url_with_asset_host_and_default_protocol + @controller.config.asset_host = "assets.example.com" + @controller.config.default_asset_host_protocol = :request + assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_url("xmlhr")) + assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/stylesheets/style.css), stylesheet_url("style")) + assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/images/xml.png), image_url("xml.png")) + end + def test_should_ignore_asset_host_on_complete_url @controller.config.asset_host = "http://assets.example.com" assert_dom_equal(%(<link href="http://bar.example.com/stylesheets/style.css" media="screen" rel="stylesheet" type="text/css" />), stylesheet_link_tag("http://bar.example.com/stylesheets/style.css")) @@ -1136,16 +1278,19 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase def test_should_wildcard_asset_host_between_zero_and_four @controller.config.asset_host = 'http://a%d.example.com' assert_match(%r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_path('xml.png')) + assert_match(%r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_url('xml.png')) end def test_asset_host_without_protocol_should_be_protocol_relative @controller.config.asset_host = 'a.example.com' assert_equal 'gopher://a.example.com/collaboration/hieraki/images/xml.png', image_path('xml.png') + assert_equal 'gopher://a.example.com/collaboration/hieraki/images/xml.png', image_url('xml.png') end def test_asset_host_without_protocol_should_be_protocol_relative_even_if_path_present @controller.config.asset_host = 'a.example.com/files/go/here' assert_equal 'gopher://a.example.com/files/go/here/collaboration/hieraki/images/xml.png', image_path('xml.png') + assert_equal 'gopher://a.example.com/files/go/here/collaboration/hieraki/images/xml.png', image_url('xml.png') end def test_assert_css_and_js_of_the_same_name_return_correct_extension diff --git a/actionpack/test/template/date_helper_i18n_test.rb b/actionpack/test/template/date_helper_i18n_test.rb index e3d3d5ff77..82b62e64f3 100644 --- a/actionpack/test/template/date_helper_i18n_test.rb +++ b/actionpack/test/template/date_helper_i18n_test.rb @@ -103,7 +103,7 @@ class DateHelperSelectTagsI18nTests < ActiveSupport::TestCase I18n.expects(:translate).with(('datetime.prompts.' + key.to_s).to_sym, :locale => 'en').returns prompt end - I18n.expects(:translate).with(:'date.order', :locale => 'en').returns [:year, :month, :day] + I18n.expects(:translate).with(:'date.order', :locale => 'en', :default => []).returns [:year, :month, :day] datetime_select('post', 'updated_at', :locale => 'en', :include_seconds => true, :prompt => true) end @@ -115,7 +115,15 @@ class DateHelperSelectTagsI18nTests < ActiveSupport::TestCase end def test_date_or_time_select_given_no_order_options_translates_order - I18n.expects(:translate).with(:'date.order', :locale => 'en').returns [:year, :month, :day] + I18n.expects(:translate).with(:'date.order', :locale => 'en', :default => []).returns [:year, :month, :day] datetime_select('post', 'updated_at', :locale => 'en') end + + def test_date_or_time_select_given_invalid_order + I18n.expects(:translate).with(:'date.order', :locale => 'en', :default => []).returns [:invalid, :month, :day] + + assert_raise StandardError do + datetime_select('post', 'updated_at', :locale => 'en') + end + end end diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb index fadfb59572..9e2f4ec347 100644 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionpack/test/template/date_helper_test.rb @@ -1587,7 +1587,7 @@ class DateHelperTest < ActionView::TestCase start_year = Time.now.year-5 end_year = Time.now.year+5 - expected = '<input name="post[written_on(3i)]" type="hidden" id="post_written_on_3i"/>' + "\n" + expected = '<input name="post[written_on(3i)]" type="hidden" id="post_written_on_3i" value="1"/>' + "\n" expected << %{<select id="post_written_on_1i" name="post[written_on(1i)]">\n} expected << "<option value=\"\"></option>\n" start_year.upto(end_year) { |i| expected << %(<option value="#{i}">#{i}</option>\n) } @@ -1601,6 +1601,40 @@ class DateHelperTest < ActionView::TestCase assert_dom_equal expected, date_select("post", "written_on", :order=>[:year, :month], :include_blank=>true) end + def test_date_select_with_nil_and_blank_and_discard_month + @post = Post.new + + start_year = Time.now.year-5 + end_year = Time.now.year+5 + + expected = %{<select id="post_written_on_1i" name="post[written_on(1i)]">\n} + expected << "<option value=\"\"></option>\n" + start_year.upto(end_year) { |i| expected << %(<option value="#{i}">#{i}</option>\n) } + expected << "</select>\n" + expected << '<input name="post[written_on(2i)]" type="hidden" id="post_written_on_2i" value="1"/>' + "\n" + expected << '<input name="post[written_on(3i)]" type="hidden" id="post_written_on_3i" value="1"/>' + "\n" + + assert_dom_equal expected, date_select("post", "written_on", :discard_month => true, :include_blank=>true) + end + + def test_date_select_with_nil_and_blank_and_discard_year + @post = Post.new + + expected = '<input id="post_written_on_1i" name="post[written_on(1i)]" type="hidden" value="1" />' + "\n" + + expected << %{<select id="post_written_on_2i" name="post[written_on(2i)]">\n} + expected << "<option value=\"\"></option>\n" + 1.upto(12) { |i| expected << %(<option value="#{i}">#{Date::MONTHNAMES[i]}</option>\n) } + expected << "</select>\n" + + expected << %{<select id="post_written_on_3i" name="post[written_on(3i)]">\n} + expected << "<option value=\"\"></option>\n" + 1.upto(31) { |i| expected << %(<option value="#{i}">#{i}</option>\n) } + expected << "</select>\n" + + assert_dom_equal expected, date_select("post", "written_on", :discard_year => true, :include_blank=>true) + end + def test_date_select_cant_override_discard_hour @post = Post.new @post.written_on = Date.new(2004, 6, 15) diff --git a/actionpack/test/template/erb_util_test.rb b/actionpack/test/template/erb_util_test.rb index eba2ef64e0..ca2710e9b3 100644 --- a/actionpack/test/template/erb_util_test.rb +++ b/actionpack/test/template/erb_util_test.rb @@ -44,4 +44,18 @@ class ErbUtilTest < ActiveSupport::TestCase assert_equal chr, html_escape(chr) end end + + def test_html_escape_once + assert_equal '1 < 2 & 3', html_escape_once('1 < 2 & 3') + end + + def test_html_escape_once_returns_unsafe_strings_when_passed_unsafe_strings + value = html_escape_once('1 < 2 & 3') + assert !value.html_safe? + end + + def test_html_escape_once_returns_safe_strings_when_passed_safe_strings + value = html_escape_once('1 < 2 & 3'.html_safe) + assert value.html_safe? + end end diff --git a/actionpack/test/template/form_collections_helper_test.rb b/actionpack/test/template/form_collections_helper_test.rb new file mode 100644 index 0000000000..a4aea8ca56 --- /dev/null +++ b/actionpack/test/template/form_collections_helper_test.rb @@ -0,0 +1,301 @@ +require 'abstract_unit' + +class Category < Struct.new(:id, :name) +end + +class FormCollectionsHelperTest < ActionView::TestCase + def assert_no_select(selector, value = nil) + assert_select(selector, :text => value, :count => 0) + end + + def with_collection_radio_buttons(*args, &block) + @output_buffer = collection_radio_buttons(*args, &block) + end + + def with_collection_check_boxes(*args, &block) + @output_buffer = collection_check_boxes(*args, &block) + end + + # COLLECTION RADIO BUTTONS + test 'collection radio accepts a collection and generate inputs from value method' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s + + assert_select 'input[type=radio][value=true]#user_active_true' + assert_select 'input[type=radio][value=false]#user_active_false' + end + + test 'collection radio accepts a collection and generate inputs from label method' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s + + assert_select 'label[for=user_active_true]', 'true' + assert_select 'label[for=user_active_false]', 'false' + end + + test 'collection radio handles camelized collection values for labels correctly' do + with_collection_radio_buttons :user, :active, ['Yes', 'No'], :to_s, :to_s + + assert_select 'label[for=user_active_yes]', 'Yes' + assert_select 'label[for=user_active_no]', 'No' + end + + test 'colection radio should sanitize collection values for labels correctly' do + with_collection_radio_buttons :user, :name, ['$0.99', '$1.99'], :to_s, :to_s + assert_select 'label[for=user_name_099]', '$0.99' + assert_select 'label[for=user_name_199]', '$1.99' + end + + test 'collection radio accepts checked item' do + with_collection_radio_buttons :user, :active, [[1, true], [0, false]], :last, :first, :checked => true + + assert_select 'input[type=radio][value=true][checked=checked]' + assert_no_select 'input[type=radio][value=false][checked=checked]' + end + + test 'collection radio accepts multiple disabled items' do + collection = [[1, true], [0, false], [2, 'other']] + with_collection_radio_buttons :user, :active, collection, :last, :first, :disabled => [true, false] + + assert_select 'input[type=radio][value=true][disabled=disabled]' + assert_select 'input[type=radio][value=false][disabled=disabled]' + assert_no_select 'input[type=radio][value=other][disabled=disabled]' + end + + test 'collection radio accepts single disable item' do + collection = [[1, true], [0, false]] + with_collection_radio_buttons :user, :active, collection, :last, :first, :disabled => true + + assert_select 'input[type=radio][value=true][disabled=disabled]' + assert_no_select 'input[type=radio][value=false][disabled=disabled]' + end + + test 'collection radio accepts html options as input' do + collection = [[1, true], [0, false]] + with_collection_radio_buttons :user, :active, collection, :last, :first, {}, :class => 'special-radio' + + assert_select 'input[type=radio][value=true].special-radio#user_active_true' + assert_select 'input[type=radio][value=false].special-radio#user_active_false' + end + + test 'collection radio does not wrap input inside the label' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s + + assert_select 'input[type=radio] + label' + assert_no_select 'label input' + end + + test 'collection radio accepts a block to render the label as radio button wrapper' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| + b.label { b.radio_button } + end + + assert_select 'label[for=user_active_true] > input#user_active_true[type=radio]' + assert_select 'label[for=user_active_false] > input#user_active_false[type=radio]' + end + + test 'collection radio accepts a block to change the order of label and radio button' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| + b.label + b.radio_button + end + + assert_select 'label[for=user_active_true] + input#user_active_true[type=radio]' + assert_select 'label[for=user_active_false] + input#user_active_false[type=radio]' + end + + test 'collection radio with block helpers accept extra html options' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| + b.label(:class => "radio_button") + b.radio_button(:class => "radio_button") + end + + assert_select 'label.radio_button[for=user_active_true] + input#user_active_true.radio_button[type=radio]' + assert_select 'label.radio_button[for=user_active_false] + input#user_active_false.radio_button[type=radio]' + end + + test 'collection radio with block helpers allows access to current text and value' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| + b.label(:"data-value" => b.value) { b.radio_button + b.text } + end + + assert_select 'label[for=user_active_true][data-value=true]', 'true' do + assert_select 'input#user_active_true[type=radio]' + end + assert_select 'label[for=user_active_false][data-value=false]', 'false' do + assert_select 'input#user_active_false[type=radio]' + end + end + + test 'collection radio buttons with fields for' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + @output_buffer = fields_for(:post) do |p| + p.collection_radio_buttons :category_id, collection, :id, :name + end + + assert_select 'input#post_category_id_1[type=radio][value=1]' + assert_select 'input#post_category_id_2[type=radio][value=2]' + + assert_select 'label[for=post_category_id_1]', 'Category 1' + assert_select 'label[for=post_category_id_2]', 'Category 2' + end + + # COLLECTION CHECK BOXES + test 'collection check boxes accepts a collection and generate a serie of checkboxes for value method' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + with_collection_check_boxes :user, :category_ids, collection, :id, :name + + assert_select 'input#user_category_ids_1[type=checkbox][value=1]' + assert_select 'input#user_category_ids_2[type=checkbox][value=2]' + end + + test 'collection check boxes generates only one hidden field for the entire collection, to ensure something will be sent back to the server when posting an empty collection' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + with_collection_check_boxes :user, :category_ids, collection, :id, :name + + assert_select "input[type=hidden][name='user[category_ids][]'][value=]", :count => 1 + end + + test 'collection check boxes accepts a collection and generate a serie of checkboxes with labels for label method' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + with_collection_check_boxes :user, :category_ids, collection, :id, :name + + assert_select 'label[for=user_category_ids_1]', 'Category 1' + assert_select 'label[for=user_category_ids_2]', 'Category 2' + end + + test 'collection check boxes handles camelized collection values for labels correctly' do + with_collection_check_boxes :user, :active, ['Yes', 'No'], :to_s, :to_s + + assert_select 'label[for=user_active_yes]', 'Yes' + assert_select 'label[for=user_active_no]', 'No' + end + + test 'colection check box should sanitize collection values for labels correctly' do + with_collection_check_boxes :user, :name, ['$0.99', '$1.99'], :to_s, :to_s + assert_select 'label[for=user_name_099]', '$0.99' + assert_select 'label[for=user_name_199]', '$1.99' + end + + test 'collection check boxes accepts selected values as :checked option' do + collection = (1..3).map{|i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, :checked => [1, 3] + + assert_select 'input[type=checkbox][value=1][checked=checked]' + assert_select 'input[type=checkbox][value=3][checked=checked]' + assert_no_select 'input[type=checkbox][value=2][checked=checked]' + end + + test 'collection check boxes accepts a single checked value' do + collection = (1..3).map{|i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, :checked => 3 + + assert_select 'input[type=checkbox][value=3][checked=checked]' + assert_no_select 'input[type=checkbox][value=1][checked=checked]' + assert_no_select 'input[type=checkbox][value=2][checked=checked]' + end + + test 'collection check boxes accepts selected values as :checked option and override the model values' do + user = Struct.new(:category_ids).new(2) + collection = (1..3).map{|i| [i, "Category #{i}"] } + + @output_buffer = fields_for(:user, user) do |p| + p.collection_check_boxes :category_ids, collection, :first, :last, :checked => [1, 3] + end + + assert_select 'input[type=checkbox][value=1][checked=checked]' + assert_select 'input[type=checkbox][value=3][checked=checked]' + assert_no_select 'input[type=checkbox][value=2][checked=checked]' + end + + test 'collection check boxes accepts multiple disabled items' do + collection = (1..3).map{|i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, :disabled => [1, 3] + + assert_select 'input[type=checkbox][value=1][disabled=disabled]' + assert_select 'input[type=checkbox][value=3][disabled=disabled]' + assert_no_select 'input[type=checkbox][value=2][disabled=disabled]' + end + + test 'collection check boxes accepts single disable item' do + collection = (1..3).map{|i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, :disabled => 1 + + assert_select 'input[type=checkbox][value=1][disabled=disabled]' + assert_no_select 'input[type=checkbox][value=3][disabled=disabled]' + assert_no_select 'input[type=checkbox][value=2][disabled=disabled]' + end + + test 'collection check boxes accepts a proc to disabled items' do + collection = (1..3).map{|i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, :disabled => proc { |i| i.first == 1 } + + assert_select 'input[type=checkbox][value=1][disabled=disabled]' + assert_no_select 'input[type=checkbox][value=3][disabled=disabled]' + assert_no_select 'input[type=checkbox][value=2][disabled=disabled]' + end + + test 'collection check boxes accepts html options' do + collection = [[1, 'Category 1'], [2, 'Category 2']] + with_collection_check_boxes :user, :category_ids, collection, :first, :last, {}, :class => 'check' + + assert_select 'input.check[type=checkbox][value=1]' + assert_select 'input.check[type=checkbox][value=2]' + end + + test 'collection check boxes with fields for' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + @output_buffer = fields_for(:post) do |p| + p.collection_check_boxes :category_ids, collection, :id, :name + end + + assert_select 'input#post_category_ids_1[type=checkbox][value=1]' + assert_select 'input#post_category_ids_2[type=checkbox][value=2]' + + assert_select 'label[for=post_category_ids_1]', 'Category 1' + assert_select 'label[for=post_category_ids_2]', 'Category 2' + end + + test 'collection check boxes does not wrap input inside the label' do + with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s + + assert_select 'input[type=checkbox] + label' + assert_no_select 'label input' + end + + test 'collection check boxes accepts a block to render the label as check box wrapper' do + with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| + b.label { b.check_box } + end + + assert_select 'label[for=user_active_true] > input#user_active_true[type=checkbox]' + assert_select 'label[for=user_active_false] > input#user_active_false[type=checkbox]' + end + + test 'collection check boxes accepts a block to change the order of label and check box' do + with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| + b.label + b.check_box + end + + assert_select 'label[for=user_active_true] + input#user_active_true[type=checkbox]' + assert_select 'label[for=user_active_false] + input#user_active_false[type=checkbox]' + end + + test 'collection check boxes with block helpers accept extra html options' do + with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| + b.label(:class => "check_box") + b.check_box(:class => "check_box") + end + + assert_select 'label.check_box[for=user_active_true] + input#user_active_true.check_box[type=checkbox]' + assert_select 'label.check_box[for=user_active_false] + input#user_active_false.check_box[type=checkbox]' + end + + test 'collection check boxes with block helpers allows access to current text and value' do + with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| + b.label(:"data-value" => b.value) { b.check_box + b.text } + end + + assert_select 'label[for=user_active_true][data-value=true]', 'true' do + assert_select 'input#user_active_true[type=checkbox]' + end + assert_select 'label[for=user_active_false][data-value=false]', 'false' do + assert_select 'input#user_active_false[type=checkbox]' + end + end +end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 5be6a2e4e5..d072d3bce0 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -115,6 +115,14 @@ class FormHelperTest < ActionView::TestCase super end + class FooTag < ActionView::Helpers::Tags::Base + def initialize; end + end + + def test_tags_base_child_without_render_method + assert_raise(NotImplementedError) { FooTag.new.render } + end + def test_label assert_dom_equal('<label for="post_title">Title</label>', label("post", "title")) assert_dom_equal('<label for="post_title">The title goes here</label>', label("post", "title", "The title goes here")) @@ -207,6 +215,10 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal('<label for="my_for">Title</label>', label(:post, :title, nil, "for" => "my_for")) end + def test_label_does_not_generate_for_attribute_when_given_nil + assert_dom_equal('<label>Title</label>', label(:post, :title, :for => nil)) + end + def test_label_with_id_attribute_as_symbol assert_dom_equal('<label for="post_title" id="my_id">Title</label>', label(:post, :title, nil, :id => "my_id")) end @@ -386,6 +398,10 @@ class FormHelperTest < ActionView::TestCase ) end + def test_check_box_with_nil_unchecked_value_is_html_safe + assert check_box("post", "secret", {}, "on", nil).html_safe? + end + def test_check_box_with_multiple_behavior @post.comment_ids = [2,3] assert_dom_equal( @@ -405,6 +421,13 @@ class FormHelperTest < ActionView::TestCase ) end + def test_checkbox_form_html5_attribute + assert_dom_equal( + '<input form="new_form" name="post[secret]" type="hidden" value="0" /><input checked="checked" form="new_form" id="post_secret" name="post[secret]" type="checkbox" value="1" />', + check_box("post", "secret", :form => "new_form") + ) + end + def test_radio_button assert_dom_equal('<input checked="checked" id="post_title_hello_world" name="post[title]" type="radio" value="Hello World" />', radio_button("post", "title", "Hello World") @@ -491,6 +514,32 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal(expected, telephone_field("user", "cell")) end + def test_date_field + expected = %{<input id="post_written_on" name="post[written_on]" type="date" value="2004-06-15" />} + assert_dom_equal(expected, date_field("post", "written_on")) + end + + def test_date_field_with_datetime_value + expected = %{<input id="post_written_on" name="post[written_on]" type="date" value="2004-06-15" />} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + assert_dom_equal(expected, date_field("post", "written_on")) + end + + def test_date_field_with_timewithzone_value + previous_time_zone, Time.zone = Time.zone, 'UTC' + expected = %{<input id="post_written_on" name="post[written_on]" type="date" value="2004-06-15" />} + @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + assert_dom_equal(expected, date_field("post", "written_on")) + ensure + Time.zone = previous_time_zone + end + + def test_date_field_with_nil_value + expected = %{<input id="post_written_on" name="post[written_on]" type="date" />} + @post.written_on = nil + assert_dom_equal(expected, date_field("post", "written_on")) + end + def test_url_field expected = %{<input id="user_homepage" size="30" name="user[homepage]" type="url" />} assert_dom_equal(expected, url_field("user", "homepage")) @@ -2152,8 +2201,8 @@ class FormHelperTest < ActionView::TestCase end protected - def protect_against_forgery? - false - end + def protect_against_forgery? + false + end end diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb index 4a889beadd..a32525c485 100644 --- a/actionpack/test/template/form_options_helper_test.rb +++ b/actionpack/test/template/form_options_helper_test.rb @@ -87,6 +87,20 @@ class FormOptionsHelperTest < ActionView::TestCase ) end + def test_collection_options_with_proc_for_value_method + assert_dom_equal( + "<option value=\"<Abe>\"><Abe> went home</option>\n<option value=\"Babe\">Babe went home</option>\n<option value=\"Cabe\">Cabe went home</option>", + options_from_collection_for_select(dummy_posts, lambda { |p| p.author_name }, "title") + ) + end + + def test_collection_options_with_proc_for_text_method + assert_dom_equal( + "<option value=\"<Abe>\"><Abe> went home</option>\n<option value=\"Babe\">Babe went home</option>\n<option value=\"Cabe\">Cabe went home</option>", + options_from_collection_for_select(dummy_posts, "author_name", lambda { |p| p.title }) + ) + end + def test_string_options_for_select options = "<option value=\"Denmark\">Denmark</option><option value=\"USA\">USA</option><option value=\"Sweden\">Sweden</option>" assert_dom_equal( @@ -144,6 +158,13 @@ class FormOptionsHelperTest < ActionView::TestCase ) end + def test_range_options_for_select + assert_dom_equal( + "<option value=\"1\">1</option>\n<option value=\"2\">2</option>\n<option value=\"3\">3</option>", + options_for_select(1..3) + ) + end + def test_array_options_for_string_include_in_other_string_bug_fix assert_dom_equal( "<option value=\"ruby\">ruby</option>\n<option value=\"rubyonrails\" selected=\"selected\">rubyonrails</option>", @@ -671,6 +692,15 @@ class FormOptionsHelperTest < ActionView::TestCase ) end + def test_select_with_range + @post = Post.new + @post.category = 0 + assert_dom_equal( + "<select id=\"post_category\" name=\"post[category]\"><option value=\"1\">1</option>\n<option value=\"2\">2</option>\n<option value=\"3\">3</option></select>", + select("post", "category", 1..3) + ) + end + def test_collection_select @post = Post.new @post.author_name = "Babe" @@ -774,7 +804,25 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( "<select id=\"post_author_name\" name=\"post[author_name]\"><option value=\"<Abe>\"><Abe></option>\n<option value=\"Babe\" selected=\"selected\">Babe</option>\n<option value=\"Cabe\" disabled=\"disabled\">Cabe</option></select>", collection_select("post", "author_name", dummy_posts, "author_name", "author_name", :disabled => 'Cabe') - ) + ) + end + + def test_collection_select_with_proc_for_value_method + @post = Post.new + + assert_dom_equal( + "<select id=\"post_author_name\" name=\"post[author_name]\"><option value=\"<Abe>\"><Abe> went home</option>\n<option value=\"Babe\">Babe went home</option>\n<option value=\"Cabe\">Cabe went home</option></select>", + collection_select("post", "author_name", dummy_posts, lambda { |p| p.author_name }, "title") + ) + end + + def test_collection_select_with_proc_for_text_method + @post = Post.new + + assert_dom_equal( + "<select id=\"post_author_name\" name=\"post[author_name]\"><option value=\"<Abe>\"><Abe> went home</option>\n<option value=\"Babe\">Babe went home</option>\n<option value=\"Cabe\">Cabe went home</option></select>", + collection_select("post", "author_name", dummy_posts, "author_name", lambda { |p| p.title }) + ) end def test_time_zone_select @@ -1068,14 +1116,14 @@ class FormOptionsHelperTest < ActionView::TestCase private - def dummy_posts - [ Post.new("<Abe> went home", "<Abe>", "To a little house", "shh!"), - Post.new("Babe went home", "Babe", "To a little house", "shh!"), - Post.new("Cabe went home", "Cabe", "To a little house", "shh!") ] - end + def dummy_posts + [ Post.new("<Abe> went home", "<Abe>", "To a little house", "shh!"), + Post.new("Babe went home", "Babe", "To a little house", "shh!"), + Post.new("Cabe went home", "Cabe", "To a little house", "shh!") ] + end - def dummy_continents - [ Continent.new("<Africa>", [Country.new("<sa>", "<South Africa>"), Country.new("so", "Somalia")] ), - Continent.new("Europe", [Country.new("dk", "Denmark"), Country.new("ie", "Ireland")] ) ] - end + def dummy_continents + [ Continent.new("<Africa>", [Country.new("<sa>", "<South Africa>"), Country.new("so", "Somalia")]), + Continent.new("Europe", [Country.new("dk", "Denmark"), Country.new("ie", "Ireland")]) ] + end end diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index 2f2546aed2..809102e5c2 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -457,11 +457,16 @@ class FormTagHelperTest < ActionView::TestCase assert_dom_equal(expected, search_field_tag("query")) end - def telephone_field_tag + def test_telephone_field_tag expected = %{<input id="cell" name="cell" type="tel" />} assert_dom_equal(expected, telephone_field_tag("cell")) end + def test_date_field_tag + expected = %{<input id="cell" name="cell" type="date" />} + assert_dom_equal(expected, date_field_tag("cell")) + end + def test_url_field_tag expected = %{<input id="homepage" name="homepage" type="url" />} assert_dom_equal(expected, url_field_tag("homepage")) diff --git a/actionpack/test/template/html-scanner/sanitizer_test.rb b/actionpack/test/template/html-scanner/sanitizer_test.rb index b4d751e405..32c655c5fd 100644 --- a/actionpack/test/template/html-scanner/sanitizer_test.rb +++ b/actionpack/test/template/html-scanner/sanitizer_test.rb @@ -56,7 +56,6 @@ class SanitizerTest < ActionController::TestCase assert_sanitized "a b c<script language=\"Javascript\">blah blah blah</script>d e f", "a b cd e f" end - # TODO: Clean up def test_sanitize_js_handlers raw = %{onthis="do that" <a href="#" onclick="hello" name="foo" onbogus="remove me">hello</a>} assert_sanitized raw, %{onthis="do that" <a name="foo" href="#">hello</a>} @@ -215,7 +214,6 @@ class SanitizerTest < ActionController::TestCase assert_sanitized img_hack, "<img>" end - # TODO: Clean up def test_should_sanitize_attributes assert_sanitized %(<SPAN title="'><script>alert()</script>">blah</SPAN>), %(<span title="'><script>alert()</script>">blah</span>) end diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index d98ffe8fa7..9441bd6b38 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -1,5 +1,4 @@ require 'abstract_unit' -require 'active_support/core_ext/string/encoding' class JavaScriptHelperTest < ActionView::TestCase tests ActionView::Helpers::JavaScriptHelper diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb index 8d679aac1d..482d953907 100644 --- a/actionpack/test/template/number_helper_test.rb +++ b/actionpack/test/template/number_helper_test.rb @@ -57,6 +57,7 @@ class NumberHelperTest < ActionView::TestCase assert_equal("1000.000%", number_to_percentage("1000")) assert_equal("123.4%", number_to_percentage(123.400, :precision => 3, :strip_insignificant_zeros => true)) assert_equal("1.000,000%", number_to_percentage(1000, :delimiter => '.', :separator => ',')) + assert_equal("1000.000 %", number_to_percentage(1000, :format => "%n %")) end def test_number_with_delimiter @@ -267,6 +268,31 @@ class NumberHelperTest < ActionView::TestCase assert_nil number_to_human(nil) end + def test_number_helpers_do_not_mutate_options_hash + options = { 'raise' => true } + + number_to_phone(1, options) + assert_equal({ 'raise' => true }, options) + + number_to_currency(1, options) + assert_equal({ 'raise' => true }, options) + + number_to_percentage(1, options) + assert_equal({ 'raise' => true }, options) + + number_with_delimiter(1, options) + assert_equal({ 'raise' => true }, options) + + number_with_precision(1, options) + assert_equal({ 'raise' => true }, options) + + number_to_human_size(1, options) + assert_equal({ 'raise' => true }, options) + + number_to_human(1, options) + assert_equal({ 'raise' => true }, options) + end + def test_number_helpers_should_return_non_numeric_param_unchanged assert_equal("+1-x x 123", number_to_phone("x", :country_code => 1, :extension => 123)) assert_equal("x", number_to_phone("x")) diff --git a/actionpack/test/template/template_error_test.rb b/actionpack/test/template/template_error_test.rb index 3a874082d9..91424daeed 100644 --- a/actionpack/test/template/template_error_test.rb +++ b/actionpack/test/template/template_error_test.rb @@ -2,12 +2,12 @@ require "abstract_unit" class TemplateErrorTest < ActiveSupport::TestCase def test_provides_original_message - error = ActionView::Template::Error.new("test", {}, Exception.new("original")) + error = ActionView::Template::Error.new("test", Exception.new("original")) assert_equal "original", error.message end def test_provides_useful_inspect - error = ActionView::Template::Error.new("test", {}, Exception.new("original")) + error = ActionView::Template::Error.new("test", Exception.new("original")) assert_equal "#<ActionView::Template::Error: original>", error.inspect end end diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index aa185d9cb0..5865b7f23c 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -91,12 +91,12 @@ class TextHelperTest < ActionView::TestCase def test_highlight assert_equal( - "This is a <strong class=\"highlight\">beautiful</strong> morning", + "This is a <mark>beautiful</mark> morning", highlight("This is a beautiful morning", "beautiful") ) assert_equal( - "This is a <strong class=\"highlight\">beautiful</strong> morning, but also a <strong class=\"highlight\">beautiful</strong> day", + "This is a <mark>beautiful</mark> morning, but also a <mark>beautiful</mark> day", highlight("This is a beautiful morning, but also a beautiful day", "beautiful") ) @@ -115,31 +115,31 @@ class TextHelperTest < ActionView::TestCase def test_highlight_should_sanitize_input assert_equal( - "This is a <strong class=\"highlight\">beautiful</strong> morning", + "This is a <mark>beautiful</mark> morning", highlight("This is a beautiful morning<script>code!</script>", "beautiful") ) end def test_highlight_should_not_sanitize_if_sanitize_option_if_false assert_equal( - "This is a <strong class=\"highlight\">beautiful</strong> morning<script>code!</script>", + "This is a <mark>beautiful</mark> morning<script>code!</script>", highlight("This is a beautiful morning<script>code!</script>", "beautiful", :sanitize => false) ) end def test_highlight_with_regexp assert_equal( - "This is a <strong class=\"highlight\">beautiful!</strong> morning", + "This is a <mark>beautiful!</mark> morning", highlight("This is a beautiful! morning", "beautiful!") ) assert_equal( - "This is a <strong class=\"highlight\">beautiful! morning</strong>", + "This is a <mark>beautiful! morning</mark>", highlight("This is a beautiful! morning", "beautiful! morning") ) assert_equal( - "This is a <strong class=\"highlight\">beautiful? morning</strong>", + "This is a <mark>beautiful? morning</mark>", highlight("This is a beautiful? morning", "beautiful? morning") ) end @@ -157,23 +157,23 @@ class TextHelperTest < ActionView::TestCase def test_highlight_with_html assert_equal( - "<p>This is a <strong class=\"highlight\">beautiful</strong> morning, but also a <strong class=\"highlight\">beautiful</strong> day</p>", + "<p>This is a <mark>beautiful</mark> morning, but also a <mark>beautiful</mark> day</p>", highlight("<p>This is a beautiful morning, but also a beautiful day</p>", "beautiful") ) assert_equal( - "<p>This is a <em><strong class=\"highlight\">beautiful</strong></em> morning, but also a <strong class=\"highlight\">beautiful</strong> day</p>", + "<p>This is a <em><mark>beautiful</mark></em> morning, but also a <mark>beautiful</mark> day</p>", highlight("<p>This is a <em>beautiful</em> morning, but also a beautiful day</p>", "beautiful") ) assert_equal( - "<p>This is a <em class=\"error\"><strong class=\"highlight\">beautiful</strong></em> morning, but also a <strong class=\"highlight\">beautiful</strong> <span class=\"last\">day</span></p>", + "<p>This is a <em class=\"error\"><mark>beautiful</mark></em> morning, but also a <mark>beautiful</mark> <span class=\"last\">day</span></p>", highlight("<p>This is a <em class=\"error\">beautiful</em> morning, but also a beautiful <span class=\"last\">day</span></p>", "beautiful") ) assert_equal( - "<p class=\"beautiful\">This is a <strong class=\"highlight\">beautiful</strong> morning, but also a <strong class=\"highlight\">beautiful</strong> day</p>", + "<p class=\"beautiful\">This is a <mark>beautiful</mark> morning, but also a <mark>beautiful</mark> day</p>", highlight("<p class=\"beautiful\">This is a beautiful morning, but also a beautiful day</p>", "beautiful") ) assert_equal( - "<p>This is a <strong class=\"highlight\">beautiful</strong> <a href=\"http://example.com/beautiful#top?what=beautiful%20morning&when=now+then\">morning</a>, but also a <strong class=\"highlight\">beautiful</strong> day</p>", + "<p>This is a <mark>beautiful</mark> <a href=\"http://example.com/beautiful#top?what=beautiful%20morning&when=now+then\">morning</a>, but also a <mark>beautiful</mark> day</p>", highlight("<p>This is a beautiful <a href=\"http://example.com/beautiful\#top?what=beautiful%20morning&when=now+then\">morning</a>, but also a beautiful day</p>", "beautiful") ) assert_equal( diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index d013a44e6c..b482bd3251 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -1,6 +1,5 @@ # encoding: utf-8 require 'abstract_unit' -require 'active_support/ordered_hash' require 'controller/fake_controllers' class UrlHelperTest < ActiveSupport::TestCase @@ -11,6 +10,9 @@ class UrlHelperTest < ActiveSupport::TestCase # In those cases, we'll set up a simple mock attr_accessor :controller, :request + cattr_accessor :request_forgery + self.request_forgery = false + routes = ActionDispatch::Routing::RouteSet.new routes.draw do match "/" => "foo#bar" @@ -28,13 +30,13 @@ class UrlHelperTest < ActiveSupport::TestCase setup :_prepare_context - def hash_for(opts = []) - ActiveSupport::OrderedHash[*([:controller, "foo", :action, "bar"].concat(opts))] + def hash_for(options = {}) + { :controller => "foo", :action => "bar" }.merge!(options) end alias url_hash hash_for def test_url_for_does_not_escape_urls - assert_equal "/?a=b&c=d", url_for(hash_for([:a, :b, :c, :d])) + assert_equal "/?a=b&c=d", url_for(hash_for(:a => :b, :c => :d)) end def test_url_for_with_back @@ -49,11 +51,22 @@ class UrlHelperTest < ActiveSupport::TestCase assert_equal 'javascript:history.back()', url_for(:back) end - # todo: missing test cases + # TODO: missing test cases def test_button_to_with_straight_url assert_dom_equal "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com") end + def test_button_to_with_straight_url_and_request_forgery + self.request_forgery = true + + assert_dom_equal( + %{<form method="post" action="http://www.example.com" class="button_to"><div><input type="submit" value="Hello" /><input name="form_token" type="hidden" value="secret" /></div></form>}, + button_to("Hello", "http://www.example.com") + ) + ensure + self.request_forgery = false + end + def test_button_to_with_form_class assert_dom_equal "<form method=\"post\" action=\"http://www.example.com\" class=\"custom-class\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com", :form_class => 'custom-class') end @@ -154,7 +167,7 @@ class UrlHelperTest < ActiveSupport::TestCase end def test_link_tag_with_host_option - hash = hash_for([:host, "www.example.com"]) + hash = hash_for(:host => "www.example.com") expected = %q{<a href="http://www.example.com/">Test Link</a>} assert_dom_equal(expected, link_to('Test Link', hash)) end @@ -329,7 +342,7 @@ class UrlHelperTest < ActiveSupport::TestCase def test_current_page_with_params_that_match @request = request_for_url("/?order=desc&page=1") - assert current_page?(hash_for([:order, "desc", :page, "1"])) + assert current_page?(hash_for(:order => "desc", :page => "1")) assert current_page?("http://www.example.com/?order=desc&page=1") end @@ -357,20 +370,20 @@ class UrlHelperTest < ActiveSupport::TestCase @request = request_for_url("/?order=desc&page=1") assert_equal "Showing", - link_to_unless_current("Showing", hash_for([:order, 'desc', :page, '1'])) + link_to_unless_current("Showing", hash_for(:order => 'desc', :page => '1')) assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/?order=desc&page=1") @request = request_for_url("/?order=desc") assert_equal %{<a href="/?order=asc">Showing</a>}, - link_to_unless_current("Showing", hash_for([:order, :asc])) + link_to_unless_current("Showing", hash_for(:order => :asc)) assert_equal %{<a href="http://www.example.com/?order=asc">Showing</a>}, link_to_unless_current("Showing", "http://www.example.com/?order=asc") @request = request_for_url("/?order=desc") assert_equal %{<a href="/?order=desc&page=2\">Showing</a>}, - link_to_unless_current("Showing", hash_for([:order, "desc", :page, 2])) + link_to_unless_current("Showing", hash_for(:order => "desc", :page => 2)) assert_equal %{<a href="http://www.example.com/?order=desc&page=2">Showing</a>}, link_to_unless_current("Showing", "http://www.example.com/?order=desc&page=2") @@ -435,9 +448,16 @@ class UrlHelperTest < ActiveSupport::TestCase assert mail_to("me@domain.com", "My email", :encode => "hex").html_safe? end - # TODO: button_to looks at this ... why? def protect_against_forgery? - false + self.request_forgery + end + + def form_authenticity_token + "secret" + end + + def request_forgery_protection_token + "form_token" end private |