mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge branch 'master' of gitproxy:rails/rails
This commit is contained in:
commit
ffec153029
10 changed files with 153 additions and 169 deletions
|
@ -29,6 +29,7 @@ module ActionController
|
|||
include ActionController::Verification
|
||||
include ActionController::RequestForgeryProtection
|
||||
include ActionController::Streaming
|
||||
include ActionController::RecordIdentifier
|
||||
include ActionController::HttpAuthentication::Basic::ControllerMethods
|
||||
include ActionController::HttpAuthentication::Digest::ControllerMethods
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ module ActionController
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
include ActionDispatch::Routing::UrlFor
|
||||
include ActionController::RackDelegation
|
||||
|
||||
def url_options
|
||||
super.reverse_merge(
|
||||
|
|
|
@ -339,9 +339,13 @@ module ActionController
|
|||
def build_request_uri(action, parameters)
|
||||
unless @request.env["PATH_INFO"]
|
||||
options = @controller.__send__(:url_options).merge(parameters)
|
||||
options.update(:only_path => true, :action => action, :relative_url_root => nil)
|
||||
rewriter = ActionController::UrlRewriter.new(@request, parameters)
|
||||
options.update(
|
||||
:only_path => true,
|
||||
:action => action,
|
||||
:relative_url_root => nil,
|
||||
:_path_segments => @request.symbolized_path_parameters)
|
||||
|
||||
rewriter = ActionController::UrlRewriter
|
||||
url, query_string = rewriter.rewrite(@router, options).split("?", 2)
|
||||
|
||||
@request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
|
||||
|
|
|
@ -2,37 +2,16 @@ require 'active_support/core_ext/hash/except'
|
|||
|
||||
module ActionController
|
||||
# Rewrites URLs for Base.redirect_to and Base.url_for in the controller.
|
||||
class UrlRewriter #:nodoc:
|
||||
module UrlRewriter #:nodoc:
|
||||
RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :port, :trailing_slash, :skip_relative_url_root]
|
||||
|
||||
def initialize(request, parameters)
|
||||
@request, @parameters = request, parameters
|
||||
end
|
||||
|
||||
def rewrite(router, options = {})
|
||||
options[:host] ||= @request.host_with_port
|
||||
options[:protocol] ||= @request.protocol
|
||||
|
||||
self.class.rewrite(router, options, @request.symbolized_path_parameters) do |options|
|
||||
process_path_options(options)
|
||||
end
|
||||
end
|
||||
|
||||
def to_str
|
||||
"#{@request.protocol}, #{@request.host_with_port}, #{@request.path}, #{@parameters[:controller]}, #{@parameters[:action]}, #{@request.parameters.inspect}"
|
||||
end
|
||||
|
||||
alias_method :to_s, :to_str
|
||||
|
||||
# ROUTES TODO: Class method code smell
|
||||
def self.rewrite(router, options, path_segments=nil)
|
||||
def self.rewrite(router, options)
|
||||
handle_positional_args(options)
|
||||
|
||||
rewritten_url = ""
|
||||
|
||||
# ROUTES TODO: Fix the tests
|
||||
segments = options.delete(:_path_segments)
|
||||
path_segments = path_segments ? path_segments.merge(segments || {}) : segments
|
||||
path_segments = options.delete(:_path_segments)
|
||||
|
||||
unless options[:only_path]
|
||||
rewritten_url << (options[:protocol] || "http")
|
||||
|
@ -81,18 +60,5 @@ module ActionController
|
|||
end
|
||||
end
|
||||
|
||||
# Given a Hash of options, generates a route
|
||||
def process_path_options(options)
|
||||
options = options.symbolize_keys
|
||||
options.update(options[:params].symbolize_keys) if options[:params]
|
||||
|
||||
if (overwrite = options.delete(:overwrite_params))
|
||||
options.update(@parameters.symbolize_keys)
|
||||
options.update(overwrite.symbolize_keys)
|
||||
end
|
||||
|
||||
options
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -276,28 +276,123 @@ module ActionDispatch
|
|||
route
|
||||
end
|
||||
|
||||
def options_as_params(options)
|
||||
# If an explicit :controller was given, always make :action explicit
|
||||
# too, so that action expiry works as expected for things like
|
||||
#
|
||||
# generate({:controller => 'content'}, {:controller => 'content', :action => 'show'})
|
||||
#
|
||||
# (the above is from the unit tests). In the above case, because the
|
||||
# controller was explicitly given, but no action, the action is implied to
|
||||
# be "index", not the recalled action of "show".
|
||||
#
|
||||
# great fun, eh?
|
||||
class Generator
|
||||
attr_reader :options, :recall, :set, :script_name, :named_route
|
||||
|
||||
options_as_params = options.clone
|
||||
options_as_params[:action] ||= 'index' if options[:controller]
|
||||
options_as_params[:action] = options_as_params[:action].to_s if options_as_params[:action]
|
||||
options_as_params
|
||||
end
|
||||
def initialize(options, recall, set, extras = false)
|
||||
@script_name = options.delete(:script_name)
|
||||
@named_route = options.delete(:use_route)
|
||||
@options = options.dup
|
||||
@recall = recall.dup
|
||||
@set = set
|
||||
@extras = extras
|
||||
|
||||
def build_expiry(options, recall)
|
||||
recall.inject({}) do |expiry, (key, recalled_value)|
|
||||
expiry[key] = (options.key?(key) && options[key].to_param != recalled_value.to_param)
|
||||
expiry
|
||||
normalize_options!
|
||||
normalize_controller_action_id!
|
||||
use_relative_controller!
|
||||
controller.sub!(%r{^/}, '') if controller
|
||||
handle_nil_action!
|
||||
end
|
||||
|
||||
def controller
|
||||
@controller ||= @options[:controller]
|
||||
end
|
||||
|
||||
def current_controller
|
||||
@recall[:controller]
|
||||
end
|
||||
|
||||
def use_recall_for(key)
|
||||
if @recall[key] && (!@options.key?(key) || @options[key] == @recall[key])
|
||||
@options[key] = @recall.delete(key)
|
||||
end
|
||||
end
|
||||
|
||||
def normalize_options!
|
||||
# If an explicit :controller was given, always make :action explicit
|
||||
# too, so that action expiry works as expected for things like
|
||||
#
|
||||
# generate({:controller => 'content'}, {:controller => 'content', :action => 'show'})
|
||||
#
|
||||
# (the above is from the unit tests). In the above case, because the
|
||||
# controller was explicitly given, but no action, the action is implied to
|
||||
# be "index", not the recalled action of "show".
|
||||
|
||||
if options[:controller]
|
||||
options[:action] ||= 'index'
|
||||
options[:controller] = options[:controller].to_s
|
||||
end
|
||||
|
||||
if options[:action]
|
||||
options[:action] = options[:action].to_s
|
||||
end
|
||||
end
|
||||
|
||||
# This pulls :controller, :action, and :id out of the recall.
|
||||
# The recall key is only used if there is no key in the options
|
||||
# or if the key in the options is identical. If any of
|
||||
# :controller, :action or :id is not found, don't pull any
|
||||
# more keys from the recall.
|
||||
def normalize_controller_action_id!
|
||||
@recall[:action] ||= 'index' if current_controller
|
||||
|
||||
use_recall_for(:controller) or return
|
||||
use_recall_for(:action) or return
|
||||
use_recall_for(:id)
|
||||
end
|
||||
|
||||
# if the current controller is "foo/bar/baz" and :controller => "baz/bat"
|
||||
# is specified, the controller becomes "foo/baz/bat"
|
||||
def use_relative_controller!
|
||||
if !named_route && different_controller?
|
||||
old_parts = current_controller.split('/')
|
||||
size = controller.count("/") + 1
|
||||
parts = old_parts[0...-size] << controller
|
||||
@controller = @options[:controller] = parts.join("/")
|
||||
end
|
||||
end
|
||||
|
||||
# This handles the case of :action => nil being explicitly passed.
|
||||
# It is identical to :action => "index"
|
||||
def handle_nil_action!
|
||||
if options.has_key?(:action) && options[:action].nil?
|
||||
options[:action] = 'index'
|
||||
end
|
||||
recall[:action] = options.delete(:action) if options[:action] == 'index'
|
||||
end
|
||||
|
||||
def generate
|
||||
error = ActionController::RoutingError.new("No route matches #{options.inspect}")
|
||||
path, params = @set.generate(:path_info, named_route, options, recall, opts)
|
||||
|
||||
raise error unless path
|
||||
|
||||
params.reject! {|k,v| !v }
|
||||
|
||||
return [path, params.keys] if @extras
|
||||
|
||||
path << "?#{params.to_query}" if params.any?
|
||||
"#{script_name}#{path}"
|
||||
rescue Rack::Mount::RoutingError
|
||||
raise error
|
||||
end
|
||||
|
||||
def opts
|
||||
parameterize = lambda do |name, value|
|
||||
if name == :controller
|
||||
value
|
||||
elsif value.is_a?(Array)
|
||||
value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
|
||||
else
|
||||
Rack::Mount::Utils.escape_uri(value.to_param)
|
||||
end
|
||||
end
|
||||
{:parameterize => parameterize}
|
||||
end
|
||||
|
||||
def different_controller?
|
||||
return false unless current_controller
|
||||
controller.to_param != current_controller.to_param
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -308,84 +403,11 @@ module ActionDispatch
|
|||
end
|
||||
|
||||
def generate_extras(options, recall={})
|
||||
generate(options, recall, :generate_extras)
|
||||
generate(options, recall, true)
|
||||
end
|
||||
|
||||
def generate(options, recall = {}, method = :generate)
|
||||
options, recall = options.dup, recall.dup
|
||||
script_name = options.delete(:script_name)
|
||||
named_route = options.delete(:use_route)
|
||||
|
||||
options = options_as_params(options)
|
||||
expire_on = build_expiry(options, recall)
|
||||
|
||||
recall[:action] ||= 'index' if options[:controller] || recall[:controller]
|
||||
|
||||
if recall[:controller] && (!options.has_key?(:controller) || options[:controller] == recall[:controller])
|
||||
options[:controller] = recall.delete(:controller)
|
||||
|
||||
if recall[:action] && (!options.has_key?(:action) || options[:action] == recall[:action])
|
||||
options[:action] = recall.delete(:action)
|
||||
|
||||
if recall[:id] && (!options.has_key?(:id) || options[:id] == recall[:id])
|
||||
options[:id] = recall.delete(:id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
options[:controller] = options[:controller].to_s if options[:controller]
|
||||
|
||||
if !named_route && expire_on[:controller] && options[:controller] && options[:controller][0] != ?/
|
||||
old_parts = recall[:controller].split('/')
|
||||
new_parts = options[:controller].split('/')
|
||||
parts = old_parts[0..-(new_parts.length + 1)] + new_parts
|
||||
options[:controller] = parts.join('/')
|
||||
end
|
||||
|
||||
options[:controller] = options[:controller][1..-1] if options[:controller] && options[:controller][0] == ?/
|
||||
|
||||
merged = options.merge(recall)
|
||||
if options.has_key?(:action) && options[:action].nil?
|
||||
options.delete(:action)
|
||||
recall[:action] = 'index'
|
||||
end
|
||||
recall[:action] = options.delete(:action) if options[:action] == 'index'
|
||||
|
||||
opts = {}
|
||||
opts[:parameterize] = lambda { |name, value|
|
||||
if name == :controller
|
||||
value
|
||||
elsif value.is_a?(Array)
|
||||
value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
|
||||
else
|
||||
Rack::Mount::Utils.escape_uri(value.to_param)
|
||||
end
|
||||
}
|
||||
|
||||
unless result = @set.generate(:path_info, named_route, options, recall, opts)
|
||||
raise ActionController::RoutingError, "No route matches #{options.inspect}"
|
||||
end
|
||||
|
||||
path, params = result
|
||||
params.each do |k, v|
|
||||
if v
|
||||
params[k] = v
|
||||
else
|
||||
params.delete(k)
|
||||
end
|
||||
end
|
||||
|
||||
if path && method == :generate_extras
|
||||
[path, params.keys]
|
||||
elsif path
|
||||
path << "?#{params.to_query}" if params.any?
|
||||
path = "#{script_name}#{path}"
|
||||
path
|
||||
else
|
||||
raise ActionController::RoutingError, "No route matches #{options.inspect}"
|
||||
end
|
||||
rescue Rack::Mount::RoutingError
|
||||
raise ActionController::RoutingError, "No route matches #{options.inspect}"
|
||||
def generate(options, recall = {}, extras = false)
|
||||
Generator.new(options, recall, @set, extras).generate
|
||||
end
|
||||
|
||||
def call(env)
|
||||
|
|
|
@ -76,6 +76,9 @@ class UrlOptionsController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
class RecordIdentifierController < ActionController::Base
|
||||
end
|
||||
|
||||
class ControllerClassTests < ActiveSupport::TestCase
|
||||
def test_controller_path
|
||||
assert_equal 'empty', EmptyController.controller_path
|
||||
|
@ -102,6 +105,11 @@ class ControllerClassTests < ActiveSupport::TestCase
|
|||
|
||||
assert_equal [:password], parameters
|
||||
end
|
||||
|
||||
def test_record_identifier
|
||||
assert_respond_to RecordIdentifierController.new, :dom_id
|
||||
assert_respond_to RecordIdentifierController.new, :dom_class
|
||||
end
|
||||
end
|
||||
|
||||
class ControllerInstanceTests < Test::Unit::TestCase
|
||||
|
|
|
@ -64,7 +64,7 @@ class PageCachingTest < ActionController::TestCase
|
|||
@controller.cache_store = :file_store, FILE_STORE_PATH
|
||||
|
||||
@params = {:controller => 'posts', :action => 'index', :only_path => true, :skip_relative_url_root => true}
|
||||
@rewriter = ActionController::UrlRewriter.new(@request, @params)
|
||||
@rewriter = ActionController::UrlRewriter
|
||||
|
||||
FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
|
||||
FileUtils.mkdir_p(FILE_STORE_PATH)
|
||||
|
|
|
@ -4,10 +4,24 @@ require 'controller/fake_controllers'
|
|||
ActionController::UrlRewriter
|
||||
|
||||
class UrlRewriterTests < ActionController::TestCase
|
||||
class Rewriter
|
||||
def initialize(request)
|
||||
@options = {
|
||||
:host => request.host_with_port,
|
||||
:protocol => request.protocol
|
||||
}
|
||||
end
|
||||
|
||||
def rewrite(router, options)
|
||||
options = @options.merge(options)
|
||||
ActionController::UrlRewriter.rewrite(router, options)
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@request = ActionController::TestRequest.new
|
||||
@params = {}
|
||||
@rewriter = ActionController::UrlRewriter.new(@request, @params)
|
||||
@rewriter = Rewriter.new(@request) #.new(@request, @params)
|
||||
end
|
||||
|
||||
def test_port
|
||||
|
@ -61,34 +75,6 @@ class UrlRewriterTests < ActionController::TestCase
|
|||
)
|
||||
end
|
||||
|
||||
def test_overwrite_params
|
||||
@params[:controller] = 'hi'
|
||||
@params[:action] = 'bye'
|
||||
@params[:id] = '2'
|
||||
|
||||
assert_equal '/hi/hi/2', @rewriter.rewrite(@router, :only_path => true, :overwrite_params => {:action => 'hi'})
|
||||
u = @rewriter.rewrite(@router, :only_path => false, :overwrite_params => {:action => 'hi'})
|
||||
assert_match %r(/hi/hi/2$), u
|
||||
end
|
||||
|
||||
def test_overwrite_removes_original
|
||||
@params[:controller] = 'search'
|
||||
@params[:action] = 'list'
|
||||
@params[:list_page] = 1
|
||||
|
||||
assert_equal '/search/list?list_page=2', @rewriter.rewrite(@router, :only_path => true, :overwrite_params => {"list_page" => 2})
|
||||
u = @rewriter.rewrite(@router, :only_path => false, :overwrite_params => {:list_page => 2})
|
||||
assert_equal 'http://test.host/search/list?list_page=2', u
|
||||
end
|
||||
|
||||
def test_to_str
|
||||
@params[:controller] = 'hi'
|
||||
@params[:action] = 'bye'
|
||||
@request.parameters[:id] = '2'
|
||||
|
||||
assert_equal 'http://, test.host, /, hi, bye, {"id"=>"2"}', @rewriter.to_str
|
||||
end
|
||||
|
||||
def test_trailing_slash
|
||||
options = {:controller => 'foo', :action => 'bar', :id => '3', :only_path => true}
|
||||
assert_equal '/foo/bar/3', @rewriter.rewrite(@router, options)
|
||||
|
|
|
@ -122,7 +122,6 @@ class UrlHelperTest < ActionView::TestCase
|
|||
url = {:controller => 'weblog', :action => 'show'}
|
||||
@controller = ActionController::Base.new
|
||||
@controller.request = ActionController::TestRequest.new
|
||||
@controller.url = ActionController::UrlRewriter.new(@controller.request, url)
|
||||
assert_dom_equal(%q{<a href="/weblog/show">Test Link</a>}, link_to('Test Link', url))
|
||||
end
|
||||
|
||||
|
@ -131,7 +130,6 @@ class UrlHelperTest < ActionView::TestCase
|
|||
url = {:controller => 'weblog', :action => 'show', :host => 'www.example.com'}
|
||||
@controller = ActionController::Base.new
|
||||
@controller.request = ActionController::TestRequest.new
|
||||
@controller.url = ActionController::UrlRewriter.new(@controller.request, url)
|
||||
assert_dom_equal(%q{<a href="http://www.example.com/weblog/show">Test Link</a>}, link_to('Test Link', url))
|
||||
end
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ module ActiveSupport
|
|||
|
||||
module JSON
|
||||
# Listed in order of preference.
|
||||
DECODERS = %w(Yajl JSONGem Yaml)
|
||||
DECODERS = %w(Yajl Yaml)
|
||||
|
||||
class << self
|
||||
attr_reader :parse_error
|
||||
|
|
Loading…
Reference in a new issue