diff options
Diffstat (limited to 'actionpack')
43 files changed, 582 insertions, 299 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 428a5d0e1a..15abfb8369 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.1.0 (unreleased)* +* Warn if we cannot verify CSRF token authenticity [José Valim] + * Allow AM/PM format in datetime selectors [Aditya Sanghi] * Only show dump of regular env methods on exception screen (not all the rack crap) [DHH] @@ -15,7 +17,7 @@ class PostsController < ActionController::Base stream :only => :index end - + Please read the docs at `ActionController::Streaming` for more information. * Added `ActionDispatch::Request.ignore_accept_header` to ignore accept headers and only consider the format given as parameter [José Valim] @@ -131,7 +133,58 @@ tested. * Add Rack::Cache to the default stack. Create a Rails store that delegates to the Rails cache, so by default, whatever caching layer you are using will be used for HTTP caching. Note that Rack::Cache will be used if you use #expires_in, #fresh_when or #stale with :public => true. Otherwise, the caching rules will apply to the browser only. [Yehuda Katz, Carl Lerche] -*Rails 3.0.2 (unreleased)* +*Rails 3.0.7 (April 18, 2011)* + +*No changes. + + +*Rails 3.0.6 (April 5, 2011) + +* Fixed XSS vulnerability in `auto_link`. `auto_link` no longer marks input as + html safe. Please make sure that calls to auto_link() are wrapped in a + sanitize(), or a raw() depending on the type of input passed to auto_link(). + For example: + + <%= sanitize(auto_link(some_user_input)) %> + + Thanks to Torben Schulz for reporting this. The fix can be found here: + 61ee3449674c591747db95f9b3472c5c3bd9e84d + +* Fixes the output of `rake routes` to be correctly match to the behavior of the application, as the regular expression used to match the path is greedy and won't capture the format part by default [Prem Sichanugrist] + +* Fixes an issue with number_to_human when converting values which are less than 1 but greater than -1 [Josh Kalderimis] + +* Sensitive query string parameters (specified in config.filter_parameters) will now be filtered out from the request paths in the log file. [Prem Sichanugrist, fxn] + +* URL parameters which return nil for to_param are now removed from the query string [Andrew White] + +* Don't allow i18n to change the minor version, version now set to ~> 0.5.0 [Santiago Pastorino] + +* Make TranslationHelper#translate use the :rescue_format option in I18n 0.5.0 [Sven Fuchs] + +* Fix regression: javascript_include_tag shouldn't raise if you register an expansion key with nil or [] value [Santiago Pastorino] + +* Fix Action caching bug where an action that has a non-cacheable response always renders a nil response body. It now correctly renders the response body. [Cheah Chu Yeow] + + +*Rails 3.0.5 (February 26, 2011)* + +* No changes. + + +*Rails 3.0.4 (February 8, 2011)* + +* No changes. + + +*Rails 3.0.3 (November 16, 2010)* + +* When ActiveRecord::Base objects are sent to predicate methods, the id of the object should be sent to ARel, not the ActiveRecord::Base object. + +* :constraints routing should only do sanity checks against regular expressions. String arguments are OK. + + +*Rails 3.0.2 (November 15, 2010)* * The helper number_to_currency accepts a new :negative_format option to be able to configure how to render negative amounts. [Don Wilson] diff --git a/actionpack/README.rdoc b/actionpack/README.rdoc index 1a56c44db5..5db4cff66b 100644 --- a/actionpack/README.rdoc +++ b/actionpack/README.rdoc @@ -338,4 +338,4 @@ API documentation is at Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here: -* https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets +* https://github.com/rails/rails/issues diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index fdd894fe63..f623d6d487 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -24,8 +24,8 @@ Gem::Specification.new do |s| s.add_dependency('i18n', '~> 0.6.0beta1') s.add_dependency('rack', '~> 1.3.0.beta') s.add_dependency('rack-test', '~> 0.6.0') - s.add_dependency('rack-mount', '~> 0.7.2') - s.add_dependency('sprockets', '~> 2.0.0.beta.2') + s.add_dependency('rack-mount', '~> 0.8.0') + s.add_dependency('sprockets', '~> 2.0.0.beta.3') s.add_dependency('tzinfo', '~> 0.3.27') s.add_dependency('erubis', '~> 2.7.0') end diff --git a/actionpack/lib/abstract_controller/url_for.rb b/actionpack/lib/abstract_controller/url_for.rb index e5d5bef6b4..e4261068d8 100644 --- a/actionpack/lib/abstract_controller/url_for.rb +++ b/actionpack/lib/abstract_controller/url_for.rb @@ -1,3 +1,9 @@ +# Includes +url_for+ into the host class (e.g. an abstract controller or mailer). The class +# has to provide a +RouteSet+ by implementing the <tt>_routes</tt> methods. Otherwise, an +# exception will be raised. +# +# Note that this module is completely decoupled from HTTP - the only requirement is a valid +# <tt>_routes</tt> implementation. module AbstractController module UrlFor extend ActiveSupport::Concern diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 881af74147..93241fc056 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -2,6 +2,7 @@ require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/array/wrap' +require 'active_support/core_ext/module/anonymous' require 'action_dispatch/http/mime_types' module ActionController @@ -136,15 +137,25 @@ module ActionController # this could be done by trying to find the defined model that has the # same singularize name as the controller. For example, +UsersController+ # will try to find if the +User+ model exists. - def _default_wrap_model + # + # This method also does namespace lookup. Foo::Bar::UsersController will + # try to find Foo::Bar::User, Foo::User and finally User. + def _default_wrap_model #:nodoc: + return nil if self.anonymous? + model_name = self.name.sub(/Controller$/, '').singularize begin model_klass = model_name.constantize - rescue NameError => e - unscoped_model_name = model_name.split("::", 2).last - break if unscoped_model_name == model_name - model_name = unscoped_model_name + rescue NameError, ArgumentError => e + if e.message =~ /is not missing constant|uninitialized constant #{model_name}/ + namespaces = model_name.split("::") + namespaces.delete_at(-2) + break if namespaces.last == model_name + model_name = namespaces.join("::") + else + raise + end end until model_klass model_klass @@ -155,12 +166,12 @@ module ActionController unless options[:only] || options[:except] model ||= _default_wrap_model - if model.respond_to?(:column_names) - options[:only] = model.column_names + if model.respond_to?(:attribute_names) && model.attribute_names.present? + options[:only] = model.attribute_names end end - unless options[:name] + unless options[:name] || self.anonymous? model ||= _default_wrap_model options[:name] = model ? model.to_s.demodulize.underscore : controller_name.singularize @@ -218,7 +229,7 @@ module ActionController # Checks if we should perform parameters wrapping. def _wrapper_enabled? ref = request.content_mime_type.try(:ref) - _wrapper_formats.include?(ref) && !request.request_parameters[_wrapper_key] + _wrapper_formats.include?(ref) && _wrapper_key && !request.request_parameters[_wrapper_key] end end end diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 1cd93a188c..13044a7450 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -73,7 +73,10 @@ module ActionController #:nodoc: protected # The actual before_filter that is used. Modify this to change how you handle unverified requests. def verify_authenticity_token - verified_request? || handle_unverified_request + unless verified_request? + logger.debug "WARNING: Can't verify CSRF token authenticity" if logger + handle_unverified_request + end end def handle_unverified_request diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index 6fc0cf1fb8..08132b1900 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -1,3 +1,24 @@ +# Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing +# the <tt>_routes</tt> method. Otherwise, an exception will be raised. +# +# In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define +# url options like the +host+. In order to do so, this module requires the host class +# to implement +env+ and +request+, which need to be a Rack-compatible. +# +# Example: +# +# class RootUrl +# include ActionController::UrlFor +# include Rails.application.routes.url_helpers +# +# delegate :env, :request, :to => :controller +# +# def initialize(controller) +# @controller = controller +# @url = root_path # named route from the application. +# end +# end +# => module ActionController module UrlFor extend ActiveSupport::Concern diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 0085f542aa..89ff5ba174 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -2,6 +2,7 @@ require 'rack/session/abstract/id' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/object/to_query' require 'active_support/core_ext/class/attribute' +require 'active_support/core_ext/module/anonymous' module ActionController module TemplateAssertions @@ -413,7 +414,11 @@ module ActionController @request.env['REQUEST_METHOD'] = http_method parameters ||= {} - @request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters) + controller_class_name = @controller.class.anonymous? ? + "anonymous_controller" : + @controller.class.name.underscore.sub(/_controller$/, '') + + @request.assign_parameters(@routes, controller_class_name, action.to_s, parameters) @request.session = ActionController::TestSession.new(session) if session @request.session["flash"] = @request.flash.update(flash || {}) diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb index 4f4cb96a74..aaed0d750f 100644 --- a/actionpack/lib/action_dispatch/http/cache.rb +++ b/actionpack/lib/action_dispatch/http/cache.rb @@ -42,20 +42,6 @@ module ActionDispatch attr_reader :cache_control, :etag alias :etag? :etag - def initialize(*) - super - - @cache_control = {} - @etag = self["ETag"] - - if cache_control = self["Cache-Control"] - cache_control.split(/,\s*/).each do |segment| - first, last = segment.split("=") - @cache_control[first.to_sym] = last || true - end - end - end - def last_modified if last = headers['Last-Modified'] Time.httpdate(last) @@ -77,6 +63,18 @@ module ActionDispatch private + def prepare_cache_control! + @cache_control = {} + @etag = self["ETag"] + + if cache_control = self["Cache-Control"] + cache_control.split(/,\s*/).each do |segment| + first, last = segment.split("=") + @cache_control[first.to_sym] = last || true + end + end + end + def handle_conditional_get! if etag? || last_modified? || !@cache_control.empty? set_conditional_cache_control! diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 1f4f3ac0da..3a6b1da4fd 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -56,26 +56,25 @@ module ActionDispatch # :nodoc: cattr_accessor(:default_charset) { "utf-8" } - module Setup - def initialize(status = 200, header = {}, body = []) - self.body, self.header, self.status = body, header, status + include Rack::Response::Helpers + include ActionDispatch::Http::Cache::Response - @sending_file = false - @blank = false + def initialize(status = 200, header = {}, body = []) + self.body, self.header, self.status = body, header, status - if content_type = self["Content-Type"] - type, charset = content_type.split(/;\s*charset=/) - @content_type = Mime::Type.lookup(type) - @charset = charset || "UTF-8" - end + @sending_file = false + @blank = false - yield self if block_given? + if content_type = self["Content-Type"] + type, charset = content_type.split(/;\s*charset=/) + @content_type = Mime::Type.lookup(type) + @charset = charset || "UTF-8" end - end - include Rack::Response::Helpers - include Setup - include ActionDispatch::Http::Cache::Response + prepare_cache_control! + + yield self if block_given? + end def status=(status) @status = Rack::Utils.status_code(status) @@ -116,9 +115,32 @@ module ActionDispatch # :nodoc: EMPTY = " " + class BodyBuster #:nodoc: + def initialize(response) + @response = response + @body = "" + end + + def bust(body) + body.call(@response, self) + body.close if body.respond_to?(:close) + @body + end + + def write(string) + @body << string.to_s + end + end + def body=(body) @blank = true if body == EMPTY + if body.respond_to?(:call) + ActiveSupport::Deprecation.warn "Setting a Proc or an object that responds to call " \ + "in response_body is no longer supported", caller + body = BodyBuster.new(self).bust(body) + end + # Explicitly check for strings. This is *wrong* theoretically # but if we don't check this, the performance on string bodies # is bad on Ruby 1.8 (because strings responds to each then). @@ -150,6 +172,10 @@ module ActionDispatch # :nodoc: headers['Location'] = url end + def close + @body.close if @body.respond_to?(:close) + end + def to_a assign_default_content_type_and_charset! handle_conditional_get! diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index d9c07d6ca3..8487b0fc8c 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -162,7 +162,7 @@ module ActionDispatch # Returns all the \subdomains as a string, so <tt>"dev.www"</tt> would be # returned for "dev.www.rubyonrails.org". You can specify a different <tt>tld_length</tt>, - # such as 2 to catch <tt>["www"]</tt> instead of <tt>"www.rubyonrails"</tt> + # such as 2 to catch <tt>"www"</tt> instead of <tt>"www.rubyonrails"</tt> # in "www.rubyonrails.co.uk". def subdomain(tld_length = @@tld_length) subdomains(tld_length).join(".") diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb index 43fd93adf6..74c090f260 100644 --- a/actionpack/lib/action_dispatch/routing.rb +++ b/actionpack/lib/action_dispatch/routing.rb @@ -49,8 +49,8 @@ module ActionDispatch # You may wish to organize groups of controllers under a namespace. Most # commonly, you might group a number of administrative controllers under # an +admin+ namespace. You would place these controllers under the - # app/controllers/admin directory, and you can group them together in your - # router: + # <tt>app/controllers/admin</tt> directory, and you can group them together + # in your router: # # namespace "admin" do # resources :posts, :comments @@ -152,7 +152,7 @@ module ActionDispatch # } # end # - # Using the multiline match modifier will raise an ArgumentError. + # Using the multiline match modifier will raise an +ArgumentError+. # Encoding regular expression modifiers are silently ignored. The # match will always use the default encoding or ASCII. # diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index a65f6e1fce..3ba6094fbb 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -335,7 +335,7 @@ module ActionDispatch # # [:on] # Shorthand for wrapping routes in a specific RESTful context. Valid - # values are :member, :collection, and :new. Only use within + # values are +:member+, +:collection+, and +:new+. Only use within # <tt>resource(s)</tt> block. For example: # # resource :bar do @@ -352,7 +352,7 @@ module ActionDispatch # # [:constraints] # Constrains parameters with a hash of regular expressions or an - # object that responds to #matches? + # object that responds to <tt>matches?</tt> # # match 'path/:id', :constraints => { :id => /[A-Z]\d{5}/ } # @@ -373,7 +373,7 @@ module ActionDispatch # See <tt>Scoping#defaults</tt> for its scope equivalent. # # [:anchor] - # Boolean to anchor a #match pattern. Default is true. When set to + # Boolean to anchor a <tt>match</tt> pattern. Default is true. When set to # false, the pattern matches any request prefixed with the given path. # # # Matches any request starting with 'path' @@ -517,15 +517,15 @@ module ActionDispatch # You may wish to organize groups of controllers under a namespace. # Most commonly, you might group a number of administrative controllers # under an +admin+ namespace. You would place these controllers under - # the app/controllers/admin directory, and you can group them together - # in your router: + # the <tt>app/controllers/admin</tt> directory, and you can group them + # together in your router: # # namespace "admin" do # resources :posts, :comments # end # # This will create a number of routes for each of the posts and comments - # controller. For Admin::PostsController, Rails will create: + # controller. For <tt>Admin::PostsController</tt>, Rails will create: # # GET /admin/posts # GET /admin/posts/new @@ -536,7 +536,7 @@ module ActionDispatch # DELETE /admin/posts/1 # # If you want to route /posts (without the prefix /admin) to - # Admin::PostsController, you could use + # <tt>Admin::PostsController</tt>, you could use # # scope :module => "admin" do # resources :posts @@ -546,7 +546,7 @@ module ActionDispatch # # resources :posts, :module => "admin" # - # If you want to route /admin/posts to PostsController + # If you want to route /admin/posts to +PostsController+ # (without the Admin:: module prefix), you could use # # scope "/admin" do @@ -555,11 +555,11 @@ module ActionDispatch # # or, for a single case # - # resources :posts, :path => "/admin" + # resources :posts, :path => "/admin/posts" # # In each of these cases, the named routes remain the same as if you did # not use scope. In the last case, the following paths map to - # PostsController: + # +PostsController+: # # GET /admin/posts # GET /admin/posts/new @@ -587,7 +587,7 @@ module ActionDispatch # # === Examples # - # # route /posts (without the prefix /admin) to Admin::PostsController + # # route /posts (without the prefix /admin) to <tt>Admin::PostsController</tt> # scope :module => "admin" do # resources :posts # end @@ -597,7 +597,7 @@ module ActionDispatch # resources :posts # end # - # # prefix the routing helper name: sekret_posts_path instead of posts_path + # # prefix the routing helper name: +sekret_posts_path+ instead of +posts_path+ # scope :as => "sekret" do # resources :posts # end @@ -679,12 +679,12 @@ module ActionDispatch # resources :posts # end # - # # maps to Sekret::PostsController rather than Admin::PostsController + # # maps to <tt>Sekret::PostsController</tt> rather than <tt>Admin::PostsController</tt> # namespace :admin, :module => "sekret" do # resources :posts # end # - # # generates sekret_posts_path rather than admin_posts_path + # # generates +sekret_posts_path+ rather than +admin_posts_path+ # namespace :admin, :as => "sekret" do # resources :posts # end @@ -712,6 +712,7 @@ module ActionDispatch # constraints(:post_id => /\d+\.\d+) do # resources :comments # end + # end # # === Restricting based on IP # @@ -846,20 +847,20 @@ module ActionDispatch # You may wish to organize groups of controllers under a namespace. Most # commonly, you might group a number of administrative controllers under # an +admin+ namespace. You would place these controllers under the - # app/controllers/admin directory, and you can group them together in your - # router: + # <tt>app/controllers/admin</tt> directory, and you can group them together + # in your router: # # namespace "admin" do # resources :posts, :comments # end # - # By default the :id parameter doesn't accept dots. If you need to - # use dots as part of the :id parameter add a constraint which + # By default the +:id+ parameter doesn't accept dots. If you need to + # use dots as part of the +:id+ parameter add a constraint which # overrides this restriction, e.g: # # resources :articles, :id => /[^\/]+/ # - # This allows any character other than a slash as part of your :id. + # This allows any character other than a slash as part of your +:id+. # module Resources # CANONICAL_ACTIONS holds all actions that does not need a prefix or @@ -975,7 +976,7 @@ module ActionDispatch # resource :geocoder # # creates six different routes in your application, all mapping to - # the GeoCoders controller (note that the controller is named after + # the +GeoCoders+ controller (note that the controller is named after # the plural): # # GET /geocoder/new @@ -1024,7 +1025,7 @@ module ActionDispatch # resources :photos # # creates seven different routes in your application, all mapping to - # the Photos controller: + # the +Photos+ controller: # # GET /photos/new # POST /photos @@ -1107,11 +1108,11 @@ module ActionDispatch # # === Examples # - # # routes call Admin::PostsController + # # routes call <tt>Admin::PostsController</tt> # resources :posts, :module => "admin" # # # resource actions are at /admin/posts. - # resources :posts, :path => "admin" + # resources :posts, :path => "admin/posts" def resources(*resources, &block) options = resources.extract_options! @@ -1151,7 +1152,7 @@ module ActionDispatch # end # # This will enable Rails to recognize paths such as <tt>/photos/search</tt> - # with GET, and route to the search action of PhotosController. It will also + # with GET, and route to the search action of +PhotosController+. It will also # create the <tt>search_photos_url</tt> and <tt>search_photos_path</tt> # route helpers. def collection @@ -1175,7 +1176,7 @@ module ActionDispatch # end # # This will recognize <tt>/photos/1/preview</tt> with GET, and route to the - # preview action of PhotosController. It will also create the + # preview action of +PhotosController+. It will also create the # <tt>preview_photo_url</tt> and <tt>preview_photo_path</tt> helpers. def member unless resource_scope? diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 97e8ccc9a5..5097f6732d 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -224,6 +224,7 @@ module ActionDispatch self.valid_conditions.push(:controller, :action) @append = [] + @prepend = [] @disable_clear_and_finalize = false clear! end @@ -232,7 +233,6 @@ module ActionDispatch clear! unless @disable_clear_and_finalize eval_block(block) finalize! unless @disable_clear_and_finalize - nil end @@ -240,6 +240,10 @@ module ActionDispatch @append << block end + def prepend(&block) + @prepend << block + end + def eval_block(block) if block.arity == 1 raise "You are using the old router DSL which has been removed in Rails 3.1. " << @@ -262,8 +266,6 @@ module ActionDispatch end def clear! - # Clear the controller cache so we may discover new ones - @controller_constraints = nil @finalized = false routes.clear named_routes.clear @@ -271,6 +273,7 @@ module ActionDispatch :parameters_key => PARAMETERS_KEY, :request_class => request_class ) + @prepend.each { |blk| eval_block(blk) } end def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false) diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index d4db78a25a..5893f86798 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -131,10 +131,10 @@ module ActionDispatch # # Examples: # - # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :port=>'8080' # => 'http://somehost.org:8080/tasks/testing' - # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :anchor => 'ok', :only_path => true # => '/tasks/testing#ok' - # url_for :controller => 'tasks', :action => 'testing', :trailing_slash=>true # => 'http://somehost.org/tasks/testing/' - # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :number => '33' # => 'http://somehost.org/tasks/testing?number=33' + # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :port => '8080' # => 'http://somehost.org:8080/tasks/testing' + # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :anchor => 'ok', :only_path => true # => '/tasks/testing#ok' + # url_for :controller => 'tasks', :action => 'testing', :trailing_slash => true # => 'http://somehost.org/tasks/testing/' + # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :number => '33' # => 'http://somehost.org/tasks/testing?number=33' def url_for(options = nil) case options when String diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index c67a0664dc..5fa91d1a76 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -169,7 +169,7 @@ module ActionDispatch # assert_select "title", "Welcome" # # # Page title is "Welcome" and there is only one title element - # assert_select "title", {:count=>1, :text=>"Welcome"}, + # assert_select "title", {:count => 1, :text => "Welcome"}, # "Wrong title or more than one title element" # # # Page contains no forms diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb index d430691429..397bda41d5 100644 --- a/actionpack/lib/action_dispatch/testing/test_process.rb +++ b/actionpack/lib/action_dispatch/testing/test_process.rb @@ -29,7 +29,7 @@ module ActionDispatch @response.redirect_url end - # Shortcut for <tt>ARack::Test::UploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>: + # Shortcut for <tt>Rack::Test::UploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>: # # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png') # diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 92b6f7c770..a67b61c1ef 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -50,6 +50,7 @@ module ActionView autoload :Resolver autoload :PathResolver autoload :FileSystemResolver + autoload :OptimizedFileSystemResolver autoload :FallbackFileSystemResolver end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index c98110353f..fd2970b8e2 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -85,11 +85,11 @@ module ActionView #:nodoc: # # Here are some basic examples: # - # xml.em("emphasized") # => <em>emphasized</em> - # xml.em { xml.b("emph & bold") } # => <em><b>emph & bold</b></em> - # xml.a("A Link", "href"=>"http://onestepback.org") # => <a href="http://onestepback.org">A Link</a> - # xml.target("name"=>"compile", "option"=>"fast") # => <target option="fast" name="compile"\> - # # NOTE: order of attributes is not specified. + # xml.em("emphasized") # => <em>emphasized</em> + # xml.em { xml.b("emph & bold") } # => <em><b>emph & bold</b></em> + # xml.a("A Link", "href" => "http://onestepback.org") # => <a href="http://onestepback.org">A Link</a> + # xml.target("name" => "compile", "option" => "fast") # => <target option="fast" name="compile"\> + # # NOTE: order of attributes is not specified. # # Any method with a block will be treated as an XML markup tag with nested markup in the block. For example, the following: # diff --git a/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/actionpack/lib/action_view/helpers/atom_feed_helper.rb index 96e5722252..889ea8a763 100644 --- a/actionpack/lib/action_view/helpers/atom_feed_helper.rb +++ b/actionpack/lib/action_view/helpers/atom_feed_helper.rb @@ -81,8 +81,8 @@ module ActionView # # The Atom spec defines five elements (content rights title subtitle # summary) which may directly contain xhtml content if :type => 'xhtml' - # is specified as an attribute. If so, this helper will take care of - # the enclosing div and xhtml namespace declaration. Example usage: + # is specified as an attribute. If so, this helper will take care of + # the enclosing div and xhtml namespace declaration. Example usage: # # entry.summary :type => 'xhtml' do |xhtml| # xhtml.p pluralize(order.line_items.count, "line item") @@ -91,8 +91,8 @@ module ActionView # end # # - # atom_feed yields an AtomFeedBuilder instance. Nested elements yield - # an AtomBuilder instance. + # <tt>atom_feed</tt> yields an +AtomFeedBuilder+ instance. Nested elements yield + # an +AtomBuilder+ instance. def atom_feed(options = {}, &block) if options[:schema_date] options[:schema_date] = options[:schema_date].strftime("%Y-%m-%d") if options[:schema_date].respond_to?(:strftime) diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb index 385378ea29..e81d03b537 100644 --- a/actionpack/lib/action_view/helpers/cache_helper.rb +++ b/actionpack/lib/action_view/helpers/cache_helper.rb @@ -3,7 +3,7 @@ module ActionView module Helpers module CacheHelper # This helper exposes a method for caching fragments of a view - # rather than an entire action or page. This technique is useful + # rather than an entire action or page. This technique is useful # caching pieces like menus, lists of newstopics, static HTML # fragments, and so on. This method takes a block that contains # the content you wish to cache. diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index ead7feb091..3b5f4e694f 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -135,8 +135,12 @@ module ActionView # for elements that will be fragment cached. def content_for(name, content = nil, &block) content = capture(&block) if block_given? - result = @view_flow.append(name, content) if content - result unless content + if content + @view_flow.append(name, content) + nil + else + @view_flow.get(name) + end end # The same as +content_for+ but when used with streaming flushes diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index d2ddaafcb3..c78c03a5eb 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -12,14 +12,14 @@ module ActionView # select-type methods share a number of common options that are as follows: # # * <tt>:prefix</tt> - overwrites the default prefix of "date" used for the select names. So specifying "birthday" - # would give birthday[month] instead of date[month] if passed to the select_month method. + # would give birthday[month] instead of date[month] if passed to the <tt>select_month</tt> method. # * <tt>:include_blank</tt> - set to true if it should be possible to set an empty date. # * <tt>:discard_type</tt> - set to true if you want to discard the type part of the select name. If set to true, - # the select_month method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead of - # "date[month]". + # the <tt>select_month</tt> method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead + # of "date[month]". module DateHelper # Reports the approximate distance in time between two Time or Date objects or integers as seconds. - # Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs + # Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs. # Distances are reported based on the following table: # # 0 <-> 29 secs # => less than a minute @@ -119,7 +119,7 @@ module ActionView end end - # Like distance_of_time_in_words, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>. + # Like <tt>distance_of_time_in_words</tt>, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>. # # ==== Examples # time_ago_in_words(3.minutes.from_now) # => 3 minutes @@ -176,7 +176,7 @@ module ActionView # NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed. # # ==== Examples - # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute + # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute. # date_select("post", "written_on") # # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute, @@ -197,7 +197,7 @@ module ActionView # # lacking a year field. # date_select("user", "birthday", :order => [:month, :day]) # - # # Generates a date select that when POSTed is stored in the user variable, in the birthday attribute + # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute # # which is initially set to the date 3 days from the current date # date_select("post", "written_on", :default => 3.days.from_now) # @@ -205,7 +205,7 @@ module ActionView # # that will have a default day of 20. # date_select("credit_card", "bill_due", :default => { :day => 20 }) # - # # Generates a date select with custom prompts + # # Generates a date select with custom prompts. # date_select("post", "written_on", :prompt => { :day => 'Select day', :month => 'Select month', :year => 'Select year' }) # # The selects are prepared for multi-parameter assignment to an Active Record object. @@ -222,22 +222,23 @@ module ActionView # with <tt>:ampm</tt> option. # # This method will also generate 3 input hidden tags, for the actual year, month and day unless the option - # <tt>:ignore_date</tt> is set to +true+. + # <tt>:ignore_date</tt> is set to +true+. If you set the <tt>:ignore_date</tt> to +true+, you must have a + # +date_select+ on the same method within the form otherwise an exception will be raised. # # If anything is passed in the html_options hash it will be applied to every select tag in the set. # # ==== Examples - # # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute + # # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute. # time_select("post", "sunrise") # # # Creates a time select tag with a seconds field that, when POSTed, will be stored in the post variables in # # the sunrise attribute. # time_select("post", "start_time", :include_seconds => true) # - # # You can set the :minute_step to 15 which will give you: 00, 15, 30 and 45. + # # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30 and 45. # time_select 'game', 'game_time', {:minute_step => 15} # - # # Creates a time select tag with a custom prompt. Use :prompt => true for generic prompts. + # # Creates a time select tag with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts. # time_select("post", "written_on", :prompt => {:hour => 'Choose hour', :minute => 'Choose minute', :second => 'Choose seconds'}) # time_select("post", "written_on", :prompt => {:hour => true}) # generic prompt for hours # time_select("post", "written_on", :prompt => true) # generic prompts for all @@ -261,7 +262,7 @@ module ActionView # # ==== Examples # # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on - # # attribute + # # attribute. # datetime_select("post", "written_on") # # # Generates a datetime select with a year select that starts at 1995 that, when POSTed, will be stored in the @@ -279,7 +280,7 @@ module ActionView # # as the written_on attribute. # datetime_select("post", "written_on", :discard_type => true) # - # # Generates a datetime select with a custom prompt. Use :prompt=>true for generic prompts. + # # Generates a datetime select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts. # datetime_select("post", "written_on", :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'}) # datetime_select("post", "written_on", :prompt => {:hour => true}) # generic prompt for hours # datetime_select("post", "written_on", :prompt => true) # generic prompts for all @@ -301,7 +302,7 @@ module ActionView # ==== Examples # my_date_time = Time.now + 4.days # - # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today) + # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today). # select_datetime(my_date_time) # # # Generates a datetime select that defaults to today (no specified datetime) @@ -331,7 +332,7 @@ module ActionView # # prefixed with 'payday' rather than 'date' # select_datetime(my_date_time, :prefix => 'payday') # - # # Generates a datetime select with a custom prompt. Use :prompt=>true for generic prompts. + # # Generates a datetime select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts. # select_datetime(my_date_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'}) # select_datetime(my_date_time, :prompt => {:hour => true}) # generic prompt for hours # select_datetime(my_date_time, :prompt => true) # generic prompts for all @@ -350,10 +351,10 @@ module ActionView # ==== Examples # my_date = Time.today + 6.days # - # # Generates a date select that defaults to the date in my_date (six days after today) + # # Generates a date select that defaults to the date in my_date (six days afteri today). # select_date(my_date) # - # # Generates a date select that defaults to today (no specified date) + # # Generates a date select that defaults to today (no specified date). # select_date() # # # Generates a date select that defaults to the date in my_date (six days after today) @@ -361,18 +362,18 @@ module ActionView # select_date(my_date, :order => [:year, :month, :day]) # # # Generates a date select that discards the type of the field and defaults to the date in - # # my_date (six days after today) + # # my_date (six days after today). # select_date(my_date, :discard_type => true) # # # Generates a date select that defaults to the date in my_date, - # # which has fields separated by '/' + # # which has fields separated by '/'. # select_date(my_date, :date_separator => '/') # # # Generates a date select that defaults to the datetime in my_date (six days after today) - # # prefixed with 'payday' rather than 'date' + # # prefixed with 'payday' rather than 'date'. # select_date(my_date, :prefix => 'payday') # - # # Generates a date select with a custom prompt. Use :prompt=>true for generic prompts. + # # Generates a date select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts. # select_date(my_date, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'}) # select_date(my_date, :prompt => {:hour => true}) # generic prompt for hours # select_date(my_date, :prompt => true) # generic prompts for all @@ -381,7 +382,7 @@ module ActionView DateTimeSelector.new(date, options, html_options).select_date end - # Returns a set of html select-tags (one for hour and minute) + # Returns a set of html select-tags (one for hour and minute). # You can set <tt>:time_separator</tt> key to format the output, and # the <tt>:include_seconds</tt> option to include an input for seconds. # @@ -390,28 +391,28 @@ module ActionView # ==== Examples # my_time = Time.now + 5.days + 7.hours + 3.minutes + 14.seconds # - # # Generates a time select that defaults to the time in my_time + # # Generates a time select that defaults to the time in my_time. # select_time(my_time) # - # # Generates a time select that defaults to the current time (no specified time) + # # Generates a time select that defaults to the current time (no specified time). # select_time() # # # Generates a time select that defaults to the time in my_time, - # # which has fields separated by ':' + # # which has fields separated by ':'. # select_time(my_time, :time_separator => ':') # # # Generates a time select that defaults to the time in my_time, - # # that also includes an input for seconds + # # that also includes an input for seconds. # select_time(my_time, :include_seconds => true) # # # Generates a time select that defaults to the time in my_time, that has fields - # # separated by ':' and includes an input for seconds + # # separated by ':' and includes an input for seconds. # select_time(my_time, :time_separator => ':', :include_seconds => true) # # # Generate a time select field with hours in the AM/PM format # select_time(my_time, :ampm => true) # - # # Generates a time select with a custom prompt. Use :prompt=>true for generic prompts. + # # Generates a time select with a custom prompt. Use <tt>:prompt</tt> to true for generic prompts. # select_time(my_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'}) # select_time(my_time, :prompt => {:hour => true}) # generic prompt for hours # select_time(my_time, :prompt => true) # generic prompts for all @@ -427,17 +428,17 @@ module ActionView # ==== Examples # my_time = Time.now + 16.minutes # - # # Generates a select field for seconds that defaults to the seconds for the time in my_time + # # Generates a select field for seconds that defaults to the seconds for the time in my_time. # select_second(my_time) # - # # Generates a select field for seconds that defaults to the number given + # # Generates a select field for seconds that defaults to the number given. # select_second(33) # # # Generates a select field for seconds that defaults to the seconds for the time in my_time - # # that is named 'interval' rather than 'second' + # # that is named 'interval' rather than 'second'. # select_second(my_time, :field_name => 'interval') # - # # Generates a select field for seconds with a custom prompt. Use :prompt=>true for a + # # Generates a select field for seconds with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. # select_minute(14, :prompt => 'Choose seconds') # @@ -453,17 +454,17 @@ module ActionView # ==== Examples # my_time = Time.now + 6.hours # - # # Generates a select field for minutes that defaults to the minutes for the time in my_time + # # Generates a select field for minutes that defaults to the minutes for the time in my_tiime. # select_minute(my_time) # - # # Generates a select field for minutes that defaults to the number given + # # Generates a select field for minutes that defaults to the number given. # select_minute(14) # # # Generates a select field for minutes that defaults to the minutes for the time in my_time - # # that is named 'stride' rather than 'second' + # # that is named 'stride' rather than 'second'. # select_minute(my_time, :field_name => 'stride') # - # # Generates a select field for minutes with a custom prompt. Use :prompt=>true for a + # # Generates a select field for minutes with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. # select_minute(14, :prompt => 'Choose minutes') # @@ -478,17 +479,17 @@ module ActionView # ==== Examples # my_time = Time.now + 6.hours # - # # Generates a select field for hours that defaults to the hour for the time in my_time + # # Generates a select field for hours that defaults to the hour for the time in my_time. # select_hour(my_time) # - # # Generates a select field for hours that defaults to the number given + # # Generates a select field for hours that defaults to the number given. # select_hour(13) # # # Generates a select field for hours that defaults to the minutes for the time in my_time - # # that is named 'stride' rather than 'second' + # # that is named 'stride' rather than 'second'. # select_hour(my_time, :field_name => 'stride') # - # # Generates a select field for hours with a custom prompt. Use :prompt => true for a + # # Generates a select field for hours with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. # select_hour(13, :prompt => 'Choose hour') # @@ -506,17 +507,17 @@ module ActionView # ==== Examples # my_date = Time.today + 2.days # - # # Generates a select field for days that defaults to the day for the date in my_date + # # Generates a select field for days that defaults to the day for the date in my_date. # select_day(my_time) # - # # Generates a select field for days that defaults to the number given + # # 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 day for the date in my_date - # # that is named 'due' rather than 'day' + # # that is named 'due' rather than 'day'. # select_day(my_time, :field_name => 'due') # - # # Generates a select field for days with a custom prompt. Use :prompt => true for a + # # Generates a select field for days with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. # select_day(5, :prompt => 'Choose day') # @@ -539,7 +540,7 @@ module ActionView # select_month(Date.today) # # # Generates a select field for months that defaults to the current month that - # # is named "start" rather than "month" + # # is named "start" rather than "month". # select_month(Date.today, :field_name => 'start') # # # Generates a select field for months that defaults to the current month that @@ -558,7 +559,7 @@ 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 with a custom prompt. Use :prompt => true for a + # # 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') # @@ -574,22 +575,22 @@ module ActionView # # ==== Examples # # Generates a select field for years that defaults to the current year that - # # has ascending year values + # # has ascending year values. # select_year(Date.today, :start_year => 1992, :end_year => 2007) # # # Generates a select field for years that defaults to the current year that - # # is named 'birth' rather than 'year' + # # is named 'birth' rather than 'year'. # select_year(Date.today, :field_name => 'birth') # # # Generates a select field for years that defaults to the current year that - # # has descending year values + # # has descending year values. # select_year(Date.today, :start_year => 2005, :end_year => 1900) # # # Generates a select field for years that defaults to the year 2006 that - # # has ascending year values + # # has ascending year values. # select_year(2006, :start_year => 2000, :end_year => 2010) # - # # Generates a select field for years with a custom prompt. Use :prompt => true for a + # # Generates a select field for years with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. # select_year(14, :prompt => 'Choose year') # @@ -783,7 +784,7 @@ module ActionView end # Returns translated month names, but also ensures that a custom month - # name array has a leading nil element + # name array has a leading nil element. def month_names month_names = @options[:use_month_names] || translated_month_names month_names.unshift(nil) if month_names.size < 13 @@ -791,13 +792,13 @@ module ActionView end memoize :month_names - # Returns translated month names + # Returns translated month names. # => [nil, "January", "February", "March", # "April", "May", "June", "July", # "August", "September", "October", # "November", "December"] # - # If :use_short_month option is set + # If <tt>:use_short_month</tt> option is set # => [nil, "Jan", "Feb", "Mar", "Apr", "May", "Jun", # "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] def translated_month_names @@ -805,13 +806,13 @@ module ActionView I18n.translate(key, :locale => @options[:locale]) end - # Lookup month name for number + # Lookup month name for number. # month_name(1) => "January" # - # If :use_month_numbers option is passed + # If <tt>:use_month_numbers</tt> option is passed # month_name(1) => 1 # - # If :add_month_numbers option is passed + # If <tt>:add_month_numbers</tt> option is passed # month_name(1) => "1 - January" def month_name(number) if @options[:use_month_numbers] @@ -832,16 +833,22 @@ module ActionView I18n.translate(:'date.order', :locale => @options[:locale]) || [] end - # Build full select tag from date type and options + # Build full select tag from date type and options. def build_options_and_select(type, selected, options = {}) build_select(type, build_options(selected, options)) end - # Build select option html from date value and options + # Build select option html from date value and options. # build_options(15, :start => 1, :end => 31) # => "<option value="1">1</option> - # <option value=\"2\">2</option> - # <option value=\"3\">3</option>..." + # <option value="2">2</option> + # <option value="3">3</option>..." + # + # If <tt>:step</tt> options is passed + # build_options(15, :start => 1, :end => 31, :step => 2) + # => "<option value="1">1</option> + # <option value="3">3</option> + # <option value="5">5</option>..." def build_options(selected, options = {}) start = options.delete(:start) || 0 stop = options.delete(:end) || 59 @@ -860,7 +867,7 @@ module ActionView (select_options.join("\n") + "\n").html_safe end - # Builds select tag from date type and html select options + # Builds select tag from date type and html select options. # build_select(:month, "<option value="1">January</option>...") # => "<select id="post_written_on_2i" name="post[written_on(2i)]"> # <option value="1">January</option>... @@ -880,7 +887,7 @@ module ActionView (content_tag(:select, select_html.html_safe, select_options) + "\n").html_safe end - # Builds a prompt option tag with supplied options or from default options + # Builds a prompt option tag with supplied options or from default options. # prompt_option_tag(:month, :prompt => 'Select month') # => "<option value="">Select month</option>" def prompt_option_tag(type, options) @@ -897,7 +904,7 @@ module ActionView prompt ? content_tag(:option, prompt, :value => '') : '' end - # Builds hidden input tag for date part and value + # Builds hidden input tag for date part and value. # build_hidden(:year, 2008) # => "<input id="post_written_on_1i" name="post[written_on(1i)]" type="hidden" value="2008" />" def build_hidden(type, value) @@ -909,7 +916,7 @@ module ActionView }.merge(@html_options.slice(:disabled))) + "\n").html_safe end - # Returns the name attribute for the input tag + # Returns the name attribute for the input tag. # => post[written_on(1i)] def input_name_from_type(type) prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX @@ -923,7 +930,7 @@ module ActionView @options[:discard_type] ? prefix : "#{prefix}[#{field_name}]" end - # Returns the id attribute for the input tag + # Returns the id attribute for the input tag. # => "post_written_on_1i" def input_id_from_type(type) input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '') @@ -940,7 +947,7 @@ module ActionView select.html_safe end - # Returns the separator for a given datetime component + # Returns the separator for a given datetime component. def separator(type) case type when :year diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index b6bb90a3ce..07e2c8d341 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -243,7 +243,7 @@ module ActionView # # === Setting the method # - # You can force the form to use the full array of HTTP verbs by setting + # You can force the form to use the full array of HTTP verbs by setting # # :method => (:get|:post|:put|:delete) # @@ -584,8 +584,8 @@ module ActionView # <% end %> # ... # <% end %> - def fields_for(record, record_object = nil, options = {}, &block) - builder = instantiate_builder(record, record_object, options, &block) + def fields_for(record_name, record_object = nil, options = {}, &block) + builder = instantiate_builder(record_name, record_object, options, &block) output = capture(builder, &block) output.concat builder.hidden_field(:id) if output && options[:hidden_field_id] && !builder.emitted_hidden_id? output @@ -898,16 +898,13 @@ module ActionView private - def instantiate_builder(record, *args, &block) - options = args.extract_options! - record_object = args.shift - - case record + def instantiate_builder(record_name, record_object, options, &block) + case record_name when String, Symbol object = record_object - object_name = record + object_name = record_name else - object = record + object = record_name object_name = ActiveModel::Naming.param_key(object) end @@ -1219,35 +1216,30 @@ module ActionView RUBY_EVAL end - def fields_for(record_or_name_or_array, *args, &block) - if options.has_key?(:index) - index = "[#{options[:index]}]" - elsif defined?(@auto_index) - self.object_name = @object_name.to_s.sub(/\[\]$/,"") - index = "[#{@auto_index}]" - else - index = "" - end - - args << {} unless args.last.is_a?(Hash) - args.last[:builder] ||= options[:builder] - args.last[:parent_builder] = self + def fields_for(record_name, record_object = nil, fields_options = {}, &block) + fields_options, record_object = record_object, nil if record_object.is_a?(Hash) + fields_options[:builder] ||= options[:builder] + fields_options[:parent_builder] = self - case record_or_name_or_array + case record_name when String, Symbol - if nested_attributes_association?(record_or_name_or_array) - return fields_for_with_nested_attributes(record_or_name_or_array, args, block) - else - name = record_or_name_or_array + if nested_attributes_association?(record_name) + return fields_for_with_nested_attributes(record_name, record_object, fields_options, block) end else - object = record_or_name_or_array.is_a?(Array) ? record_or_name_or_array.last : record_or_name_or_array - name = ActiveModel::Naming.param_key(object) - args.unshift(object) + record_object = record_name.is_a?(Array) ? record_name.last : record_name + record_name = ActiveModel::Naming.param_key(record_object) + end + + index = if options.has_key?(:index) + "[#{options[:index]}]" + elsif defined?(@auto_index) + self.object_name = @object_name.to_s.sub(/\[\]$/,"") + "[#{@auto_index}]" end - name = "#{object_name}#{index}[#{name}]" + record_name = "#{object_name}#{index}[#{record_name}]" - @template.fields_for(name, *args, &block) + @template.fields_for(record_name, record_object, fields_options, &block) end def label(method, text = nil, options = {}, &block) @@ -1336,10 +1328,8 @@ module ActionView @object.respond_to?("#{association_name}_attributes=") end - def fields_for_with_nested_attributes(association_name, args, block) + def fields_for_with_nested_attributes(association_name, association, options, block) name = "#{object_name}[#{association_name}_attributes]" - options = args.extract_options! - association = args.shift association = convert_to_model(association) if association.respond_to?(:persisted?) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 7698602022..0aaa690129 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -274,10 +274,10 @@ module ActionView # You can optionally provide html attributes as the last element of the array. # # Examples: - # options_for_select([ "Denmark", ["USA", {:class=>'bold'}], "Sweden" ], ["USA", "Sweden"]) + # options_for_select([ "Denmark", ["USA", {:class => 'bold'}], "Sweden" ], ["USA", "Sweden"]) # <option value="Denmark">Denmark</option>\n<option value="USA" class="bold" selected="selected">USA</option>\n<option value="Sweden" selected="selected">Sweden</option> # - # options_for_select([["Dollar", "$", {:class=>"bold"}], ["Kroner", "DKK", {:onclick => "alert('HI');"}]]) + # options_for_select([["Dollar", "$", {:class => "bold"}], ["Kroner", "DKK", {:onclick => "alert('HI');"}]]) # <option value="$" class="bold">Dollar</option>\n<option value="DKK" onclick="alert('HI');">Kroner</option> # # If you wish to specify disabled option tags, set +selected+ to be a hash, with <tt>:disabled</tt> being either a value diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 9e0f8f32b7..65a98fb27a 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -82,22 +82,22 @@ module ActionView # select_tag "people", options_from_collection_for_select(@people, "id", "name") # # <select id="people" name="people"><option value="1">David</option></select> # - # select_tag "people", "<option>David</option>" + # select_tag "people", "<option>David</option>".html_safe # # => <select id="people" name="people"><option>David</option></select> # - # select_tag "count", "<option>1</option><option>2</option><option>3</option><option>4</option>" + # select_tag "count", "<option>1</option><option>2</option><option>3</option><option>4</option>".html_safe # # => <select id="count" name="count"><option>1</option><option>2</option> # # <option>3</option><option>4</option></select> # - # select_tag "colors", "<option>Red</option><option>Green</option><option>Blue</option>", :multiple => true + # select_tag "colors", "<option>Red</option><option>Green</option><option>Blue</option>".html_safe, :multiple => true # # => <select id="colors" multiple="multiple" name="colors[]"><option>Red</option> # # <option>Green</option><option>Blue</option></select> # - # select_tag "locations", "<option>Home</option><option selected="selected">Work</option><option>Out</option>" + # select_tag "locations", "<option>Home</option><option selected="selected">Work</option><option>Out</option>".html_safe # # => <select id="locations" name="locations"><option>Home</option><option selected='selected'>Work</option> # # <option>Out</option></select> # - # select_tag "access", "<option>Read</option><option>Write</option>", :multiple => true, :class => 'form_input' + # select_tag "access", "<option>Read</option><option>Write</option>".html_safe, :multiple => true, :class => 'form_input' # # => <select class="form_input" id="access" multiple="multiple" name="access[]"><option>Read</option> # # <option>Write</option></select> # @@ -107,7 +107,7 @@ module ActionView # select_tag "people", options_from_collection_for_select(@people, "id", "name"), :prompt => "Select something" # # => <select id="people" name="people"><option value="">Select something</option><option value="1">David</option></select> # - # select_tag "destination", "<option>NYC</option><option>Paris</option><option>Rome</option>", :disabled => true + # select_tag "destination", "<option>NYC</option><option>Paris</option><option>Rome</option>".html_safe, :disabled => true # # => <select disabled="disabled" id="destination" name="destination"><option>NYC</option> # # <option>Paris</option><option>Rome</option></select> def select_tag(name, option_tags = nil, options = {}) diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb index ec9bdd5320..fd8fe417d0 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionpack/lib/action_view/helpers/translation_helper.rb @@ -15,10 +15,10 @@ module ActionView # = Action View Translation Helpers module Helpers module TranslationHelper - # Delegates to I18n#translate but also performs three additional functions. + # Delegates to <tt>I18n#translate</tt> but also performs three additional functions. # - # First, it'll pass the :rescue_format => :html option to I18n so that any - # thrown MissingTranslation messages will be turned into inline spans that + # First, it'll pass the <tt>:rescue_format => :html</tt> option to I18n so that any + # thrown +MissingTranslation+ messages will be turned into inline spans that # # * have a "translation-missing" class set, # * contain the missing key as a title attribute and @@ -54,7 +54,7 @@ module ActionView end alias :t :translate - # Delegates to I18n.localize with no additional functionality. + # Delegates to <tt>I18n.localize</tt> with no additional functionality. def localize(*args) I18n.localize(*args) end diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index ffa9a5bb0b..5488c752cc 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -420,7 +420,7 @@ module ActionView end # Creates a link tag of the given +name+ using a URL created by the set of - # +options+ if +condition+ is true, in which case only the name is + # +options+ if +condition+ is true, otherwise only the name is # returned. To specialize the default behavior, you can pass a block that # accepts the name or the full argument list for +link_to_unless+ (see the examples # in +link_to_unless+). diff --git a/actionpack/lib/action_view/path_set.rb b/actionpack/lib/action_view/path_set.rb index 8b840a6463..e0cb5d6a70 100644 --- a/actionpack/lib/action_view/path_set.rb +++ b/actionpack/lib/action_view/path_set.rb @@ -35,7 +35,7 @@ module ActionView #:nodoc: each_with_index do |path, i| path = path.to_s if path.is_a?(Pathname) next unless path.is_a?(String) - self[i] = FileSystemResolver.new(path) + self[i] = OptimizedFileSystemResolver.new(path) end end end diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 98ecd15aa0..b99d24d281 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -79,9 +79,9 @@ module ActionView # you are handling out-of-band metadata, you are # also responsible for alerting the user to any # problems with converting the user's data to - # the default_internal. + # the <tt>default_internal</tt>. # - # To do so, simply raise the raise WrongEncodingError + # To do so, simply raise the raise +WrongEncodingError+ # as follows: # # raise WrongEncodingError.new( @@ -198,7 +198,7 @@ module ActionView # Among other things, this method is responsible for properly setting # the encoding of the source. Until this point, we assume that the # source is BINARY data. If no additional information is supplied, - # we assume the encoding is the same as Encoding.default_external. + # we assume the encoding is the same as <tt>Encoding.default_external</tt>. # # The user can also specify the encoding via a comment on the first # line of the template (# encoding: NAME-OF-ENCODING). This will work @@ -212,8 +212,8 @@ module ActionView # specifying the encoding. For instance, ERB supports <%# encoding: %> # # Otherwise, after we figure out the correct encoding, we then - # encode the source into Encoding.default_internal. In general, - # this means that templates will be UTF-8 inside of Rails, + # encode the source into <tt>Encoding.default_internal</tt>. + # In general, this means that templates will be UTF-8 inside of Rails, # regardless of the original source encoding. def compile(view, mod) #:nodoc: method_name = self.method_name diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index e246646963..d4448a7b33 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -1,3 +1,4 @@ +require "active_support/core_ext/array/wrap" require "active_support/core_ext/enumerable" module ActionView @@ -29,6 +30,7 @@ module ActionView def initialize(paths, path, prefixes, partial, details, *) @path = path + prefixes = Array.wrap(prefixes) display_paths = paths.compact.map{ |p| p.to_s.inspect }.join(", ") template_type = if partial "partial" diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 870897958a..2b9427ace5 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -10,17 +10,16 @@ module ActionView attr_reader :name, :prefix, :partial, :virtual alias_method :partial?, :partial - def initialize(name, prefix, partial) - @name, @prefix, @partial = name, prefix, partial - rebuild(@name, @prefix, @partial) + def self.build(name, prefix, partial) + virtual = "" + virtual << "#{prefix}/" unless prefix.empty? + virtual << (partial ? "_#{name}" : name) + new name, prefix, partial, virtual end - def rebuild(name, prefix, partial) - @virtual = "" - @virtual << "#{prefix}/" unless prefix.empty? - @virtual << (partial ? "_#{name}" : name) - - self.replace(@virtual) + def initialize(name, prefix, partial, virtual) + @name, @prefix, @partial = name, prefix, partial + super(virtual) end end @@ -60,7 +59,7 @@ module ActionView # Helpers that builds a path. Useful for building virtual paths. def build_path(name, prefix, partial) - Path.new(name, prefix, partial) + Path.build(name, prefix, partial) end # Handles templates caching. If a key is given and caching is on @@ -112,7 +111,8 @@ module ActionView end end - class PathResolver < Resolver + # An abstract class that implements a Resolver with path semantics. + class PathResolver < Resolver #:nodoc: EXTENSIONS = [:locale, :formats, :handlers] DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{.:handlers,}" @@ -124,13 +124,12 @@ module ActionView private def find_templates(name, prefix, partial, details) - path = build_path(name, prefix, partial) - extensions = Hash[EXTENSIONS.map { |ext| [ext, details[ext]] }.flatten(0)] - query(path, extensions, details[:formats]) + path = Path.build(name, prefix, partial) + query(path, details, details[:formats]) end - def query(path, exts, formats) - query = build_query(path, exts) + def query(path, details, formats) + query = build_query(path, details) templates = [] sanitizer = Hash.new { |h,k| h[k] = Dir["#{File.dirname(k)}/*"] } @@ -138,7 +137,7 @@ module ActionView next if File.directory?(p) || !sanitizer[p].include?(p) handler, format = extract_handler_and_format(p, formats) - contents = File.open(p, "rb") {|io| io.read } + contents = File.open(p, "rb") { |io| io.read } templates << Template.new(contents, File.expand_path(p), handler, :virtual_path => path.virtual, :format => format, :updated_at => mtime(p)) @@ -147,18 +146,15 @@ module ActionView templates end - # Helper for building query glob string based on resolver's pattern. - def build_query(path, exts) + # Helper for building query glob string based on resolver's pattern. + def build_query(path, details) query = @pattern.dup query.gsub!(/\:prefix(\/)?/, path.prefix.empty? ? "" : "#{path.prefix}\\1") # prefix can be empty... query.gsub!(/\:action/, path.partial? ? "_#{path.name}" : path.name) - exts.each { |ext, variants| + details.each do |ext, variants| query.gsub!(/\:#{ext}/, "{#{variants.compact.uniq.join(',')}}") - } - - query.gsub!('.{html,', '.{html,text.html,') - query.gsub!('.{text,', '.{text,text.plain,') + end File.expand_path(query, @path) end @@ -235,9 +231,25 @@ module ActionView alias :== :eql? end + # An Optimized resolver for Rails' most common case. + class OptimizedFileSystemResolver < FileSystemResolver #:nodoc: + def build_query(path, details) + exts = EXTENSIONS.map { |ext| details[ext] } + query = File.join(@path, path) + + exts.each do |ext| + query << "{" + ext.compact.each { |e| query << ".#{e}," } + query << "}" + end + + query + end + end + # The same as FileSystemResolver but does not allow templates to store # a virtual path since it is invalid for such resolvers. - class FallbackFileSystemResolver < FileSystemResolver + class FallbackFileSystemResolver < FileSystemResolver #:nodoc: def self.instances [new(""), new("/")] end diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb index 9c10decd60..8cee3babe2 100644 --- a/actionpack/lib/sprockets/railtie.rb +++ b/actionpack/lib/sprockets/railtie.rb @@ -34,12 +34,12 @@ module Sprockets app.assets = asset_environment(app) ActiveSupport.on_load(:action_view) do - app.assets.context.instance_eval do + app.assets.context_class.instance_eval do include ::ActionView::Helpers::SprocketsHelper end end - app.routes.append do + app.routes.prepend do mount app.assets => assets.prefix end @@ -91,7 +91,7 @@ module Sprockets compressor when :yui require 'yui/compressor' - YUI::JavaScriptCompressor.new(:munge => true) + YUI::CssCompressor.new else sym end diff --git a/actionpack/test/activerecord/controller_runtime_test.rb b/actionpack/test/activerecord/controller_runtime_test.rb index 7931da3741..b87b9f9c47 100644 --- a/actionpack/test/activerecord/controller_runtime_test.rb +++ b/actionpack/test/activerecord/controller_runtime_test.rb @@ -11,6 +11,10 @@ class ControllerRuntimeLogSubscriberTest < ActionController::TestCase def show render :inline => "<%= Project.all %>" end + + def zero + render :inline => "Zero DB runtime" + end end include ActiveSupport::LogSubscriber::TestHelper @@ -37,6 +41,15 @@ class ControllerRuntimeLogSubscriberTest < ActionController::TestCase wait assert_equal 2, @logger.logged(:info).size - assert_match(/\(Views: [\d.]+ms | ActiveRecord: [\d.]+ms\)/, @logger.logged(:info)[1]) + assert_match(/\(Views: [\d.]+ms \| ActiveRecord: [\d.]+ms\)/, @logger.logged(:info)[1]) + end + + def test_runtime_reset_before_requests + ActiveRecord::LogSubscriber.runtime += 12345 + get :zero + wait + + assert_equal 2, @logger.logged(:info).size + assert_match(/\(Views: [\d.]+ms \| ActiveRecord: 0.0ms\)/, @logger.logged(:info)[1]) end end diff --git a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb index 99f09286ff..97be5a5bb0 100644 --- a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb +++ b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb @@ -36,7 +36,7 @@ class RenderPartialWithRecordIdentificationController < ActionController::Base end def render_with_record_collection - @developers = Developer.find(:all) + @developers = Developer.all render :partial => @developers end diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb index 548cd02dc0..a50065bcc7 100644 --- a/actionpack/test/controller/params_wrapper_test.rb +++ b/actionpack/test/controller/params_wrapper_test.rb @@ -2,7 +2,21 @@ require 'abstract_unit' module Admin; class User; end; end +module ParamsWrapperTestHelp + def with_default_wrapper_options(&block) + @controller.class._wrapper_options = {:format => [:json]} + @controller.class.inherited(@controller.class) + yield + end + + def assert_parameters(expected) + assert_equal expected, self.class.controller_class.last_parameters + end +end + class ParamsWrapperTest < ActionController::TestCase + include ParamsWrapperTestHelp + class UsersController < ActionController::Base class << self attr_accessor :last_parameters @@ -133,8 +147,8 @@ class ParamsWrapperTest < ActionController::TestCase end def test_derived_wrapped_keys_from_matching_model - User.expects(:respond_to?).with(:column_names).returns(true) - User.expects(:column_names).returns(["username"]) + User.expects(:respond_to?).with(:attribute_names).returns(true) + User.expects(:attribute_names).twice.returns(["username"]) with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' @@ -145,8 +159,8 @@ class ParamsWrapperTest < ActionController::TestCase def test_derived_wrapped_keys_from_specified_model with_default_wrapper_options do - Person.expects(:respond_to?).with(:column_names).returns(true) - Person.expects(:column_names).returns(["username"]) + Person.expects(:respond_to?).with(:attribute_names).returns(true) + Person.expects(:attribute_names).twice.returns(["username"]) UsersController.wrap_parameters Person @@ -156,42 +170,52 @@ class ParamsWrapperTest < ActionController::TestCase end end - private - def with_default_wrapper_options(&block) - @controller.class._wrapper_options = {:format => [:json]} - @controller.class.inherited(@controller.class) - yield - end + def test_not_wrapping_abstract_model + User.expects(:respond_to?).with(:attribute_names).returns(true) + User.expects(:attribute_names).returns([]) - def assert_parameters(expected) - assert_equal expected, UsersController.last_parameters + with_default_wrapper_options do + @request.env['CONTENT_TYPE'] = 'application/json' + post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } + assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu', 'title' => 'Developer' }}) end + end end class NamespacedParamsWrapperTest < ActionController::TestCase - module Admin - class UsersController < ActionController::Base - class << self - attr_accessor :last_parameters - end + include ParamsWrapperTestHelp - def parse - self.class.last_parameters = request.params.except(:controller, :action) - head :ok + module Admin + module Users + class UsersController < ActionController::Base; + class << self + attr_accessor :last_parameters + end + + def parse + self.class.last_parameters = request.params.except(:controller, :action) + head :ok + end end end end - class Sample - def self.column_names + class SampleOne + def self.attribute_names ["username"] end end - tests Admin::UsersController + class SampleTwo + def self.attribute_names + ["title"] + end + end + + tests Admin::Users::UsersController def teardown - Admin::UsersController.last_parameters = nil + Admin::Users::UsersController.last_parameters = nil end def test_derived_name_from_controller @@ -203,7 +227,7 @@ class NamespacedParamsWrapperTest < ActionController::TestCase end def test_namespace_lookup_from_model - Admin.const_set(:User, Class.new(Sample)) + Admin.const_set(:User, Class.new(SampleOne)) begin with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' @@ -216,31 +240,48 @@ class NamespacedParamsWrapperTest < ActionController::TestCase end def test_hierarchy_namespace_lookup_from_model - # Make sure that we cleanup ::Admin::User - admin_user_constant = ::Admin::User - ::Admin.send :remove_const, :User - - Object.const_set(:User, Class.new(Sample)) + Object.const_set(:User, Class.new(SampleTwo)) begin with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }}) + assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'title' => 'Developer' }}) end ensure Object.send :remove_const, :User - ::Admin.const_set(:User, admin_user_constant) end end - private - def with_default_wrapper_options(&block) - @controller.class._wrapper_options = {:format => [:json]} - @controller.class.inherited(@controller.class) - yield +end + +class AnonymousControllerParamsWrapperTest < ActionController::TestCase + include ParamsWrapperTestHelp + + tests(Class.new(ActionController::Base) do + class << self + attr_accessor :last_parameters + end + + def parse + self.class.last_parameters = request.params.except(:controller, :action) + head :ok end + end) - def assert_parameters(expected) - assert_equal expected, Admin::UsersController.last_parameters + def test_does_not_implicitly_wrap_params + with_default_wrapper_options do + @request.env['CONTENT_TYPE'] = 'application/json' + post :parse, { 'username' => 'sikachu' } + assert_parameters({ 'username' => 'sikachu' }) + end + end + + def test_does_wrap_params_if_name_provided + with_default_wrapper_options do + @controller.class.wrap_parameters(:name => "guest") + @request.env['CONTENT_TYPE'] = 'application/json' + post :parse, { 'username' => 'sikachu' } + assert_parameters({ 'username' => 'sikachu', 'guest' => { 'username' => 'sikachu' }}) end + end end diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb index 31f4bf3a76..dea80ed887 100644 --- a/actionpack/test/controller/request_forgery_protection_test.rb +++ b/actionpack/test/controller/request_forgery_protection_test.rb @@ -81,22 +81,25 @@ module RequestForgeryProtectionTests @token = "cf50faa3fe97702ca1ae" ActiveSupport::SecureRandom.stubs(:base64).returns(@token) - ActionController::Base.request_forgery_protection_token = :authenticity_token + ActionController::Base.request_forgery_protection_token = :custom_authenticity_token end + def teardown + ActionController::Base.request_forgery_protection_token = nil + end def test_should_render_form_with_token_tag assert_not_blocked do get :index end - assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token + assert_select 'form>div>input[name=?][value=?]', 'custom_authenticity_token', @token end def test_should_render_button_to_with_token_tag assert_not_blocked do get :show_button end - assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token + assert_select 'form>div>input[name=?][value=?]', 'custom_authenticity_token', @token end def test_should_allow_get @@ -128,15 +131,15 @@ module RequestForgeryProtectionTests end def test_should_allow_post_with_token - assert_not_blocked { post :index, :authenticity_token => @token } + assert_not_blocked { post :index, :custom_authenticity_token => @token } end def test_should_allow_put_with_token - assert_not_blocked { put :index, :authenticity_token => @token } + assert_not_blocked { put :index, :custom_authenticity_token => @token } end def test_should_allow_delete_with_token - assert_not_blocked { delete :index, :authenticity_token => @token } + assert_not_blocked { delete :index, :custom_authenticity_token => @token } end def test_should_allow_post_with_token_in_header @@ -172,10 +175,18 @@ end class RequestForgeryProtectionControllerTest < ActionController::TestCase include RequestForgeryProtectionTests + setup do + ActionController::Base.request_forgery_protection_token = :custom_authenticity_token + end + + teardown do + ActionController::Base.request_forgery_protection_token = nil + end + test 'should emit a csrf-param meta tag and a csrf-token meta tag' do ActiveSupport::SecureRandom.stubs(:base64).returns(@token + '<=?') get :meta - assert_select 'meta[name=?][content=?]', 'csrf-param', 'authenticity_token' + assert_select 'meta[name=?][content=?]', 'csrf-param', 'custom_authenticity_token' assert_select 'meta[name=?][content=?]', 'csrf-token', 'cf50faa3fe97702ca1ae<=?' end end diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index d128006404..25b1b4f745 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -358,6 +358,13 @@ class RequestTest < ActiveSupport::TestCase assert request.head? end + test "post masquerading as put" do + request = stub_request 'REQUEST_METHOD' => 'PUT', "rack.methodoverride.original_method" => "POST" + assert_equal "POST", request.method + assert_equal "PUT", request.request_method + assert request.put? + end + test "xml format" do request = stub_request request.expects(:parameters).at_least_once.returns({ :format => 'xml' }) diff --git a/actionpack/test/dispatch/response_body_is_proc_test.rb b/actionpack/test/dispatch/response_body_is_proc_test.rb new file mode 100644 index 0000000000..fd94832624 --- /dev/null +++ b/actionpack/test/dispatch/response_body_is_proc_test.rb @@ -0,0 +1,37 @@ +require 'abstract_unit' + +class ResponseBodyIsProcTest < ActionDispatch::IntegrationTest + class TestController < ActionController::Base + def test + self.response_body = proc { |response, output| + output.write 'Hello' + } + end + end + + def test_simple_get + with_test_route_set do + assert_deprecated do + get '/test' + end + assert_response :success + assert_equal 'Hello', response.body + end + end + + private + + def with_test_route_set(options = {}) + with_routing do |set| + set.draw do + match ':action', :to => ::ResponseBodyIsProcTest::TestController + end + + @app = self.class.build_app(set) do |middleware| + middleware.delete "ActionDispatch::ShowExceptions" + end + + yield + end + end +end diff --git a/actionpack/test/template/capture_helper_test.rb b/actionpack/test/template/capture_helper_test.rb index 592c7da060..a9157e711c 100644 --- a/actionpack/test/template/capture_helper_test.rb +++ b/actionpack/test/template/capture_helper_test.rb @@ -38,7 +38,15 @@ class CaptureHelperTest < ActionView::TestCase assert_equal '<em>bar</em>', string end - def test_content_for + def test_capture_used_for_read + content_for :foo, "foo" + assert_equal "foo", content_for(:foo) + + content_for(:bar){ "bar" } + assert_equal "bar", content_for(:bar) + end + + def test_content_for_question_mark assert ! content_for?(:title) content_for :title, 'title' assert content_for?(:title) @@ -49,14 +57,14 @@ class CaptureHelperTest < ActionView::TestCase assert !content_for?(:title) provide :title, "hi" assert content_for?(:title) - assert_equal "hi", @view_flow.get(:title) + assert_equal "hi", content_for(:title) provide :title, "<p>title</p>" - assert_equal "hi<p>title</p>", @view_flow.get(:title) + assert_equal "hi<p>title</p>", content_for(:title) @view_flow = ActionView::OutputFlow.new provide :title, "hi" provide :title, "<p>title</p>".html_safe - assert_equal "hi<p>title</p>", @view_flow.get(:title) + assert_equal "hi<p>title</p>", content_for(:title) end def test_with_output_buffer_swaps_the_output_buffer_given_no_argument diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index c25c850eb3..286bfb4d04 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -1725,6 +1725,20 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end + def test_form_for_and_fields_for_with_non_nested_association_and_without_object + form_for(@post) do |f| + concat f.fields_for(:category) { |c| + concat c.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', 'put') do + "<input name='post[category][name]' type='text' size='30' id='post_category_name' />" + end + + assert_dom_equal expected, output_buffer + end + class LabelledFormBuilder < ActionView::Helpers::FormBuilder (field_helpers - %w(hidden_field)).each do |selector| class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 diff --git a/actionpack/test/template/lookup_context_test.rb b/actionpack/test/template/lookup_context_test.rb index f34a40795a..47b70f05ab 100644 --- a/actionpack/test/template/lookup_context_test.rb +++ b/actionpack/test/template/lookup_context_test.rb @@ -256,4 +256,13 @@ class TestMissingTemplate < ActiveSupport::TestCase end assert_match %r{Missing partial parent/foo, child/foo with .* Searched in:\n \* "/Path/to/views"\n}, e.message end + + test "if a single prefix is passed as a string and the lookup fails, MissingTemplate accepts it" do + e = assert_raise ActionView::MissingTemplate do + details = {:handlers=>[], :formats=>[], :locale=>[]} + @lookup_context.view_paths.find("foo", "parent", true, details) + end + assert_match %r{Missing partial parent/foo with .* Searched in:\n \* "/Path/to/views"\n}, e.message + end + end diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index d4e912c410..86d08a43a5 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -325,7 +325,7 @@ class CachedViewRenderTest < ActiveSupport::TestCase # Ensure view path cache is primed def setup view_paths = ActionController::Base.view_paths - assert_equal ActionView::FileSystemResolver, view_paths.first.class + assert_equal ActionView::OptimizedFileSystemResolver, view_paths.first.class setup_view(view_paths) end |