Rails 2.1.1
Among other things, a security fix.
This commit is contained in:
parent
d2c4c8737c
commit
d4f97345db
354 changed files with 21027 additions and 3072 deletions
|
@ -97,7 +97,7 @@ module ActionController
|
|||
value['controller'] = value['controller'].to_s
|
||||
if key == :actual && value['controller'].first != '/' && !value['controller'].include?('/')
|
||||
new_controller_path = ActionController::Routing.controller_relative_to(value['controller'], @controller.class.controller_path)
|
||||
value['controller'] = new_controller_path if value['controller'] != new_controller_path && ActionController::Routing.possible_controllers.include?(new_controller_path)
|
||||
value['controller'] = new_controller_path if value['controller'] != new_controller_path && ActionController::Routing.possible_controllers.include?(new_controller_path) && @response.redirected_to.is_a?(Hash)
|
||||
end
|
||||
value['controller'] = value['controller'][1..-1] if value['controller'].first == '/' # strip leading hash
|
||||
end
|
||||
|
|
|
@ -398,47 +398,31 @@ module ActionController
|
|||
# # The same, but shorter.
|
||||
# assert_select "ol>li", 4
|
||||
def assert_select_rjs(*args, &block)
|
||||
rjs_type = nil
|
||||
arg = args.shift
|
||||
rjs_type = args.first.is_a?(Symbol) ? args.shift : nil
|
||||
id = args.first.is_a?(String) ? args.shift : nil
|
||||
|
||||
# If the first argument is a symbol, it's the type of RJS statement we're looking
|
||||
# for (update, replace, insertion, etc). Otherwise, we're looking for just about
|
||||
# any RJS statement.
|
||||
if arg.is_a?(Symbol)
|
||||
rjs_type = arg
|
||||
|
||||
if rjs_type
|
||||
if rjs_type == :insert
|
||||
arg = args.shift
|
||||
insertion = "insert_#{arg}".to_sym
|
||||
raise ArgumentError, "Unknown RJS insertion type #{arg}" unless RJS_STATEMENTS[insertion]
|
||||
position = args.shift
|
||||
insertion = "insert_#{position}".to_sym
|
||||
raise ArgumentError, "Unknown RJS insertion type #{position}" unless RJS_STATEMENTS[insertion]
|
||||
statement = "(#{RJS_STATEMENTS[insertion]})"
|
||||
else
|
||||
raise ArgumentError, "Unknown RJS statement type #{rjs_type}" unless RJS_STATEMENTS[rjs_type]
|
||||
statement = "(#{RJS_STATEMENTS[rjs_type]})"
|
||||
end
|
||||
arg = args.shift
|
||||
else
|
||||
statement = "#{RJS_STATEMENTS[:any]}"
|
||||
end
|
||||
|
||||
# Next argument we're looking for is the element identifier. If missing, we pick
|
||||
# any element.
|
||||
if arg.is_a?(String)
|
||||
id = Regexp.quote(arg)
|
||||
arg = args.shift
|
||||
else
|
||||
id = "[^\"]*"
|
||||
end
|
||||
|
||||
pattern =
|
||||
case rjs_type
|
||||
when :chained_replace, :chained_replace_html
|
||||
Regexp.new("\\$\\(\"#{id}\"\\)#{statement}\\(#{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
|
||||
when :remove, :show, :hide, :toggle
|
||||
Regexp.new("#{statement}\\(\"#{id}\"\\)")
|
||||
else
|
||||
Regexp.new("#{statement}\\(\"#{id}\", #{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
|
||||
end
|
||||
# any element, otherwise we replace it in the statement.
|
||||
pattern = Regexp.new(
|
||||
id ? statement.gsub(RJS_ANY_ID, "\"#{id}\"") : statement
|
||||
)
|
||||
|
||||
# Duplicate the body since the next step involves destroying it.
|
||||
matches = nil
|
||||
|
@ -447,7 +431,7 @@ module ActionController
|
|||
matches = @response.body.match(pattern)
|
||||
else
|
||||
@response.body.gsub(pattern) do |match|
|
||||
html = unescape_rjs($2)
|
||||
html = unescape_rjs(match)
|
||||
matches ||= []
|
||||
matches.concat HTML::Document.new(html).root.children.select { |n| n.tag? }
|
||||
""
|
||||
|
@ -577,27 +561,23 @@ module ActionController
|
|||
|
||||
protected
|
||||
unless const_defined?(:RJS_STATEMENTS)
|
||||
RJS_STATEMENTS = {
|
||||
:replace => /Element\.replace/,
|
||||
:replace_html => /Element\.update/,
|
||||
:chained_replace => /\.replace/,
|
||||
:chained_replace_html => /\.update/,
|
||||
:remove => /Element\.remove/,
|
||||
:show => /Element\.show/,
|
||||
:hide => /Element\.hide/,
|
||||
:toggle => /Element\.toggle/
|
||||
RJS_PATTERN_HTML = "\"((\\\\\"|[^\"])*)\""
|
||||
RJS_ANY_ID = "\"([^\"])*\""
|
||||
RJS_STATEMENTS = {
|
||||
:chained_replace => "\\$\\(#{RJS_ANY_ID}\\)\\.replace\\(#{RJS_PATTERN_HTML}\\)",
|
||||
:chained_replace_html => "\\$\\(#{RJS_ANY_ID}\\)\\.update\\(#{RJS_PATTERN_HTML}\\)",
|
||||
:replace_html => "Element\\.update\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)",
|
||||
:replace => "Element\\.replace\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)"
|
||||
}
|
||||
RJS_INSERTIONS = [:top, :bottom, :before, :after]
|
||||
RJS_INSERTIONS.each do |insertion|
|
||||
RJS_STATEMENTS["insert_#{insertion}".to_sym] = Regexp.new(Regexp.quote("new Insertion.#{insertion.to_s.camelize}"))
|
||||
[:remove, :show, :hide, :toggle].each do |action|
|
||||
RJS_STATEMENTS[action] = "Element\\.#{action}\\(#{RJS_ANY_ID}\\)"
|
||||
end
|
||||
RJS_INSERTIONS = ["top", "bottom", "before", "after"]
|
||||
RJS_INSERTIONS.each do |insertion|
|
||||
RJS_STATEMENTS["insert_#{insertion}".to_sym] = "Element.insert\\(#{RJS_ANY_ID}, \\{ #{insertion}: #{RJS_PATTERN_HTML} \\}\\)"
|
||||
end
|
||||
RJS_STATEMENTS[:insert_html] = "Element.insert\\(#{RJS_ANY_ID}, \\{ (#{RJS_INSERTIONS.join('|')}): #{RJS_PATTERN_HTML} \\}\\)"
|
||||
RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})")
|
||||
RJS_STATEMENTS[:insert_html] = Regexp.new(RJS_INSERTIONS.collect do |insertion|
|
||||
Regexp.quote("new Insertion.#{insertion.to_s.camelize}")
|
||||
end.join('|'))
|
||||
RJS_PATTERN_HTML = /"((\\"|[^"])*)"/
|
||||
RJS_PATTERN_EVERYTHING = Regexp.new("#{RJS_STATEMENTS[:any]}\\(\"([^\"]*)\", #{RJS_PATTERN_HTML}\\)",
|
||||
Regexp::MULTILINE)
|
||||
RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/
|
||||
end
|
||||
|
||||
|
@ -611,8 +591,8 @@ module ActionController
|
|||
root = HTML::Node.new(nil)
|
||||
|
||||
while true
|
||||
next if body.sub!(RJS_PATTERN_EVERYTHING) do |match|
|
||||
html = unescape_rjs($3)
|
||||
next if body.sub!(RJS_STATEMENTS[:any]) do |match|
|
||||
html = unescape_rjs(match)
|
||||
matches = HTML::Document.new(html).root.children.select { |n| n.tag? }
|
||||
root.children.concat matches
|
||||
""
|
||||
|
|
|
@ -613,8 +613,9 @@ module ActionController #:nodoc:
|
|||
#
|
||||
# This takes the current URL as is and only exchanges the action. In contrast, <tt>url_for :action => 'print'</tt>
|
||||
# would have slashed-off the path components after the changed action.
|
||||
def url_for(options = nil) #:doc:
|
||||
case options || {}
|
||||
def url_for(options = {})
|
||||
options ||= {}
|
||||
case options
|
||||
when String
|
||||
options
|
||||
when Hash
|
||||
|
@ -743,6 +744,9 @@ module ActionController #:nodoc:
|
|||
# # Renders the template located in [TEMPLATE_ROOT]/weblog/show.r(html|xml) (in Rails, app/views/weblog/show.erb)
|
||||
# render :template => "weblog/show"
|
||||
#
|
||||
# # Renders the template with a local variable
|
||||
# render :template => "weblog/show", :locals => {:customer => Customer.new}
|
||||
#
|
||||
# === Rendering a file
|
||||
#
|
||||
# File rendering works just like action rendering except that it takes a filesystem path. By default, the path
|
||||
|
@ -865,7 +869,7 @@ module ActionController #:nodoc:
|
|||
render_for_file(file, options[:status], options[:use_full_path], options[:locals] || {})
|
||||
|
||||
elsif template = options[:template]
|
||||
render_for_file(template, options[:status], true)
|
||||
render_for_file(template, options[:status], true, options[:locals] || {})
|
||||
|
||||
elsif inline = options[:inline]
|
||||
add_variables_to_assigns
|
||||
|
@ -1147,7 +1151,7 @@ module ActionController #:nodoc:
|
|||
|
||||
def log_processing
|
||||
if logger && logger.info?
|
||||
logger.info "\n\nProcessing #{controller_class_name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
|
||||
logger.info "\n\nProcessing #{self.class.name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
|
||||
logger.info " Session ID: #{@_session.session_id}" if @_session and @_session.respond_to?(:session_id)
|
||||
logger.info " Parameters: #{respond_to?(:filter_parameters) ? filter_parameters(params).inspect : params.inspect}"
|
||||
end
|
||||
|
|
|
@ -135,7 +135,7 @@ module ActionController
|
|||
# be reloaded on the next request without restarting the server.
|
||||
def cleanup_application
|
||||
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
|
||||
Dependencies.clear
|
||||
ActiveSupport::Dependencies.clear
|
||||
ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
|
||||
end
|
||||
|
||||
|
|
|
@ -7,6 +7,200 @@ module ActionController #:nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc:
|
||||
def append_filter_to_chain(filters, filter_type, &block)
|
||||
pos = find_filter_append_position(filters, filter_type)
|
||||
update_filter_chain(filters, filter_type, pos, &block)
|
||||
end
|
||||
|
||||
def prepend_filter_to_chain(filters, filter_type, &block)
|
||||
pos = find_filter_prepend_position(filters, filter_type)
|
||||
update_filter_chain(filters, filter_type, pos, &block)
|
||||
end
|
||||
|
||||
def create_filters(filters, filter_type, &block)
|
||||
filters, conditions = extract_options(filters, &block)
|
||||
filters.map! { |filter| find_or_create_filter(filter, filter_type, conditions) }
|
||||
filters
|
||||
end
|
||||
|
||||
def skip_filter_in_chain(*filters, &test)
|
||||
filters, conditions = extract_options(filters)
|
||||
filters.each do |filter|
|
||||
if callback = find(filter) then delete(callback) end
|
||||
end if conditions.empty?
|
||||
update_filter_in_chain(filters, :skip => conditions, &test)
|
||||
end
|
||||
|
||||
private
|
||||
def update_filter_chain(filters, filter_type, pos, &block)
|
||||
new_filters = create_filters(filters, filter_type, &block)
|
||||
insert(pos, new_filters).flatten!
|
||||
end
|
||||
|
||||
def find_filter_append_position(filters, filter_type)
|
||||
# appending an after filter puts it at the end of the call chain
|
||||
# before and around filters go before the first after filter in the chain
|
||||
unless filter_type == :after
|
||||
each_with_index do |f,i|
|
||||
return i if f.after?
|
||||
end
|
||||
end
|
||||
return -1
|
||||
end
|
||||
|
||||
def find_filter_prepend_position(filters, filter_type)
|
||||
# prepending a before or around filter puts it at the front of the call chain
|
||||
# after filters go before the first after filter in the chain
|
||||
if filter_type == :after
|
||||
each_with_index do |f,i|
|
||||
return i if f.after?
|
||||
end
|
||||
return -1
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
def find_or_create_filter(filter, filter_type, options = {})
|
||||
update_filter_in_chain([filter], options)
|
||||
|
||||
if found_filter = find(filter) { |f| f.type == filter_type }
|
||||
found_filter
|
||||
else
|
||||
filter_kind = case
|
||||
when filter.respond_to?(:before) && filter_type == :before
|
||||
:before
|
||||
when filter.respond_to?(:after) && filter_type == :after
|
||||
:after
|
||||
else
|
||||
:filter
|
||||
end
|
||||
|
||||
case filter_type
|
||||
when :before
|
||||
BeforeFilter.new(filter_kind, filter, options)
|
||||
when :after
|
||||
AfterFilter.new(filter_kind, filter, options)
|
||||
else
|
||||
AroundFilter.new(filter_kind, filter, options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update_filter_in_chain(filters, options, &test)
|
||||
filters.map! { |f| block_given? ? find(f, &test) : find(f) }
|
||||
filters.compact!
|
||||
|
||||
map! do |filter|
|
||||
if filters.include?(filter)
|
||||
new_filter = filter.dup
|
||||
new_filter.options.merge!(options)
|
||||
new_filter
|
||||
else
|
||||
filter
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Filter < ActiveSupport::Callbacks::Callback #:nodoc:
|
||||
def before?
|
||||
self.class == BeforeFilter
|
||||
end
|
||||
|
||||
def after?
|
||||
self.class == AfterFilter
|
||||
end
|
||||
|
||||
def around?
|
||||
self.class == AroundFilter
|
||||
end
|
||||
|
||||
private
|
||||
def should_not_skip?(controller)
|
||||
if options[:skip]
|
||||
!included_in_action?(controller, options[:skip])
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def included_in_action?(controller, options)
|
||||
if options[:only]
|
||||
Array(options[:only]).map(&:to_s).include?(controller.action_name)
|
||||
elsif options[:except]
|
||||
!Array(options[:except]).map(&:to_s).include?(controller.action_name)
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def should_run_callback?(controller)
|
||||
should_not_skip?(controller) && included_in_action?(controller, options) && super
|
||||
end
|
||||
end
|
||||
|
||||
class AroundFilter < Filter #:nodoc:
|
||||
def type
|
||||
:around
|
||||
end
|
||||
|
||||
def call(controller, &block)
|
||||
if should_run_callback?(controller)
|
||||
method = filter_responds_to_before_and_after? ? around_proc : self.method
|
||||
|
||||
# For around_filter do |controller, action|
|
||||
if method.is_a?(Proc) && method.arity == 2
|
||||
evaluate_method(method, controller, block)
|
||||
else
|
||||
evaluate_method(method, controller, &block)
|
||||
end
|
||||
else
|
||||
block.call
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def filter_responds_to_before_and_after?
|
||||
method.respond_to?(:before) && method.respond_to?(:after)
|
||||
end
|
||||
|
||||
def around_proc
|
||||
Proc.new do |controller, action|
|
||||
method.before(controller)
|
||||
|
||||
if controller.send!(:performed?)
|
||||
controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
|
||||
else
|
||||
begin
|
||||
action.call
|
||||
ensure
|
||||
method.after(controller)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class BeforeFilter < Filter #:nodoc:
|
||||
def type
|
||||
:before
|
||||
end
|
||||
|
||||
def call(controller, &block)
|
||||
super
|
||||
if controller.send!(:performed?)
|
||||
controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class AfterFilter < Filter #:nodoc:
|
||||
def type
|
||||
:after
|
||||
end
|
||||
end
|
||||
|
||||
# Filters enable controllers to run shared pre- and post-processing code for its actions. These filters can be used to do
|
||||
# authentication, caching, or auditing before the intended action is performed. Or to do localization or output
|
||||
# compression after the action has been performed. Filters have access to the request, response, and all the instance
|
||||
|
@ -245,201 +439,6 @@ module ActionController #:nodoc:
|
|||
# filter and controller action will not be run. If +before+ renders or redirects,
|
||||
# the second half of +around+ and will still run but +after+ and the
|
||||
# action will not. If +around+ fails to yield, +after+ will not be run.
|
||||
|
||||
class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc:
|
||||
def append_filter_to_chain(filters, filter_type, &block)
|
||||
pos = find_filter_append_position(filters, filter_type)
|
||||
update_filter_chain(filters, filter_type, pos, &block)
|
||||
end
|
||||
|
||||
def prepend_filter_to_chain(filters, filter_type, &block)
|
||||
pos = find_filter_prepend_position(filters, filter_type)
|
||||
update_filter_chain(filters, filter_type, pos, &block)
|
||||
end
|
||||
|
||||
def create_filters(filters, filter_type, &block)
|
||||
filters, conditions = extract_options(filters, &block)
|
||||
filters.map! { |filter| find_or_create_filter(filter, filter_type, conditions) }
|
||||
filters
|
||||
end
|
||||
|
||||
def skip_filter_in_chain(*filters, &test)
|
||||
filters, conditions = extract_options(filters)
|
||||
filters.each do |filter|
|
||||
if callback = find(filter) then delete(callback) end
|
||||
end if conditions.empty?
|
||||
update_filter_in_chain(filters, :skip => conditions, &test)
|
||||
end
|
||||
|
||||
private
|
||||
def update_filter_chain(filters, filter_type, pos, &block)
|
||||
new_filters = create_filters(filters, filter_type, &block)
|
||||
insert(pos, new_filters).flatten!
|
||||
end
|
||||
|
||||
def find_filter_append_position(filters, filter_type)
|
||||
# appending an after filter puts it at the end of the call chain
|
||||
# before and around filters go before the first after filter in the chain
|
||||
unless filter_type == :after
|
||||
each_with_index do |f,i|
|
||||
return i if f.after?
|
||||
end
|
||||
end
|
||||
return -1
|
||||
end
|
||||
|
||||
def find_filter_prepend_position(filters, filter_type)
|
||||
# prepending a before or around filter puts it at the front of the call chain
|
||||
# after filters go before the first after filter in the chain
|
||||
if filter_type == :after
|
||||
each_with_index do |f,i|
|
||||
return i if f.after?
|
||||
end
|
||||
return -1
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
def find_or_create_filter(filter, filter_type, options = {})
|
||||
update_filter_in_chain([filter], options)
|
||||
|
||||
if found_filter = find(filter) { |f| f.type == filter_type }
|
||||
found_filter
|
||||
else
|
||||
filter_kind = case
|
||||
when filter.respond_to?(:before) && filter_type == :before
|
||||
:before
|
||||
when filter.respond_to?(:after) && filter_type == :after
|
||||
:after
|
||||
else
|
||||
:filter
|
||||
end
|
||||
|
||||
case filter_type
|
||||
when :before
|
||||
BeforeFilter.new(filter_kind, filter, options)
|
||||
when :after
|
||||
AfterFilter.new(filter_kind, filter, options)
|
||||
else
|
||||
AroundFilter.new(filter_kind, filter, options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update_filter_in_chain(filters, options, &test)
|
||||
filters.map! { |f| block_given? ? find(f, &test) : find(f) }
|
||||
filters.compact!
|
||||
|
||||
map! do |filter|
|
||||
if filters.include?(filter)
|
||||
new_filter = filter.dup
|
||||
new_filter.options.merge!(options)
|
||||
new_filter
|
||||
else
|
||||
filter
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Filter < ActiveSupport::Callbacks::Callback #:nodoc:
|
||||
def before?
|
||||
self.class == BeforeFilter
|
||||
end
|
||||
|
||||
def after?
|
||||
self.class == AfterFilter
|
||||
end
|
||||
|
||||
def around?
|
||||
self.class == AroundFilter
|
||||
end
|
||||
|
||||
private
|
||||
def should_not_skip?(controller)
|
||||
if options[:skip]
|
||||
!included_in_action?(controller, options[:skip])
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def included_in_action?(controller, options)
|
||||
if options[:only]
|
||||
Array(options[:only]).map(&:to_s).include?(controller.action_name)
|
||||
elsif options[:except]
|
||||
!Array(options[:except]).map(&:to_s).include?(controller.action_name)
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def should_run_callback?(controller)
|
||||
should_not_skip?(controller) && included_in_action?(controller, options) && super
|
||||
end
|
||||
end
|
||||
|
||||
class AroundFilter < Filter #:nodoc:
|
||||
def type
|
||||
:around
|
||||
end
|
||||
|
||||
def call(controller, &block)
|
||||
if should_run_callback?(controller)
|
||||
method = filter_responds_to_before_and_after? ? around_proc : self.method
|
||||
|
||||
# For around_filter do |controller, action|
|
||||
if method.is_a?(Proc) && method.arity == 2
|
||||
evaluate_method(method, controller, block)
|
||||
else
|
||||
evaluate_method(method, controller, &block)
|
||||
end
|
||||
else
|
||||
block.call
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def filter_responds_to_before_and_after?
|
||||
method.respond_to?(:before) && method.respond_to?(:after)
|
||||
end
|
||||
|
||||
def around_proc
|
||||
Proc.new do |controller, action|
|
||||
method.before(controller)
|
||||
|
||||
if controller.send!(:performed?)
|
||||
controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
|
||||
else
|
||||
begin
|
||||
action.call
|
||||
ensure
|
||||
method.after(controller)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class BeforeFilter < Filter #:nodoc:
|
||||
def type
|
||||
:before
|
||||
end
|
||||
|
||||
def call(controller, &block)
|
||||
super
|
||||
if controller.send!(:performed?)
|
||||
controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class AfterFilter < Filter #:nodoc:
|
||||
def type
|
||||
:after
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# The passed <tt>filters</tt> will be appended to the filter_chain and
|
||||
# will execute before the action on this controller is performed.
|
||||
|
|
|
@ -48,6 +48,9 @@ module ActionController
|
|||
#
|
||||
# # 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"
|
||||
#
|
||||
# ==== Options
|
||||
#
|
||||
|
@ -83,8 +86,6 @@ module ActionController
|
|||
else [ record_or_hash_or_array ]
|
||||
end
|
||||
|
||||
args << format if format
|
||||
|
||||
inflection =
|
||||
case
|
||||
when options[:action].to_s == "new"
|
||||
|
@ -96,6 +97,9 @@ module ActionController
|
|||
else
|
||||
:singular
|
||||
end
|
||||
|
||||
args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
|
||||
args << format if format
|
||||
|
||||
named_route = build_named_route_call(record_or_hash_or_array, namespace, inflection, options)
|
||||
send!(named_route, *args)
|
||||
|
@ -136,11 +140,19 @@ module ActionController
|
|||
else
|
||||
record = records.pop
|
||||
route = records.inject("") do |string, parent|
|
||||
string << "#{RecordIdentifier.send!("singular_class_name", parent)}_"
|
||||
if parent.is_a?(Symbol) || parent.is_a?(String)
|
||||
string << "#{parent}_"
|
||||
else
|
||||
string << "#{RecordIdentifier.send!("singular_class_name", parent)}_"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_"
|
||||
if record.is_a?(Symbol) || record.is_a?(String)
|
||||
route << "#{record}_"
|
||||
else
|
||||
route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_"
|
||||
end
|
||||
|
||||
action_prefix(options) + namespace + route + routing_type(options).to_s
|
||||
end
|
||||
|
@ -163,16 +175,17 @@ module ActionController
|
|||
end
|
||||
end
|
||||
|
||||
# Remove the first symbols from the array and return the url prefix
|
||||
# implied by those symbols.
|
||||
def extract_namespace(record_or_hash_or_array)
|
||||
returning "" do |namespace|
|
||||
if record_or_hash_or_array.is_a?(Array)
|
||||
record_or_hash_or_array.delete_if do |record_or_namespace|
|
||||
if record_or_namespace.is_a?(String) || record_or_namespace.is_a?(Symbol)
|
||||
namespace << "#{record_or_namespace}_"
|
||||
end
|
||||
end
|
||||
end
|
||||
return "" unless record_or_hash_or_array.is_a?(Array)
|
||||
|
||||
namespace_keys = []
|
||||
while (key = record_or_hash_or_array.first) && key.is_a?(String) || key.is_a?(Symbol)
|
||||
namespace_keys << record_or_hash_or_array.shift
|
||||
end
|
||||
|
||||
namespace_keys.map {|k| "#{k}_"}.join
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,18 +31,21 @@ module ActionController
|
|||
module RecordIdentifier
|
||||
extend self
|
||||
|
||||
JOIN = '_'.freeze
|
||||
NEW = 'new'.freeze
|
||||
|
||||
# Returns plural/singular for a record or class. Example:
|
||||
#
|
||||
# partial_path(post) # => "posts/post"
|
||||
# partial_path(Person) # => "people/person"
|
||||
# partial_path(Person, "admin/games") # => "admin/people/person"
|
||||
def partial_path(record_or_class, controller_path = nil)
|
||||
klass = class_from_record_or_class(record_or_class)
|
||||
name = model_name_from_record_or_class(record_or_class)
|
||||
|
||||
if controller_path && controller_path.include?("/")
|
||||
"#{File.dirname(controller_path)}/#{klass.name.tableize}/#{klass.name.demodulize.underscore}"
|
||||
"#{File.dirname(controller_path)}/#{name.partial_path}"
|
||||
else
|
||||
"#{klass.name.tableize}/#{klass.name.demodulize.underscore}"
|
||||
name.partial_path
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -56,21 +59,25 @@ module ActionController
|
|||
# dom_class(post, :edit) # => "edit_post"
|
||||
# dom_class(Person, :edit) # => "edit_person"
|
||||
def dom_class(record_or_class, prefix = nil)
|
||||
[ prefix, singular_class_name(record_or_class) ].compact * '_'
|
||||
singular = singular_class_name(record_or_class)
|
||||
prefix ? "#{prefix}#{JOIN}#{singular}" : singular
|
||||
end
|
||||
|
||||
# The DOM id convention is to use the singular form of an object or class with the id following an underscore.
|
||||
# If no id is found, prefix with "new_" instead. Examples:
|
||||
#
|
||||
# dom_id(Post.new(:id => 45)) # => "post_45"
|
||||
# dom_id(Post.find(45)) # => "post_45"
|
||||
# dom_id(Post.new) # => "new_post"
|
||||
#
|
||||
# If you need to address multiple instances of the same class in the same view, you can prefix the dom_id:
|
||||
#
|
||||
# dom_id(Post.new(:id => 45), :edit) # => "edit_post_45"
|
||||
# dom_id(Post.find(45), :edit) # => "edit_post_45"
|
||||
def dom_id(record, prefix = nil)
|
||||
prefix ||= 'new' unless record.id
|
||||
[ prefix, singular_class_name(record), record.id ].compact * '_'
|
||||
if record_id = record.id
|
||||
"#{dom_class(record, prefix)}#{JOIN}#{record_id}"
|
||||
else
|
||||
dom_class(record, prefix || NEW)
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the plural class name of a record or class. Examples:
|
||||
|
@ -78,7 +85,7 @@ module ActionController
|
|||
# plural_class_name(post) # => "posts"
|
||||
# plural_class_name(Highrise::Person) # => "highrise_people"
|
||||
def plural_class_name(record_or_class)
|
||||
singular_class_name(record_or_class).pluralize
|
||||
model_name_from_record_or_class(record_or_class).plural
|
||||
end
|
||||
|
||||
# Returns the singular class name of a record or class. Examples:
|
||||
|
@ -86,12 +93,12 @@ module ActionController
|
|||
# singular_class_name(post) # => "post"
|
||||
# singular_class_name(Highrise::Person) # => "highrise_person"
|
||||
def singular_class_name(record_or_class)
|
||||
class_from_record_or_class(record_or_class).name.underscore.tr('/', '_')
|
||||
model_name_from_record_or_class(record_or_class).singular
|
||||
end
|
||||
|
||||
private
|
||||
def class_from_record_or_class(record_or_class)
|
||||
record_or_class.is_a?(Class) ? record_or_class : record_or_class.class
|
||||
def model_name_from_record_or_class(record_or_class)
|
||||
(record_or_class.is_a?(Class) ? record_or_class : record_or_class.class).model_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -134,14 +134,17 @@ module ActionController
|
|||
# REMOTE_ADDR is a proxy. HTTP_X_FORWARDED_FOR may be a comma-
|
||||
# delimited list in the case of multiple chained proxies; the last
|
||||
# address which is not trusted is the originating IP.
|
||||
|
||||
def remote_ip
|
||||
if TRUSTED_PROXIES !~ @env['REMOTE_ADDR']
|
||||
return @env['REMOTE_ADDR']
|
||||
remote_addr_list = @env['REMOTE_ADDR'] && @env['REMOTE_ADDR'].split(',').collect(&:strip)
|
||||
|
||||
unless remote_addr_list.blank?
|
||||
not_trusted_addrs = remote_addr_list.reject {|addr| addr =~ TRUSTED_PROXIES}
|
||||
return not_trusted_addrs.first unless not_trusted_addrs.empty?
|
||||
end
|
||||
remote_ips = @env['HTTP_X_FORWARDED_FOR'] && @env['HTTP_X_FORWARDED_FOR'].split(',')
|
||||
|
||||
if @env.include? 'HTTP_CLIENT_IP'
|
||||
if @env.include? 'HTTP_X_FORWARDED_FOR'
|
||||
if remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
|
||||
# We don't know which came from the proxy, and which from the user
|
||||
raise ActionControllerError.new(<<EOM)
|
||||
IP spoofing attack?!
|
||||
|
@ -149,11 +152,11 @@ HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}
|
|||
HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}
|
||||
EOM
|
||||
end
|
||||
|
||||
return @env['HTTP_CLIENT_IP']
|
||||
end
|
||||
|
||||
if @env.include? 'HTTP_X_FORWARDED_FOR' then
|
||||
remote_ips = @env['HTTP_X_FORWARDED_FOR'].split(',')
|
||||
if remote_ips
|
||||
while remote_ips.size > 1 && TRUSTED_PROXIES =~ remote_ips.last.strip
|
||||
remote_ips.pop
|
||||
end
|
||||
|
|
|
@ -88,6 +88,10 @@ module ActionController
|
|||
#
|
||||
# map.connect ':controller/:action/:id', :action => 'show', :defaults => { :page => 'Dashboard' }
|
||||
#
|
||||
# Note: The default routes, as provided by the Rails generator, make all actions in every
|
||||
# controller accessible via GET requests. You should consider removing them or commenting
|
||||
# them out if you're using named routes and resources.
|
||||
#
|
||||
# == Named routes
|
||||
#
|
||||
# Routes can be named with the syntax <tt>map.name_of_route options</tt>,
|
||||
|
@ -369,7 +373,7 @@ module ActionController
|
|||
|
||||
Routes = RouteSet.new
|
||||
|
||||
::Inflector.module_eval do
|
||||
ActiveSupport::Inflector.module_eval do
|
||||
# Ensures that routes are reloaded when Rails inflections are updated.
|
||||
def inflections_with_route_reloading(&block)
|
||||
returning(inflections_without_route_reloading(&block)) {
|
||||
|
|
|
@ -67,10 +67,9 @@ module ActionController
|
|||
options = options.dup
|
||||
|
||||
if options[:namespace]
|
||||
options[:controller] = "#{options[:path_prefix]}/#{options[:controller]}"
|
||||
options[:controller] = "#{options.delete(:namespace).sub(/\/$/, '')}/#{options[:controller]}"
|
||||
options.delete(:path_prefix)
|
||||
options.delete(:name_prefix)
|
||||
options.delete(:namespace)
|
||||
end
|
||||
|
||||
requirements = (options.delete(:requirements) || {}).dup
|
||||
|
|
|
@ -248,7 +248,7 @@ module ActionController
|
|||
end
|
||||
|
||||
def extract_value
|
||||
"#{local_name} = hash[:#{key}] && hash[:#{key}].collect { |path_component| CGI.escape(path_component.to_param, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}"
|
||||
"#{local_name} = hash[:#{key}] && Array(hash[:#{key}]).collect { |path_component| CGI.escape(path_component.to_param, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}"
|
||||
end
|
||||
|
||||
def default
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Action Controller: Exception caught</title>
|
||||
<style>
|
||||
|
|
|
@ -171,7 +171,7 @@ module ActionController #:nodoc:
|
|||
|
||||
# Was the response successful?
|
||||
def success?
|
||||
response_code == 200
|
||||
(200..299).include?(response_code)
|
||||
end
|
||||
|
||||
# Was the URL not found?
|
||||
|
@ -333,7 +333,7 @@ module ActionController #:nodoc:
|
|||
attr_reader :original_filename
|
||||
|
||||
# The content type of the "uploaded" file
|
||||
attr_reader :content_type
|
||||
attr_accessor :content_type
|
||||
|
||||
def initialize(path, content_type = Mime::TEXT, binary = false)
|
||||
raise "#{path} file does not exist" unless File.exist?(path)
|
||||
|
@ -413,6 +413,8 @@ module ActionController #:nodoc:
|
|||
get(@response.redirected_to.delete(:action), @response.redirected_to.stringify_keys)
|
||||
end
|
||||
|
||||
deprecate :follow_redirect => "If you wish to follow redirects, you should use integration tests"
|
||||
|
||||
def assigns(key = nil)
|
||||
if key.nil?
|
||||
@response.template.assigns
|
||||
|
|
|
@ -17,7 +17,7 @@ module HTML #:nodoc:
|
|||
@root = Node.new(nil)
|
||||
node_stack = [ @root ]
|
||||
while token = tokenizer.next
|
||||
node = Node.parse(node_stack.last, tokenizer.line, tokenizer.position, token)
|
||||
node = Node.parse(node_stack.last, tokenizer.line, tokenizer.position, token, strict)
|
||||
|
||||
node_stack.last.children << node unless node.tag? && node.closing == :close
|
||||
if node.tag?
|
||||
|
|
|
@ -116,7 +116,7 @@ module ActionController #:nodoc:
|
|||
end
|
||||
|
||||
def apply_redirect_to(redirect_to_option) # :nodoc:
|
||||
redirect_to_option.is_a?(Symbol) ? self.send!(redirect_to_option) : redirect_to_option
|
||||
(redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.send!(redirect_to_option) : redirect_to_option
|
||||
end
|
||||
|
||||
def apply_remaining_actions(options) # :nodoc:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue