aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb8
-rw-r--r--actionpack/lib/action_controller/metal/helpers.rb3
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb8
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb38
-rw-r--r--actionpack/lib/action_controller/metal/rendering.rb47
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb10
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb4
-rw-r--r--actionpack/lib/action_controller/railties/paths.rb4
-rw-r--r--actionpack/lib/action_controller/test_case.rb6
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb4
-rw-r--r--actionpack/lib/action_dispatch/http/mime_negotiation.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb37
-rw-r--r--actionpack/lib/action_dispatch/http/upload.rb10
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb60
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb13
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb139
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb30
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb7
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb4
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb7
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb4
-rw-r--r--actionpack/lib/action_view/partials.rb5
-rw-r--r--actionpack/lib/action_view/template.rb8
23 files changed, 299 insertions, 163 deletions
diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
index 475785a4b4..91b75273fa 100644
--- a/actionpack/lib/abstract_controller/rendering.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -119,7 +119,7 @@ module AbstractController
controller_path
end
- private
+ private
# This method should return a hash with assigns.
# You can overwrite this configuration per controller.
@@ -128,7 +128,7 @@ module AbstractController
hash = {}
variables = instance_variable_names
variables -= protected_instance_variables if respond_to?(:protected_instance_variables)
- variables.each { |name| hash[name.to_s[1..-1]] = instance_variable_get(name) }
+ variables.each { |name| hash[name.to_s[1, name.length]] = instance_variable_get(name) }
hash
end
@@ -138,13 +138,13 @@ module AbstractController
case action
when NilClass
when Hash
- options, action = action, nil
+ options = action
when String, Symbol
action = action.to_s
key = action.include?(?/) ? :file : :action
options[key] = action
else
- options.merge!(:partial => action)
+ options[:partial] = action
end
options
diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb
index d14831b763..91a88ab68a 100644
--- a/actionpack/lib/action_controller/metal/helpers.rb
+++ b/actionpack/lib/action_controller/metal/helpers.rb
@@ -53,8 +53,9 @@ module ActionController
include AbstractController::Helpers
included do
- config_accessor :helpers_path
+ config_accessor :helpers_path, :include_all_helpers
self.helpers_path ||= []
+ self.include_all_helpers = true
end
module ClassMethods
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index f7dd0dcb69..9ba37134b8 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -258,9 +258,8 @@ module ActionController #:nodoc:
# nil if :not_acceptable was sent to the client.
#
def retrieve_response_from_mimes(mimes=nil, &block)
- collector = Collector.new { default_render }
mimes ||= collect_mimes_from_class_level
- mimes.each { |mime| collector.send(mime) }
+ collector = Collector.new(mimes) { default_render }
block.call(collector) if block_given?
if format = request.negotiate_mime(collector.order)
@@ -277,8 +276,9 @@ module ActionController #:nodoc:
include AbstractController::Collector
attr_accessor :order
- def initialize(&block)
+ def initialize(mimes, &block)
@order, @responses, @default_response = [], {}, block
+ mimes.each { |mime| send(mime) }
end
def any(*args, &block)
@@ -291,7 +291,7 @@ module ActionController #:nodoc:
alias :all :any
def custom(mime_type, &block)
- mime_type = mime_type.is_a?(Mime::Type) ? mime_type : Mime::Type.lookup(mime_type.to_s)
+ mime_type = Mime::Type.lookup(mime_type.to_s) unless mime_type.is_a?(Mime::Type)
@order << mime_type
@responses[mime_type] ||= block
end
diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb
index f9b226b7c9..d6f6ab1855 100644
--- a/actionpack/lib/action_controller/metal/renderers.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -15,30 +15,12 @@ module ActionController
end
module ClassMethods
- def _write_render_options
- renderers = _renderers.map do |name, value|
- <<-RUBY_EVAL
- if options.key?(:#{name})
- _process_options(options)
- return _render_option_#{name}(options.delete(:#{name}), options)
- end
- RUBY_EVAL
- end
-
- class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def _handle_render_options(options)
- #{renderers.join}
- end
- RUBY_EVAL
- end
-
def use_renderers(*args)
new = _renderers.dup
args.each do |key|
new[key] = RENDERERS[key]
end
self._renderers = new.freeze
- _write_render_options
end
alias use_renderer use_renderers
end
@@ -47,31 +29,33 @@ module ActionController
_handle_render_options(options) || super
end
+ def _handle_render_options(options)
+ _renderers.each do |name, value|
+ if options.key?(name.to_sym)
+ _process_options(options)
+ return send("_render_option_#{name}", options.delete(name.to_sym), options)
+ end
+ end
+ nil
+ end
+
RENDERERS = {}
def self.add(key, &block)
define_method("_render_option_#{key}", &block)
RENDERERS[key] = block
- All._write_render_options
end
module All
extend ActiveSupport::Concern
include Renderers
- INCLUDED = []
included do
self._renderers = RENDERERS
- _write_render_options
- INCLUDED << self
- end
-
- def self._write_render_options
- INCLUDED.each(&:_write_render_options)
end
end
add :json do |json, options|
- json = json.to_json(options) unless json.respond_to?(:to_str)
+ json = json.to_json(options) unless json.kind_of?(String)
json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
self.content_type ||= Mime::JSON
self.response_body = json
diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb
index e524e546ad..14cc547dd0 100644
--- a/actionpack/lib/action_controller/metal/rendering.rb
+++ b/actionpack/lib/action_controller/metal/rendering.rb
@@ -20,36 +20,35 @@ module ActionController
private
- # Normalize arguments by catching blocks and setting them on :update.
- def _normalize_args(action=nil, options={}, &blk) #:nodoc:
- options = super
- options[:update] = blk if block_given?
- options
- end
-
- # Normalize both text and status options.
- def _normalize_options(options) #:nodoc:
- if options.key?(:text) && options[:text].respond_to?(:to_text)
- options[:text] = options[:text].to_text
- end
+ # Normalize arguments by catching blocks and setting them on :update.
+ def _normalize_args(action=nil, options={}, &blk) #:nodoc:
+ options = super
+ options[:update] = blk if block_given?
+ options
+ end
- if options[:status]
- options[:status] = Rack::Utils.status_code(options[:status])
- end
+ # Normalize both text and status options.
+ def _normalize_options(options) #:nodoc:
+ if options.key?(:text) && options[:text].respond_to?(:to_text)
+ options[:text] = options[:text].to_text
+ end
- super
+ if options[:status]
+ options[:status] = Rack::Utils.status_code(options[:status])
end
- # Process controller specific options, as status, content-type and location.
- def _process_options(options) #:nodoc:
- status, content_type, location = options.values_at(:status, :content_type, :location)
+ super
+ end
- self.status = status if status
- self.content_type = content_type if content_type
- self.headers["Location"] = url_for(location) if location
+ # Process controller specific options, as status, content-type and location.
+ def _process_options(options) #:nodoc:
+ status, content_type, location = options.values_at(:status, :content_type, :location)
- super
- end
+ self.status = status if status
+ self.content_type = content_type if content_type
+ self.headers["Location"] = url_for(location) if location
+ super
+ 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 02f577647e..148efbb081 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -53,9 +53,13 @@ module ActionController #:nodoc:
# class FooController < ApplicationController
# protect_from_forgery :except => :index
#
- # # you can disable csrf protection on controller-by-controller basis:
- # skip_before_filter :verify_authenticity_token
- # end
+ # You can disable csrf protection on controller-by-controller basis:
+ #
+ # skip_before_filter :verify_authenticity_token
+ #
+ # It can also be disabled for specific controller actions:
+ #
+ # skip_before_filter :verify_authenticity_token, :except => [:create]
#
# Valid Options:
#
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 333eeaeffb..6fc0cf1fb8 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -6,7 +6,8 @@ module ActionController
def url_options
@_url_options ||= super.reverse_merge(
- :host => request.host_with_port,
+ :host => request.host,
+ :port => request.optional_port,
:protocol => request.protocol,
:_path_segments => request.symbolized_path_parameters
).freeze
@@ -20,5 +21,6 @@ module ActionController
@_url_options
end
end
+
end
end
diff --git a/actionpack/lib/action_controller/railties/paths.rb b/actionpack/lib/action_controller/railties/paths.rb
index 7a59d4f2f3..699c44c62c 100644
--- a/actionpack/lib/action_controller/railties/paths.rb
+++ b/actionpack/lib/action_controller/railties/paths.rb
@@ -13,7 +13,9 @@ module ActionController
end
klass.helpers_path = paths
- klass.helper :all if klass.superclass == ActionController::Base
+ if klass.superclass == ActionController::Base && ActionController::Base.include_all_helpers
+ klass.helper :all
+ end
end
end
end
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 2b2f647d32..0f43527a56 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -1,6 +1,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'
module ActionController
module TemplateAssertions
@@ -325,11 +326,11 @@ module ActionController
def controller_class=(new_class)
prepare_controller_class(new_class) if new_class
- write_inheritable_attribute(:controller_class, new_class)
+ self._controller_class = new_class
end
def controller_class
- if current_controller_class = read_inheritable_attribute(:controller_class)
+ if current_controller_class = self._controller_class
current_controller_class
else
self.controller_class = determine_default_controller_class(name)
@@ -442,6 +443,7 @@ module ActionController
included do
include ActionController::TemplateAssertions
include ActionDispatch::Assertions
+ class_attribute :_controller_class
setup :setup_controller_request_and_response
end
diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
index dceddb9b80..3e5d23b5c1 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
@@ -1,5 +1,5 @@
require 'set'
-require 'active_support/core_ext/class/inheritable_attributes'
+require 'active_support/core_ext/class/attribute'
module HTML
class Sanitizer
@@ -60,7 +60,7 @@ module HTML
class WhiteListSanitizer < Sanitizer
[:protocol_separator, :uri_attributes, :allowed_attributes, :allowed_tags, :allowed_protocols, :bad_tags,
:allowed_css_properties, :allowed_css_keywords, :shorthand_css_properties].each do |attr|
- class_inheritable_accessor attr, :instance_writer => false
+ class_attribute attr, :instance_writer => false
end
# A regular expression of the valid characters used to separate protocols like
diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
index b959aa258e..68ba1a81b5 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -36,19 +36,21 @@ module ActionDispatch
#
# GET /posts/5.xml | request.format => Mime::XML
# GET /posts/5.xhtml | request.format => Mime::HTML
- # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
+ # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first
#
def format(view_path = [])
formats.first
end
+ BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
+
def formats
accept = @env['HTTP_ACCEPT']
@env["action_dispatch.request.formats"] ||=
if parameters[:format]
Array(Mime[parameters[:format]])
- elsif xhr? || (accept && accept !~ /,\s*\*\/\*/)
+ elsif xhr? || (accept && accept !~ BROWSER_LIKE_ACCEPTS)
accepts
else
[Mime::HTML]
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index 8f1c9b6691..08eab5634a 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -80,6 +80,9 @@ module Mime
end
class << self
+
+ TRAILING_STAR_REGEXP = /(text|application)\/\*/
+
def lookup(string)
LOOKUP[string]
end
@@ -105,7 +108,11 @@ module Mime
def parse(accept_header)
if accept_header !~ /,/
- [Mime::Type.lookup(accept_header)]
+ if accept_header =~ TRAILING_STAR_REGEXP
+ parse_data_with_trailing_star($1)
+ else
+ [Mime::Type.lookup(accept_header)]
+ end
else
# keep track of creation order to keep the subsequent sort stable
list = []
@@ -113,7 +120,11 @@ module Mime
params, q = header.split(/;\s*q=/)
if params
params.strip!
- list << AcceptItem.new(index, params, q) unless params.empty?
+ if params =~ TRAILING_STAR_REGEXP
+ parse_data_with_trailing_star($1).each { |m| list << AcceptItem.new(index, m.to_s, q) }
+ else
+ list << AcceptItem.new(index, params, q) unless params.empty?
+ end
end
end
list.sort!
@@ -160,6 +171,28 @@ module Mime
list
end
end
+
+ # input: 'text'
+ # returend value: [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT]
+ #
+ # input: 'application'
+ # returend value: [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::URL_ENCODED_FORM
+ def parse_data_with_trailing_star(input)
+ keys = Mime::LOOKUP.keys.select{|k| k.include?(input)}
+ Mime::LOOKUP.values_at(*keys).uniq
+ end
+
+ # This method is opposite of register method.
+ #
+ # Usage:
+ #
+ # Mime::Type.unregister("text/x-mobile", :mobile)
+ def unregister(string, symbol)
+ EXTENSION_LOOKUP.delete(symbol.to_s)
+ LOOKUP.delete(string)
+ symbol = symbol.to_s.upcase.intern
+ Mime.module_eval { remove_const(symbol) if const_defined?(symbol) }
+ end
end
def initialize(string, symbol = nil, synonyms = [])
diff --git a/actionpack/lib/action_dispatch/http/upload.rb b/actionpack/lib/action_dispatch/http/upload.rb
index 84e58d7d6a..37effade4f 100644
--- a/actionpack/lib/action_dispatch/http/upload.rb
+++ b/actionpack/lib/action_dispatch/http/upload.rb
@@ -1,5 +1,3 @@
-require 'active_support/core_ext/object/blank'
-
module ActionDispatch
module Http
class UploadedFile
@@ -13,6 +11,14 @@ module ActionDispatch
raise(ArgumentError, ':tempfile is required') unless @tempfile
end
+ def open
+ @tempfile.open
+ end
+
+ def path
+ @tempfile.path
+ end
+
def read(*args)
@tempfile.read(*args)
end
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index 9c9eed2c6d..1e7054f381 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -4,6 +4,27 @@ module ActionDispatch
mattr_accessor :tld_length
self.tld_length = 1
+ def self.extract_domain(host, tld_length = @@tld_length)
+ return nil unless named_host?(host)
+
+ host.split('.').last(1 + tld_length).join('.')
+ end
+
+ def self.extract_subdomains(host, tld_length = @@tld_length)
+ return [] unless named_host?(host)
+ parts = host.split('.')
+ parts[0..-(tld_length+2)]
+ end
+
+ def self.extract_subdomain(host, tld_length = @@tld_length)
+ extract_subdomains(host, tld_length).join('.')
+ end
+
+ def self.named_host?(host)
+ !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
+ end
+
+
# Returns the complete URL used for this request.
def url
protocol + host_with_port + fullpath
@@ -36,10 +57,12 @@ module ActionDispatch
# Returns the port number of this request as an integer.
def port
- if raw_host_with_port =~ /:(\d+)$/
- $1.to_i
- else
- standard_port
+ @port ||= begin
+ if raw_host_with_port =~ /:(\d+)$/
+ $1.to_i
+ else
+ standard_port
+ end
end
end
@@ -56,10 +79,16 @@ module ActionDispatch
port == standard_port
end
- # Returns a \port suffix like ":8080" if the \port number of this request
+ # Returns a number \port suffix like 8080 if the \port number of this request
# is not the default HTTP \port 80 or HTTPS \port 443.
+ def optional_port
+ standard_port? ? nil : port
+ end
+
+ # Returns a string \port suffix, including colon, like ":8080" if the \port
+ # number of this request is not the default HTTP \port 80 or HTTPS \port 443.
def port_string
- port == standard_port ? '' : ":#{port}"
+ standard_port? ? '' : ":#{port}"
end
def server_port
@@ -69,9 +98,7 @@ module ActionDispatch
# Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
# a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
def domain(tld_length = @@tld_length)
- return nil unless named_host?(host)
-
- host.split('.').last(1 + tld_length).join('.')
+ ActionDispatch::Http::URL.extract_domain(host, tld_length)
end
# Returns all the \subdomains as an array, so <tt>["dev", "www"]</tt> would be
@@ -79,20 +106,17 @@ module ActionDispatch
# such as 2 to catch <tt>["www"]</tt> instead of <tt>["www", "rubyonrails"]</tt>
# in "www.rubyonrails.co.uk".
def subdomains(tld_length = @@tld_length)
- return [] unless named_host?(host)
- parts = host.split('.')
- parts[0..-(tld_length+2)]
+ ActionDispatch::Http::URL.extract_subdomains(host, tld_length)
end
+ # 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>
+ # in "www.rubyonrails.co.uk".
def subdomain(tld_length = @@tld_length)
- subdomains(tld_length).join('.')
+ subdomains(tld_length)
end
- private
-
- def named_host?(host)
- !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
- end
end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index c4c2e1acd7..b0a4e3d949 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -16,17 +16,23 @@ module ActionDispatch
# Examples for writing:
#
# # Sets a simple session cookie.
+ # # This cookie will be deleted when the user's browser is closed.
# cookies[:user_name] = "david"
#
+ # # Assign an array of values to a cookie.
+ # cookies[:lat_lon] = [47.68, -122.37]
+ #
# # Sets a cookie that expires in 1 hour.
# cookies[:login] = { :value => "XJ-122", :expires => 1.hour.from_now }
#
# # Sets a signed cookie, which prevents a user from tampering with its value.
- # # You must specify a value in ActionController::Base.cookie_verifier_secret.
- # cookies.signed[:remember_me] = [current_user.id, current_user.salt]
+ # # The cookie is signed by your app's <tt>config.secret_token</tt> value.
+ # # Rails generates this value by default when you create a new Rails app.
+ # cookies.signed[:user_id] = current_user.id
#
# # Sets a "permanent" cookie (which expires in 20 years from now).
# cookies.permanent[:login] = "XJ-122"
+ #
# # You can also chain these methods:
# cookies.permanent.signed[:login] = "XJ-122"
#
@@ -34,6 +40,7 @@ module ActionDispatch
#
# cookies[:user_name] # => "david"
# cookies.size # => 2
+ # cookies[:lat_lon] # => [47.68, -122.37]
#
# Example for deleting:
#
@@ -275,7 +282,7 @@ module ActionDispatch
"integrity hash for cookie session data. Use " +
"config.secret_token = \"some secret phrase of at " +
"least #{SECRET_MIN_LENGTH} characters\"" +
- "in config/application.rb"
+ "in config/initializers/secret_token.rb"
end
if secret.length < SECRET_MIN_LENGTH
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 879ccc5791..01826fcede 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -439,13 +439,13 @@ module ActionDispatch
# This will create a number of routes for each of the posts and comments
# controller. For Admin::PostsController, Rails will create:
#
- # GET /admin/photos
- # GET /admin/photos/new
- # POST /admin/photos
- # GET /admin/photos/1
- # GET /admin/photos/1/edit
- # PUT /admin/photos/1
- # DELETE /admin/photos/1
+ # GET /admin/posts
+ # GET /admin/posts/new
+ # POST /admin/posts
+ # GET /admin/posts/1
+ # GET /admin/posts/1/edit
+ # PUT /admin/posts/1
+ # DELETE /admin/posts/1
#
# If you want to route /posts (without the prefix /admin) to
# Admin::PostsController, you could use
@@ -473,21 +473,19 @@ module ActionDispatch
# not use scope. In the last case, the following paths map to
# PostsController:
#
- # GET /admin/photos
- # GET /admin/photos/new
- # POST /admin/photos
- # GET /admin/photos/1
- # GET /admin/photos/1/edit
- # PUT /admin/photos/1
- # DELETE /admin/photos/1
+ # GET /admin/posts
+ # GET /admin/posts/new
+ # POST /admin/posts
+ # GET /admin/posts/1
+ # GET /admin/posts/1/edit
+ # PUT /admin/posts/1
+ # DELETE /admin/posts/1
module Scoping
def initialize(*args) #:nodoc:
@scope = {}
super
end
- # Used to route <tt>/photos</tt> (without the prefix <tt>/admin</tt>)
- # to Admin::PostsController:
# === Supported options
# [:module]
# If you want to route /posts (without the prefix /admin) to
@@ -588,13 +586,13 @@ module ActionDispatch
#
# This generates the following routes:
#
- # admin_posts GET /admin/posts(.:format) {:action=>"index", :controller=>"admin/posts"}
- # admin_posts POST /admin/posts(.:format) {:action=>"create", :controller=>"admin/posts"}
- # new_admin_post GET /admin/posts/new(.:format) {:action=>"new", :controller=>"admin/posts"}
- # edit_admin_post GET /admin/posts/:id/edit(.:format) {:action=>"edit", :controller=>"admin/posts"}
- # admin_post GET /admin/posts/:id(.:format) {:action=>"show", :controller=>"admin/posts"}
- # admin_post PUT /admin/posts/:id(.:format) {:action=>"update", :controller=>"admin/posts"}
- # admin_post DELETE /admin/posts/:id(.:format) {:action=>"destroy", :controller=>"admin/posts"}
+ # admin_posts GET /admin/posts(.:format) {:action=>"index", :controller=>"admin/posts"}
+ # admin_posts POST /admin/posts(.:format) {:action=>"create", :controller=>"admin/posts"}
+ # new_admin_post GET /admin/posts/new(.:format) {:action=>"new", :controller=>"admin/posts"}
+ # edit_admin_post GET /admin/posts/:id/edit(.:format) {:action=>"edit", :controller=>"admin/posts"}
+ # admin_post GET /admin/posts/:id(.:format) {:action=>"show", :controller=>"admin/posts"}
+ # admin_post PUT /admin/posts/:id(.:format) {:action=>"update", :controller=>"admin/posts"}
+ # admin_post DELETE /admin/posts/:id(.:format) {:action=>"destroy", :controller=>"admin/posts"}
# === Supported options
#
# The +:path+, +:as+, +:module+, +:shallow_path+ and +:shallow_prefix+ all default to the name of the namespace.
@@ -707,61 +705,61 @@ module ActionDispatch
end
private
- def scope_options
+ def scope_options #:nodoc:
@scope_options ||= private_methods.grep(/^merge_(.+)_scope$/) { $1.to_sym }
end
- def merge_path_scope(parent, child)
+ def merge_path_scope(parent, child) #:nodoc:
Mapper.normalize_path("#{parent}/#{child}")
end
- def merge_shallow_path_scope(parent, child)
+ def merge_shallow_path_scope(parent, child) #:nodoc:
Mapper.normalize_path("#{parent}/#{child}")
end
- def merge_as_scope(parent, child)
+ def merge_as_scope(parent, child) #:nodoc:
parent ? "#{parent}_#{child}" : child
end
- def merge_shallow_prefix_scope(parent, child)
+ def merge_shallow_prefix_scope(parent, child) #:nodoc:
parent ? "#{parent}_#{child}" : child
end
- def merge_module_scope(parent, child)
+ def merge_module_scope(parent, child) #:nodoc:
parent ? "#{parent}/#{child}" : child
end
- def merge_controller_scope(parent, child)
+ def merge_controller_scope(parent, child) #:nodoc:
child
end
- def merge_path_names_scope(parent, child)
+ def merge_path_names_scope(parent, child) #:nodoc:
merge_options_scope(parent, child)
end
- def merge_constraints_scope(parent, child)
+ def merge_constraints_scope(parent, child) #:nodoc:
merge_options_scope(parent, child)
end
- def merge_defaults_scope(parent, child)
+ def merge_defaults_scope(parent, child) #:nodoc:
merge_options_scope(parent, child)
end
- def merge_blocks_scope(parent, child)
+ def merge_blocks_scope(parent, child) #:nodoc:
merged = parent ? parent.dup : []
merged << child if child
merged
end
- def merge_options_scope(parent, child)
+ def merge_options_scope(parent, child) #:nodoc:
(parent || {}).except(*override_keys(child)).merge(child)
end
- def merge_shallow_scope(parent, child)
+ def merge_shallow_scope(parent, child) #:nodoc:
child ? true : false
end
- def override_keys(child)
+ def override_keys(child) #:nodoc:
child.key?(:only) || child.key?(:except) ? [:only, :except] : []
end
end
@@ -969,6 +967,22 @@ module ActionDispatch
# GET /photos/:id/edit
# PUT /photos/:id
# DELETE /photos/:id
+ #
+ # Resources can also be nested infinitely by using this block syntax:
+ #
+ # resources :photos do
+ # resources :comments
+ # end
+ #
+ # This generates the following comments routes:
+ #
+ # GET /photos/:id/comments/new
+ # POST /photos/:id/comments
+ # GET /photos/:id/comments/:id
+ # GET /photos/:id/comments/:id/edit
+ # PUT /photos/:id/comments/:id
+ # DELETE /photos/:id/comments/:id
+ #
# === Supported options
# [:path_names]
# Allows you to change the paths of the seven default actions.
@@ -977,6 +991,21 @@ module ActionDispatch
# resources :posts, :path_names => { :new => "brand_new" }
#
# The above example will now change /posts/new to /posts/brand_new
+ #
+ # [:module]
+ # Set the module where the controller can be found. Defaults to nothing.
+ #
+ # resources :posts, :module => "admin"
+ #
+ # All requests to the posts resources will now go to +Admin::PostsController+.
+ #
+ # [:path]
+ #
+ # Set a path prefix for this resource.
+ #
+ # resources :posts, :path => "admin"
+ #
+ # All actions for this resource will now be at +/admin/posts+.
def resources(*resources, &block)
options = resources.extract_options!
@@ -1167,7 +1196,7 @@ module ActionDispatch
@scope[:scope_level_resource]
end
- def apply_common_behavior_for(method, resources, options, &block)
+ def apply_common_behavior_for(method, resources, options, &block) #:nodoc:
if resources.length > 1
resources.each { |r| send(method, r, options, &block) }
return true
@@ -1197,23 +1226,23 @@ module ActionDispatch
false
end
- def action_options?(options)
+ def action_options?(options) #:nodoc:
options[:only] || options[:except]
end
- def scope_action_options?
+ def scope_action_options? #:nodoc:
@scope[:options].is_a?(Hash) && (@scope[:options][:only] || @scope[:options][:except])
end
- def scope_action_options
+ def scope_action_options #:nodoc:
@scope[:options].slice(:only, :except)
end
- def resource_scope?
+ def resource_scope? #:nodoc:
[:resource, :resources].include?(@scope[:scope_level])
end
- def resource_method_scope?
+ def resource_method_scope? #:nodoc:
[:collection, :member, :new].include?(@scope[:scope_level])
end
@@ -1239,7 +1268,7 @@ module ActionDispatch
@scope[:scope_level_resource] = old_resource
end
- def resource_scope(resource)
+ def resource_scope(resource) #:nodoc:
with_scope_level(resource.is_a?(SingletonResource) ? :resource : :resources, resource) do
scope(parent_resource.resource_scope) do
yield
@@ -1247,30 +1276,30 @@ module ActionDispatch
end
end
- def nested_options
+ def nested_options #:nodoc:
{}.tap do |options|
options[:as] = parent_resource.member_name
options[:constraints] = { "#{parent_resource.singular}_id".to_sym => id_constraint } if id_constraint?
end
end
- def id_constraint?
+ def id_constraint? #:nodoc:
@scope[:constraints] && @scope[:constraints][:id].is_a?(Regexp)
end
- def id_constraint
+ def id_constraint #:nodoc:
@scope[:constraints][:id]
end
- def canonical_action?(action, flag)
+ def canonical_action?(action, flag) #:nodoc:
flag && resource_method_scope? && CANONICAL_ACTIONS.include?(action.to_s)
end
- def shallow_scoping?
+ def shallow_scoping? #:nodoc:
shallow? && @scope[:scope_level] == :member
end
- def path_for_action(action, path)
+ def path_for_action(action, path) #:nodoc:
prefix = shallow_scoping? ?
"#{@scope[:shallow_path]}/#{parent_resource.path}/:id" : @scope[:path]
@@ -1281,11 +1310,11 @@ module ActionDispatch
end
end
- def action_path(name, path = nil)
+ def action_path(name, path = nil) #:nodoc:
path || @scope[:path_names][name.to_sym] || name.to_s
end
- def prefix_name_for_action(as, action)
+ def prefix_name_for_action(as, action) #:nodoc:
if as
as.to_s
elsif !canonical_action?(action, @scope[:scope_level])
@@ -1293,12 +1322,14 @@ module ActionDispatch
end
end
- def name_for_action(as, action)
+ def name_for_action(as, action) #:nodoc:
prefix = prefix_name_for_action(as, action)
prefix = Mapper.normalize_name(prefix) if prefix
name_prefix = @scope[:as]
if parent_resource
+ return nil if as.nil? && action.nil?
+
collection_name = parent_resource.collection_name
member_name = parent_resource.member_name
end
@@ -1323,7 +1354,7 @@ module ActionDispatch
end
end
- module Shorthand
+ module Shorthand #:nodoc:
def match(*args)
if args.size == 1 && args.last.is_a?(Hash)
options = args.pop
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 32f41934f1..ebced9cabe 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -485,7 +485,8 @@ module ActionDispatch
Generator.new(options, recall, self, extras).generate
end
- RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :port, :trailing_slash, :script_name]
+ RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length,
+ :trailing_slash, :script_name, :anchor, :params, :only_path ]
def _generate_prefix(options = {})
nil
@@ -504,11 +505,8 @@ module ActionDispatch
rewritten_url << (options[:protocol] || "http")
rewritten_url << "://" unless rewritten_url.match("://")
rewritten_url << rewrite_authentication(options)
-
- raise "Missing host to link to! Please provide :host parameter or set default_url_options[:host]" unless options[:host]
-
- rewritten_url << options[:host]
- rewritten_url << ":#{options.delete(:port)}" if options.key?(:port)
+ rewritten_url << host_from_options(options)
+ rewritten_url << ":#{options.delete(:port)}" if options[:port]
end
script_name = options.delete(:script_name)
@@ -562,6 +560,26 @@ module ActionDispatch
end
private
+
+ def host_from_options(options)
+ computed_host = subdomain_and_domain(options) || options[:host]
+ unless computed_host
+ raise ArgumentError, "Missing host to link to! Please provide :host parameter or set default_url_options[:host]"
+ end
+ computed_host
+ end
+
+ def subdomain_and_domain(options)
+ return nil unless options[:subdomain] || options[:domain]
+ tld_length = options[:tld_length] || ActionDispatch::Http::URL.tld_length
+
+ host = ""
+ host << (options[:subdomain] || ActionDispatch::Http::URL.extract_subdomain(options[:host], tld_length))
+ host << "."
+ host << (options[:domain] || ActionDispatch::Http::URL.extract_domain(options[:host], tld_length))
+ host
+ end
+
def handle_positional_args(options)
return unless args = options.delete(:_positional_args)
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index bfdea41f60..d4db78a25a 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -115,6 +115,13 @@ module ActionDispatch
# * <tt>:host</tt> - Specifies the host the link should be targeted at.
# If <tt>:only_path</tt> is false, this option must be
# provided either explicitly, or via +default_url_options+.
+ # * <tt>:subdomain</tt> - Specifies the subdomain of the link, using the +tld_length+
+ # to split the domain from the host.
+ # * <tt>:domain</tt> - Specifies the domain of the link, using the +tld_length+
+ # to split the subdomain from the host.
+ # * <tt>:tld_length</tt> - Number of labels the TLD id composed of, only used if
+ # <tt>:subdomain</tt> or <tt>:domain</tt> are supplied. Defaults to
+ # <tt>ActionDispatch::Http::URL.tld_length</tt>, which in turn defaults to 1.
# * <tt>:port</tt> - Optionally specify the port to connect to.
# * <tt>:anchor</tt> - An anchor name to be appended to the path.
# * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2009/"
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index fee8cad9f5..8fe74c3c80 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -363,6 +363,10 @@ module ActionDispatch
integration_session.url_options
end
+ def respond_to?(method, include_private = false)
+ integration_session.respond_to?(method, include_private) || super
+ end
+
# Delegate unhandled messages to the current session instance.
def method_missing(sym, *args, &block)
reset! unless integration_session
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb
index 3bc81ae068..e52797042f 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb
@@ -57,8 +57,8 @@ module ActionView
private
- def path_to_asset(source)
- asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension)
+ def path_to_asset(source, include_host = true)
+ asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension, include_host)
end
def compute_paths(*args)
@@ -77,9 +77,8 @@ module ActionView
def ensure_sources!(sources)
sources.each do |source|
- asset_file_path!(path_to_asset(source))
+ asset_file_path!(path_to_asset(source, false))
end
- return sources
end
def collect_asset_files(*path)
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 8c300ec745..ef5bbd8ae3 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -2,7 +2,7 @@ require 'cgi'
require 'action_view/helpers/date_helper'
require 'action_view/helpers/tag_helper'
require 'action_view/helpers/form_tag_helper'
-require 'active_support/core_ext/class/inheritable_attributes'
+require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/string/output_safety'
@@ -1117,7 +1117,7 @@ module ActionView
class FormBuilder #:nodoc:
# The methods which wrap a form helper call.
- class_inheritable_accessor :field_helpers
+ class_attribute :field_helpers
self.field_helpers = (FormHelper.instance_method_names - ['form_for'])
attr_accessor :object_name, :object, :options
diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/partials.rb
index 844c3e9572..cd3f130dc4 100644
--- a/actionpack/lib/action_view/partials.rb
+++ b/actionpack/lib/action_view/partials.rb
@@ -75,6 +75,11 @@ module ActionView
#
# <%= render :partial => "ad", :collection => @advertisements, :spacer_template => "ad_divider" %>
#
+ # If the given <tt>:collection</tt> is nil or empty, <tt>render</tt> will return nil. This will allow you
+ # to specify a text which will displayed instead by using this form:
+ #
+ # <%= render(:partial => "ad", :collection => @advertisements) || "There's no ad to be displayed" %>
+ #
# NOTE: Due to backwards compatibility concerns, the collection can't be one of hashes. Normally you'd also
# just keep domain objects, like Active Records, in there.
#
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index dbb1532cd4..831a19654e 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -184,6 +184,11 @@ module ActionView
end
end
+ # Used to store template data by template handlers.
+ def data
+ @data ||= {}
+ end
+
def inspect
@inspect ||=
if defined?(Rails.root)
@@ -269,7 +274,8 @@ module ActionView
end
end
- code = @handler.call(self)
+ arity = @handler.respond_to?(:arity) ? @handler.arity : @handler.method(:call).arity
+ code = arity == 1 ? @handler.call(self) : @handler.call(self, view)
# Make sure that the resulting String to be evalled is in the
# encoding of the code