aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch
diff options
context:
space:
mode:
authorXavier Noria <fxn@hashref.com>2010-07-22 01:29:18 +0200
committerXavier Noria <fxn@hashref.com>2010-07-22 01:29:18 +0200
commit919eb200a9a0969c444b938d08eb4661d41ba986 (patch)
tree329cbe815d549275cc0dc6aa0f75c18d8954f105 /actionpack/lib/action_dispatch
parent56669ec3048de316918ec5ad554fff83d757911b (diff)
parentb456877cfb7e0cb0bab9ffd5674abd23caba0ab4 (diff)
downloadrails-919eb200a9a0969c444b938d08eb4661d41ba986.tar.gz
rails-919eb200a9a0969c444b938d08eb4661d41ba986.tar.bz2
rails-919eb200a9a0969c444b938d08eb4661d41ba986.zip
Merge remote branch 'rails/master'
Diffstat (limited to 'actionpack/lib/action_dispatch')
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb76
-rw-r--r--actionpack/lib/action_dispatch/http/parameter_filter.rb72
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb11
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/stack.rb15
-rw-r--r--actionpack/lib/action_dispatch/routing.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/polymorphic_routes.rb186
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb3
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb1
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/model.rb19
11 files changed, 291 insertions, 99 deletions
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index 152aaa2e67..1ab48ae04d 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -26,88 +26,32 @@ module ActionDispatch
module FilterParameters
extend ActiveSupport::Concern
- @@compiled_parameter_filter_for = {}
+ @@parameter_filter_for = {}
# Return a hash of parameters with all sensitive data replaced.
def filtered_parameters
- @filtered_parameters ||= if filtering_parameters?
- process_parameter_filter(parameters)
- else
- parameters.dup
- end
+ @filtered_parameters ||= parameter_filter.filter(parameters)
end
- alias :fitered_params :filtered_parameters
# Return a hash of request.env with all sensitive data replaced.
def filtered_env
- filtered_env = @env.dup
- filtered_env.each do |key, value|
- if (key =~ /RAW_POST_DATA/i)
- filtered_env[key] = '[FILTERED]'
- elsif value.is_a?(Hash)
- filtered_env[key] = process_parameter_filter(value)
- end
- end
- filtered_env
+ @filtered_env ||= env_filter.filter(@env)
end
protected
- def filtering_parameters? #:nodoc:
- @env["action_dispatch.parameter_filter"].present?
+ def parameter_filter
+ parameter_filter_for(@env["action_dispatch.parameter_filter"])
end
- def process_parameter_filter(params) #:nodoc:
- compiled_parameter_filter_for(@env["action_dispatch.parameter_filter"]).call(params)
+ def env_filter
+ parameter_filter_for(Array.wrap(@env["action_dispatch.parameter_filter"]) << /RAW_POST_DATA/)
end
- def compile_parameter_filter(filters) #:nodoc:
- strings, regexps, blocks = [], [], []
-
- filters.each do |item|
- case item
- when NilClass
- when Proc
- blocks << item
- when Regexp
- regexps << item
- else
- strings << item.to_s
- end
- end
-
- regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
- [regexps, blocks]
- end
-
- def compiled_parameter_filter_for(filters) #:nodoc:
- @@compiled_parameter_filter_for[filters] ||= begin
- regexps, blocks = compile_parameter_filter(filters)
-
- lambda do |original_params|
- filtered_params = {}
-
- original_params.each do |key, value|
- if regexps.find { |r| key =~ r }
- value = '[FILTERED]'
- elsif value.is_a?(Hash)
- value = process_parameter_filter(value)
- elsif value.is_a?(Array)
- value = value.map { |v| v.is_a?(Hash) ? process_parameter_filter(v) : v }
- elsif blocks.present?
- key = key.dup
- value = value.dup if value.duplicable?
- blocks.each { |b| b.call(key, value) }
- end
-
- filtered_params[key] = value
- end
-
- filtered_params
- end
- end
+ def parameter_filter_for(filters)
+ @@parameter_filter_for[filters] ||= ParameterFilter.new(filters)
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_dispatch/http/parameter_filter.rb b/actionpack/lib/action_dispatch/http/parameter_filter.rb
new file mode 100644
index 0000000000..1480e8f77c
--- /dev/null
+++ b/actionpack/lib/action_dispatch/http/parameter_filter.rb
@@ -0,0 +1,72 @@
+module ActionDispatch
+ module Http
+ class ParameterFilter
+
+ def initialize(filters)
+ @filters = filters
+ end
+
+ def filter(params)
+ if enabled?
+ compiled_filter.call(params)
+ else
+ params.dup
+ end
+ end
+
+ private
+
+ def enabled?
+ @filters.present?
+ end
+
+ def compiled_filter
+ @compiled_filter ||= begin
+ regexps, blocks = compile_filter
+
+ lambda do |original_params|
+ filtered_params = {}
+
+ original_params.each do |key, value|
+ if regexps.find { |r| key =~ r }
+ value = '[FILTERED]'
+ elsif value.is_a?(Hash)
+ value = filter(value)
+ elsif value.is_a?(Array)
+ value = value.map { |v| v.is_a?(Hash) ? filter(v) : v }
+ elsif blocks.present?
+ key = key.dup
+ value = value.dup if value.duplicable?
+ blocks.each { |b| b.call(key, value) }
+ end
+
+ filtered_params[key] = value
+ end
+
+ filtered_params
+ end
+ end
+ end
+
+ def compile_filter
+ strings, regexps, blocks = [], [], []
+
+ @filters.each do |item|
+ case item
+ when NilClass
+ when Proc
+ blocks << item
+ when Regexp
+ regexps << item
+ else
+ strings << item.to_s
+ end
+ end
+
+ regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
+ [regexps, blocks]
+ end
+
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index 64f4d1d532..ad98249468 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -24,9 +24,9 @@ module ActionDispatch
def [](key)
if key == :id
- load_session_id! unless super(:id) || has_session_id?
+ load_session_id! unless key?(:id) || has_session_id?
end
- super(key)
+ super
end
private
@@ -191,8 +191,11 @@ module ActionDispatch
def load_session(env)
stale_session_check! do
- sid = current_session_id(env)
- sid, session = get_session(env, sid)
+ if sid = current_session_id(env)
+ sid, session = get_session(env, sid)
+ else
+ sid, session = generate_sid, {}
+ end
[sid, session]
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
index 28e3dbd732..5304440418 100644
--- a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
@@ -25,7 +25,6 @@ module ActionDispatch
private
def get_session(env, sid)
- sid ||= generate_sid
begin
session = @pool.get(sid) || {}
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb
index 4618f3befc..41078eced7 100644
--- a/actionpack/lib/action_dispatch/middleware/stack.rb
+++ b/actionpack/lib/action_dispatch/middleware/stack.rb
@@ -46,7 +46,7 @@ module ActionDispatch
end
def insert(index, *args, &block)
- index = self.index(index) unless index.is_a?(Integer)
+ index = assert_index(index, :before)
middleware = self.class::Middleware.new(*args, &block)
super(index, middleware)
end
@@ -54,9 +54,8 @@ module ActionDispatch
alias_method :insert_before, :insert
def insert_after(index, *args, &block)
- i = index.is_a?(Integer) ? index : self.index(index)
- raise "No such middleware to insert after: #{index.inspect}" unless i
- insert(i + 1, *args, &block)
+ index = assert_index(index, :after)
+ insert(index + 1, *args, &block)
end
def swap(target, *args, &block)
@@ -79,5 +78,13 @@ module ActionDispatch
raise "MiddlewareStack#build requires an app" unless app
reverse.inject(app) { |a, e| e.build(a) }
end
+
+ protected
+
+ def assert_index(index, where)
+ i = index.is_a?(Integer) ? index : self.index(index)
+ raise "No such middleware to insert #{where}: #{index.inspect}" unless i
+ i
+ end
end
end
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index 8afc685fdf..683dd72555 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -1,6 +1,5 @@
require 'active_support/core_ext/object/to_param'
require 'active_support/core_ext/regexp'
-require 'action_controller/polymorphic_routes'
module ActionDispatch
# = Routing
@@ -217,13 +216,14 @@ module ActionDispatch
autoload :Route, 'action_dispatch/routing/route'
autoload :RouteSet, 'action_dispatch/routing/route_set'
autoload :UrlFor, 'action_dispatch/routing/url_for'
+ autoload :PolymorphicRoutes, 'action_dispatch/routing/polymorphic_routes'
SEPARATORS = %w( / . ? ) #:nodoc:
HTTP_METHODS = [:get, :head, :post, :put, :delete, :options] #:nodoc:
# A helper module to hold URL related helpers.
module Helpers #:nodoc:
- include ActionController::PolymorphicRoutes
+ include PolymorphicRoutes
end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
new file mode 100644
index 0000000000..31dba835ac
--- /dev/null
+++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -0,0 +1,186 @@
+module ActionDispatch
+ module Routing
+ # Polymorphic URL helpers are methods for smart resolution to a named route call when
+ # given an Active Record model instance. They are to be used in combination with
+ # ActionController::Resources.
+ #
+ # These methods are useful when you want to generate correct URL or path to a RESTful
+ # resource without having to know the exact type of the record in question.
+ #
+ # Nested resources and/or namespaces are also supported, as illustrated in the example:
+ #
+ # polymorphic_url([:admin, @article, @comment])
+ #
+ # results in:
+ #
+ # admin_article_comment_url(@article, @comment)
+ #
+ # == Usage within the framework
+ #
+ # Polymorphic URL helpers are used in a number of places throughout the Rails framework:
+ #
+ # * <tt>url_for</tt>, so you can use it with a record as the argument, e.g.
+ # <tt>url_for(@article)</tt>;
+ # * ActionView::Helpers::FormHelper uses <tt>polymorphic_path</tt>, so you can write
+ # <tt>form_for(@article)</tt> without having to specify <tt>:url</tt> parameter for the form
+ # action;
+ # * <tt>redirect_to</tt> (which, in fact, uses <tt>url_for</tt>) so you can write
+ # <tt>redirect_to(post)</tt> in your controllers;
+ # * ActionView::Helpers::AtomFeedHelper, so you don't have to explicitly specify URLs
+ # for feed entries.
+ #
+ # == Prefixed polymorphic helpers
+ #
+ # In addition to <tt>polymorphic_url</tt> and <tt>polymorphic_path</tt> methods, a
+ # number of prefixed helpers are available as a shorthand to <tt>:action => "..."</tt>
+ # in options. Those are:
+ #
+ # * <tt>edit_polymorphic_url</tt>, <tt>edit_polymorphic_path</tt>
+ # * <tt>new_polymorphic_url</tt>, <tt>new_polymorphic_path</tt>
+ #
+ # Example usage:
+ #
+ # edit_polymorphic_path(@post) # => "/posts/1/edit"
+ # polymorphic_path(@post, :format => :pdf) # => "/posts/1.pdf"
+ module PolymorphicRoutes
+ # Constructs a call to a named RESTful route for the given record and returns the
+ # resulting URL string. For example:
+ #
+ # # calls post_url(post)
+ # polymorphic_url(post) # => "http://example.com/posts/1"
+ # polymorphic_url([blog, post]) # => "http://example.com/blogs/1/posts/1"
+ # polymorphic_url([:admin, blog, post]) # => "http://example.com/admin/blogs/1/posts/1"
+ # polymorphic_url([user, :blog, post]) # => "http://example.com/users/1/blog/posts/1"
+ # polymorphic_url(Comment) # => "http://example.com/comments"
+ #
+ # ==== Options
+ #
+ # * <tt>:action</tt> - Specifies the action prefix for the named route:
+ # <tt>:new</tt> or <tt>:edit</tt>. Default is no prefix.
+ # * <tt>:routing_type</tt> - Allowed values are <tt>:path</tt> or <tt>:url</tt>.
+ # Default is <tt>:url</tt>.
+ #
+ # ==== Examples
+ #
+ # # an Article record
+ # polymorphic_url(record) # same as article_url(record)
+ #
+ # # a Comment record
+ # polymorphic_url(record) # same as comment_url(record)
+ #
+ # # it recognizes new records and maps to the collection
+ # record = Comment.new
+ # polymorphic_url(record) # same as comments_url()
+ #
+ # # the class of a record will also map to the collection
+ # polymorphic_url(Comment) # same as comments_url()
+ #
+ def polymorphic_url(record_or_hash_or_array, options = {})
+ if record_or_hash_or_array.kind_of?(Array)
+ record_or_hash_or_array = record_or_hash_or_array.compact
+ record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1
+ end
+
+ record = extract_record(record_or_hash_or_array)
+ record = record.to_model if record.respond_to?(:to_model)
+
+ args = case record_or_hash_or_array
+ when Hash; [ record_or_hash_or_array ]
+ when Array; record_or_hash_or_array.dup
+ else [ record_or_hash_or_array ]
+ end
+
+ inflection = if options[:action].to_s == "new"
+ args.pop
+ :singular
+ elsif (record.respond_to?(:persisted?) && !record.persisted?)
+ args.pop
+ :plural
+ elsif record.is_a?(Class)
+ args.pop
+ :plural
+ else
+ :singular
+ end
+
+ args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
+ named_route = build_named_route_call(record_or_hash_or_array, inflection, options)
+
+ url_options = options.except(:action, :routing_type)
+ unless url_options.empty?
+ args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options
+ end
+
+ send(named_route, *args)
+ end
+
+ # Returns the path component of a URL for the given record. It uses
+ # <tt>polymorphic_url</tt> with <tt>:routing_type => :path</tt>.
+ def polymorphic_path(record_or_hash_or_array, options = {})
+ polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path))
+ end
+
+ %w(edit new).each do |action|
+ module_eval <<-EOT, __FILE__, __LINE__ + 1
+ def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {})
+ polymorphic_url( # polymorphic_url(
+ record_or_hash, # record_or_hash,
+ options.merge(:action => "#{action}")) # options.merge(:action => "edit"))
+ end # end
+ #
+ def #{action}_polymorphic_path(record_or_hash, options = {}) # def edit_polymorphic_path(record_or_hash, options = {})
+ polymorphic_url( # polymorphic_url(
+ record_or_hash, # record_or_hash,
+ options.merge(:action => "#{action}", :routing_type => :path)) # options.merge(:action => "edit", :routing_type => :path))
+ end # end
+ EOT
+ end
+
+ private
+ def action_prefix(options)
+ options[:action] ? "#{options[:action]}_" : ''
+ end
+
+ def routing_type(options)
+ options[:routing_type] || :url
+ end
+
+ def build_named_route_call(records, inflection, options = {})
+ unless records.is_a?(Array)
+ record = extract_record(records)
+ route = ''
+ else
+ record = records.pop
+ route = records.inject("") do |string, parent|
+ if parent.is_a?(Symbol) || parent.is_a?(String)
+ string << "#{parent}_"
+ else
+ string << ActiveModel::Naming.plural(parent).singularize
+ string << "_"
+ end
+ end
+ end
+
+ if record.is_a?(Symbol) || record.is_a?(String)
+ route << "#{record}_"
+ else
+ route << ActiveModel::Naming.plural(record)
+ route = route.singularize if inflection == :singular
+ route << "_"
+ route << "index_" if ActiveModel::Naming.uncountable?(record) && inflection == :plural
+ end
+
+ action_prefix(options) + route + routing_type(options).to_s
+ end
+
+ def extract_record(record_or_hash_or_array)
+ case record_or_hash_or_array
+ when Array; record_or_hash_or_array.last
+ when Hash; record_or_hash_or_array[:id]
+ else record_or_hash_or_array
+ end
+ end
+ end
+ end
+end
+
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 36c52eb65a..a9b97a17eb 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -414,7 +414,8 @@ module ActionDispatch
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)
+ return nil unless param = value.to_param
+ param.split('/').map { |v| Rack::Mount::Utils.escape_uri(v) }.join("/")
end
end
{:parameterize => parameterize}
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index 980abd44df..662eb05c26 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -82,6 +82,7 @@ module ActionDispatch
#
module UrlFor
extend ActiveSupport::Concern
+ include PolymorphicRoutes
included do
# TODO: with_routing extends @controller with url_helpers, trickling down to including this module which overrides its default_url_options
diff --git a/actionpack/lib/action_dispatch/testing/assertions.rb b/actionpack/lib/action_dispatch/testing/assertions.rb
index 0e4a92048f..822150b768 100644
--- a/actionpack/lib/action_dispatch/testing/assertions.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions.rb
@@ -1,7 +1,6 @@
module ActionDispatch
module Assertions
autoload :DomAssertions, 'action_dispatch/testing/assertions/dom'
- autoload :ModelAssertions, 'action_dispatch/testing/assertions/model'
autoload :ResponseAssertions, 'action_dispatch/testing/assertions/response'
autoload :RoutingAssertions, 'action_dispatch/testing/assertions/routing'
autoload :SelectorAssertions, 'action_dispatch/testing/assertions/selector'
@@ -11,7 +10,6 @@ module ActionDispatch
included do
include DomAssertions
- include ModelAssertions
include ResponseAssertions
include RoutingAssertions
include SelectorAssertions
diff --git a/actionpack/lib/action_dispatch/testing/assertions/model.rb b/actionpack/lib/action_dispatch/testing/assertions/model.rb
deleted file mode 100644
index 46714418c6..0000000000
--- a/actionpack/lib/action_dispatch/testing/assertions/model.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module ActionDispatch
- module Assertions
- module ModelAssertions
- # Ensures that the passed record is valid by Active Record standards and
- # returns any error messages if it is not.
- #
- # ==== Examples
- #
- # # assert that a newly created record is valid
- # model = Model.new
- # assert_valid(model)
- #
- def assert_valid(record)
- ::ActiveSupport::Deprecation.warn("assert_valid is deprecated. Use assert record.valid? instead", caller)
- assert record.valid?, record.errors.full_messages.join("\n")
- end
- end
- end
-end