diff options
author | Xavier Noria <fxn@hashref.com> | 2010-07-22 01:29:18 +0200 |
---|---|---|
committer | Xavier Noria <fxn@hashref.com> | 2010-07-22 01:29:18 +0200 |
commit | 919eb200a9a0969c444b938d08eb4661d41ba986 (patch) | |
tree | 329cbe815d549275cc0dc6aa0f75c18d8954f105 /actionpack/lib/action_dispatch | |
parent | 56669ec3048de316918ec5ad554fff83d757911b (diff) | |
parent | b456877cfb7e0cb0bab9ffd5674abd23caba0ab4 (diff) | |
download | rails-919eb200a9a0969c444b938d08eb4661d41ba986.tar.gz rails-919eb200a9a0969c444b938d08eb4661d41ba986.tar.bz2 rails-919eb200a9a0969c444b938d08eb4661d41ba986.zip |
Merge remote branch 'rails/master'
Diffstat (limited to 'actionpack/lib/action_dispatch')
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 |