aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2008-08-28 11:36:56 +0100
committerPratik Naik <pratiknaik@gmail.com>2008-08-28 11:36:56 +0100
commit3e3945b2fafb9ccedfd9ff181c31b18f5d4cd0ce (patch)
treecd86abce0ab9accbbbf24018961464590fa6bb39 /actionpack
parent5db2f199aba9aa8d00adefa8237922ad684aca03 (diff)
parent96c6fe084228d570dad80e3100830edb2bc0448d (diff)
downloadrails-3e3945b2fafb9ccedfd9ff181c31b18f5d4cd0ce.tar.gz
rails-3e3945b2fafb9ccedfd9ff181c31b18f5d4cd0ce.tar.bz2
rails-3e3945b2fafb9ccedfd9ff181c31b18f5d4cd0ce.zip
Merge commit 'mainstream/master'
Conflicts: activerecord/lib/active_record/associations/association_proxy.rb activerecord/lib/active_record/callbacks.rb activeresource/lib/active_resource/base.rb
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG8
-rw-r--r--actionpack/lib/action_controller.rb15
-rw-r--r--actionpack/lib/action_controller/base.rb46
-rw-r--r--actionpack/lib/action_controller/dispatcher.rb6
-rw-r--r--actionpack/lib/action_controller/integration.rb78
-rw-r--r--actionpack/lib/action_controller/mime_type.rb2
-rw-r--r--actionpack/lib/action_controller/polymorphic_routes.rb16
-rw-r--r--actionpack/lib/action_controller/rack_process.rb102
-rwxr-xr-x[-rw-r--r--]actionpack/lib/action_controller/request.rb10
-rw-r--r--actionpack/lib/action_controller/rescue.rb2
-rw-r--r--actionpack/lib/action_controller/response.rb55
-rw-r--r--actionpack/lib/action_controller/templates/rescues/diagnostics.erb4
-rw-r--r--actionpack/lib/action_controller/templates/rescues/template_error.erb4
-rw-r--r--actionpack/lib/action_controller/test_process.rb36
-rw-r--r--actionpack/lib/action_view.rb20
-rw-r--r--actionpack/lib/action_view/base.rb104
-rw-r--r--actionpack/lib/action_view/helpers.rb39
-rw-r--r--actionpack/lib/action_view/helpers/active_record_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/atom_feed_helper.rb24
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/sanitize_helper.rb96
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb54
-rw-r--r--actionpack/lib/action_view/helpers/translation_helper.rb2
-rw-r--r--actionpack/lib/action_view/locale/en-US.rb53
-rw-r--r--actionpack/lib/action_view/locale/en-US.yml91
-rw-r--r--actionpack/lib/action_view/partials.rb137
-rw-r--r--actionpack/lib/action_view/paths.rb28
-rw-r--r--actionpack/lib/action_view/renderable.rb11
-rw-r--r--actionpack/lib/action_view/renderable_partial.rb6
-rw-r--r--actionpack/lib/action_view/template.rb2
-rw-r--r--actionpack/lib/action_view/template_error.rb2
-rw-r--r--actionpack/lib/action_view/test_case.rb4
-rw-r--r--actionpack/test/activerecord/render_partial_with_record_identification_test.rb10
-rw-r--r--actionpack/test/controller/content_type_test.rb20
-rw-r--r--actionpack/test/controller/integration_test.rb90
-rw-r--r--actionpack/test/controller/layout_test.rb19
-rw-r--r--actionpack/test/controller/new_render_test.rb9
-rw-r--r--actionpack/test/controller/polymorphic_routes_test.rb22
-rw-r--r--actionpack/test/controller/rack_test.rb39
-rw-r--r--actionpack/test/controller/render_test.rb2
-rw-r--r--actionpack/test/controller/request_test.rb27
-rw-r--r--actionpack/test/controller/test_test.rb5
-rw-r--r--actionpack/test/fixtures/test/_layout_for_block_with_args.html.erb3
-rw-r--r--actionpack/test/fixtures/test/using_layout_around_block_with_args.html.erb1
-rw-r--r--actionpack/test/template/active_record_helper_i18n_test.rb28
-rw-r--r--actionpack/test/template/atom_feed_helper_test.rb37
-rw-r--r--actionpack/test/template/date_helper_i18n_test.rb22
-rw-r--r--actionpack/test/template/render_test.rb12
-rw-r--r--actionpack/test/template/sanitize_helper_test.rb6
-rw-r--r--actionpack/test/template/text_helper_test.rb34
-rw-r--r--actionpack/test/template/url_helper_test.rb1
52 files changed, 984 insertions, 480 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 6f65d4003d..f6942b43f1 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,13 @@
*Edge*
+* Introduce current_cycle helper method to return the current value without bumping the cycle. #417 [Ken Collins]
+
+* Allow polymorphic_url helper to take url options. #880 [Tarmo Tänav]
+
+* Switched integration test runner to use Rack processor instead of CGI [Josh Peek]
+
+* Made AbstractRequest.if_modified_sense return nil if the header could not be parsed [Jamis Buck]
+
* Added back ActionController::Base.allow_concurrency flag [Josh Peek]
* AbstractRequest.relative_url_root is no longer automatically configured by a HTTP header. It can now be set in your configuration environment with config.action_controller.relative_url_root [Josh Peek]
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 3c4a339d50..e58071d4af 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -21,16 +21,13 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-$:.unshift(File.dirname(__FILE__)) unless
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
-
-unless defined?(ActiveSupport)
- begin
- $:.unshift "#{File.dirname(__FILE__)}/../../activesupport/lib"
+begin
+ require 'active_support'
+rescue LoadError
+ activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
+ if File.directory?(activesupport_path)
+ $:.unshift activesupport_path
require 'active_support'
- rescue LoadError
- require 'rubygems'
- gem 'activesupport'
end
end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 0fdbcbd26f..55e1d48949 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -548,7 +548,6 @@ module ActionController #:nodoc:
@@guard.synchronize { send(method, *arguments) }
end
- assign_default_content_type_and_charset
response.prepare! unless component_request?
response
ensure
@@ -781,9 +780,6 @@ module ActionController #:nodoc:
# render :file => "/path/to/some/template.erb", :layout => true, :status => 404
# render :file => "c:/path/to/some/template.erb", :layout => true, :status => 404
#
- # # Renders a template relative to the template root and chooses the proper file extension
- # render :file => "some/template", :use_full_path => true
- #
# === Rendering text
#
# Rendering of text is usually used for tests or for rendering prepared content, such as a cache. By default, text
@@ -914,21 +910,10 @@ module ActionController #:nodoc:
response.content_type ||= Mime::JSON
render_for_text(json, options[:status])
- elsif partial = options[:partial]
- partial = default_template_name if partial == true
+ elsif options[:partial]
+ options[:partial] = default_template_name if options[:partial] == true
add_variables_to_assigns
-
- if collection = options[:collection]
- render_for_text(
- @template.send!(:render_partial_collection, partial, collection,
- options[:spacer_template], options[:locals], options[:as]), options[:status]
- )
- else
- render_for_text(
- @template.send!(:render_partial, partial,
- options[:object], options[:locals]), options[:status]
- )
- end
+ render_for_text(@template.render(options), options[:status])
elsif options[:update]
add_variables_to_assigns
@@ -939,8 +924,7 @@ module ActionController #:nodoc:
render_for_text(generator.to_s, options[:status])
elsif options[:nothing]
- # Safari doesn't pass the headers of the return if the response is zero length
- render_for_text(" ", options[:status])
+ render_for_text(nil, options[:status])
else
render_for_file(default_template_name, options[:status], true)
@@ -1154,13 +1138,17 @@ module ActionController #:nodoc:
response.body ||= ''
response.body << text.to_s
else
- response.body = text.is_a?(Proc) ? text : text.to_s
+ response.body = case text
+ when Proc then text
+ when nil then " " # Safari doesn't pass the headers of the return if the response is zero length
+ else text.to_s
+ end
end
end
def initialize_template_class(response)
response.template = ActionView::Base.new(self.class.view_paths, {}, self)
- response.template.extend self.class.master_helper_module
+ response.template.helpers.send :include, self.class.master_helper_module
response.redirected_to = nil
@performed_render = @performed_redirect = false
end
@@ -1201,7 +1189,7 @@ module ActionController #:nodoc:
elsif respond_to? :method_missing
method_missing action_name
default_render unless performed?
- elsif template_exists? && template_public?
+ elsif template_exists?
default_render
else
raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence}", caller
@@ -1217,13 +1205,9 @@ module ActionController #:nodoc:
end
def assign_default_content_type_and_charset
- response.content_type ||= Mime::HTML
- response.charset ||= self.class.default_charset unless sending_file?
- end
-
- def sending_file?
- response.headers["Content-Transfer-Encoding"] == "binary"
+ response.assign_default_content_type_and_charset!
end
+ deprecate :assign_default_content_type_and_charset => :'response.assign_default_content_type_and_charset!'
def action_methods
self.class.action_methods
@@ -1280,10 +1264,6 @@ module ActionController #:nodoc:
@template.file_exists?(template_name)
end
- def template_public?(template_name = default_template_name)
- @template.file_public?(template_name)
- end
-
def template_exempt_from_layout?(template_name = default_template_name)
template_name = @template.pick_template(template_name).to_s if @template
@@exempt_from_layout.any? { |ext| template_name =~ ext }
diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb
index 835d8e834e..bdae5f9d86 100644
--- a/actionpack/lib/action_controller/dispatcher.rb
+++ b/actionpack/lib/action_controller/dispatcher.rb
@@ -24,7 +24,7 @@ module ActionController
to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers }
end
- after_dispatch :flush_logger if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush)
+ after_dispatch :flush_logger if Base.logger && Base.logger.respond_to?(:flush)
end
# Backward-compatible class method takes CGI-specific args. Deprecated
@@ -44,7 +44,7 @@ module ActionController
def to_prepare(identifier = nil, &block)
@prepare_dispatch_callbacks ||= ActiveSupport::Callbacks::CallbackChain.new
callback = ActiveSupport::Callbacks::Callback.new(:prepare_dispatch, block, :identifier => identifier)
- @prepare_dispatch_callbacks | callback
+ @prepare_dispatch_callbacks.replace_or_append!(callback)
end
# If the block raises, send status code as a last-ditch response.
@@ -142,7 +142,7 @@ module ActionController
end
def flush_logger
- RAILS_DEFAULT_LOGGER.flush
+ Base.logger.flush
end
protected
diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb
index 1d2b81355c..198a22e8dc 100644
--- a/actionpack/lib/action_controller/integration.rb
+++ b/actionpack/lib/action_controller/integration.rb
@@ -228,21 +228,6 @@ module ActionController
end
private
- class StubCGI < CGI #:nodoc:
- attr_accessor :stdinput, :stdoutput, :env_table
-
- def initialize(env, stdinput = nil)
- self.env_table = env
- self.stdoutput = StringIO.new
-
- super
-
- stdinput.set_encoding(Encoding::BINARY) if stdinput.respond_to?(:set_encoding)
- stdinput.force_encoding(Encoding::BINARY) if stdinput.respond_to?(:force_encoding)
- @stdinput = stdinput.is_a?(IO) ? stdinput : StringIO.new(stdinput || '')
- end
- end
-
# Tailors the session based on the given URI, setting the HTTPS value
# and the hostname.
def interpret_uri(path)
@@ -290,9 +275,8 @@ module ActionController
ActionController::Base.clear_last_instantiation!
- cgi = StubCGI.new(env, data)
- ActionController::Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, cgi.stdoutput)
- @result = cgi.stdoutput.string
+ env['rack.input'] = data.is_a?(IO) ? data : StringIO.new(data || '')
+ @status, @headers, result_body = ActionController::Dispatcher.new.call(env)
@request_count += 1
@controller = ActionController::Base.last_instantiation
@@ -306,32 +290,34 @@ module ActionController
@html_document = nil
- parse_result
- return status
- rescue MultiPartNeededException
- boundary = "----------XnJLe9ZIbbGUYtzPQJ16u1"
- status = process(method, path, multipart_body(parameters, boundary), (headers || {}).merge({"CONTENT_TYPE" => "multipart/form-data; boundary=#{boundary}"}))
- return status
- end
+ # Inject status back in for backwords compatibility with CGI
+ @headers['Status'] = @status
- # Parses the result of the response and extracts the various values,
- # like cookies, status, headers, etc.
- def parse_result
- response_headers, result_body = @result.split(/\r\n\r\n/, 2)
+ @status, @status_message = @status.split(/ /)
+ @status = @status.to_i
- @headers = Hash.new { |h,k| h[k] = [] }
- response_headers.to_s.each_line do |line|
- key, value = line.strip.split(/:\s*/, 2)
- @headers[key.downcase] << value
+ cgi_headers = Hash.new { |h,k| h[k] = [] }
+ @headers.each do |key, value|
+ cgi_headers[key.downcase] << value
end
+ cgi_headers['set-cookie'] = cgi_headers['set-cookie'].first
+ @headers = cgi_headers
- (@headers['set-cookie'] || [] ).each do |string|
- name, value = string.match(/^([^=]*)=([^;]*);/)[1,2]
+ @response.headers['cookie'] ||= []
+ (@headers['set-cookie'] || []).each do |cookie|
+ name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2]
@cookies[name] = value
+
+ # Fake CGI cookie header
+ # DEPRECATE: Use response.headers["Set-Cookie"] instead
+ @response.headers['cookie'] << CGI::Cookie::new("name" => name, "value" => value)
end
- @status, @status_message = @headers["status"].first.to_s.split(/ /)
- @status = @status.to_i
+ return status
+ rescue MultiPartNeededException
+ boundary = "----------XnJLe9ZIbbGUYtzPQJ16u1"
+ status = process(method, path, multipart_body(parameters, boundary), (headers || {}).merge({"CONTENT_TYPE" => "multipart/form-data; boundary=#{boundary}"}))
+ return status
end
# Encode the cookies hash in a format suitable for passing to a
@@ -344,13 +330,15 @@ module ActionController
# Get a temporary URL writer object
def generic_url_rewriter
- cgi = StubCGI.new('REQUEST_METHOD' => "GET",
- 'QUERY_STRING' => "",
- "REQUEST_URI" => "/",
- "HTTP_HOST" => host,
- "SERVER_PORT" => https? ? "443" : "80",
- "HTTPS" => https? ? "on" : "off")
- ActionController::UrlRewriter.new(ActionController::CgiRequest.new(cgi), {})
+ env = {
+ 'REQUEST_METHOD' => "GET",
+ 'QUERY_STRING' => "",
+ "REQUEST_URI" => "/",
+ "HTTP_HOST" => host,
+ "SERVER_PORT" => https? ? "443" : "80",
+ "HTTPS" => https? ? "on" : "off"
+ }
+ ActionController::UrlRewriter.new(ActionController::RackRequest.new(env), {})
end
def name_with_prefix(prefix, name)
@@ -451,7 +439,7 @@ EOF
end
%w(get post put head delete cookies assigns
- xml_http_request get_via_redirect post_via_redirect).each do |method|
+ xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
define_method(method) do |*args|
reset! unless @integration_session
# reset the html_document variable, but only for new get/post calls
diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb
index a7215e6ea3..26edca3b69 100644
--- a/actionpack/lib/action_controller/mime_type.rb
+++ b/actionpack/lib/action_controller/mime_type.rb
@@ -1,3 +1,5 @@
+require 'set'
+
module Mime
SET = []
EXTENSION_LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb
index 7c30bf0778..30564c7bb3 100644
--- a/actionpack/lib/action_controller/polymorphic_routes.rb
+++ b/actionpack/lib/action_controller/polymorphic_routes.rb
@@ -102,6 +102,12 @@ module ActionController
args << format if format
named_route = build_named_route_call(record_or_hash_or_array, namespace, inflection, options)
+
+ url_options = options.except(:action, :routing_type, :format)
+ unless url_options.empty?
+ args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options
+ end
+
send!(named_route, *args)
end
@@ -114,19 +120,19 @@ module ActionController
%w(edit new formatted).each do |action|
module_eval <<-EOT, __FILE__, __LINE__
- def #{action}_polymorphic_url(record_or_hash)
- polymorphic_url(record_or_hash, :action => "#{action}")
+ def #{action}_polymorphic_url(record_or_hash, options = {})
+ polymorphic_url(record_or_hash, options.merge(:action => "#{action}"))
end
- def #{action}_polymorphic_path(record_or_hash)
- polymorphic_url(record_or_hash, :action => "#{action}", :routing_type => :path)
+ def #{action}_polymorphic_path(record_or_hash, options = {})
+ polymorphic_url(record_or_hash, options.merge(:action => "#{action}", :routing_type => :path))
end
EOT
end
private
def action_prefix(options)
- options[:action] ? "#{options[:action]}_" : ""
+ options[:action] ? "#{options[:action]}_" : options[:format] ? "formatted_" : ""
end
def routing_type(options)
diff --git a/actionpack/lib/action_controller/rack_process.rb b/actionpack/lib/action_controller/rack_process.rb
index dcbcf8bc1d..1ace16da07 100644
--- a/actionpack/lib/action_controller/rack_process.rb
+++ b/actionpack/lib/action_controller/rack_process.rb
@@ -25,7 +25,7 @@ module ActionController #:nodoc:
end
%w[ AUTH_TYPE GATEWAY_INTERFACE PATH_INFO
- PATH_TRANSLATED QUERY_STRING REMOTE_HOST
+ PATH_TRANSLATED REMOTE_HOST
REMOTE_IDENT REMOTE_USER SCRIPT_NAME
SERVER_NAME SERVER_PROTOCOL
@@ -37,6 +37,15 @@ module ActionController #:nodoc:
end
end
+ def query_string
+ qs = super
+ if !qs.blank?
+ qs
+ else
+ @env['QUERY_STRING']
+ end
+ end
+
def body_stream #:nodoc:
@env['rack.input']
end
@@ -143,23 +152,30 @@ end_msg
end
class RackResponse < AbstractResponse #:nodoc:
- attr_accessor :status
-
def initialize(request)
- @request = request
+ @cgi = request.cgi
@writer = lambda { |x| @body << x }
@block = nil
super()
end
+ # Retrieve status from instance variable if has already been delete
+ def status
+ @status || super
+ end
+
def out(output = $stdout, &block)
+ # Nasty hack because CGI sessions are closed after the normal
+ # prepare! statement
+ set_cookies!
+
@block = block
- normalize_headers(@headers)
- if [204, 304].include?(@status.to_i)
- @headers.delete "Content-Type"
- [status, @headers.to_hash, []]
+ @status = headers.delete("Status")
+ if [204, 304].include?(status.to_i)
+ headers.delete("Content-Type")
+ [status, headers.to_hash, []]
else
- [status, @headers.to_hash, self]
+ [status, headers.to_hash, self]
end
end
alias to_a out
@@ -191,43 +207,57 @@ end_msg
@block == nil && @body.empty?
end
- private
- def normalize_headers(options = "text/html")
- if options.is_a?(String)
- headers['Content-Type'] = options unless headers['Content-Type']
- else
- headers['Content-Length'] = options.delete('Content-Length').to_s if options['Content-Length']
+ def prepare!
+ super
- headers['Content-Type'] = options.delete('type') || "text/html"
- headers['Content-Type'] += "; charset=" + options.delete('charset') if options['charset']
+ convert_language!
+ convert_expires!
+ set_status!
+ # set_cookies!
+ end
- headers['Content-Language'] = options.delete('language') if options['language']
- headers['Expires'] = options.delete('expires') if options['expires']
+ private
+ def convert_language!
+ headers["Content-Language"] = headers.delete("language") if headers["language"]
+ end
- @status = options.delete('Status') || "200 OK"
+ def convert_expires!
+ headers["Expires"] = headers.delete("") if headers["expires"]
+ end
- # Convert 'cookie' header to 'Set-Cookie' headers.
- # Because Set-Cookie header can appear more the once in the response body,
- # we store it in a line break separated string that will be translated to
- # multiple Set-Cookie header by the handler.
- if cookie = options.delete('cookie')
- cookies = []
+ def convert_content_type!
+ super
+ headers['Content-Type'] = headers.delete('type') || "text/html"
+ headers['Content-Type'] += "; charset=" + headers.delete('charset') if headers['charset']
+ end
- case cookie
- when Array then cookie.each { |c| cookies << c.to_s }
- when Hash then cookie.each { |_, c| cookies << c.to_s }
- else cookies << cookie.to_s
- end
+ def set_content_length!
+ super
+ headers["Content-Length"] = headers["Content-Length"].to_s if headers["Content-Length"]
+ end
- @request.cgi.output_cookies.each { |c| cookies << c.to_s } if @request.cgi.output_cookies
+ def set_status!
+ self.status ||= "200 OK"
+ end
- headers['Set-Cookie'] = [headers['Set-Cookie'], cookies].flatten.compact
+ def set_cookies!
+ # Convert 'cookie' header to 'Set-Cookie' headers.
+ # Because Set-Cookie header can appear more the once in the response body,
+ # we store it in a line break separated string that will be translated to
+ # multiple Set-Cookie header by the handler.
+ if cookie = headers.delete('cookie')
+ cookies = []
+
+ case cookie
+ when Array then cookie.each { |c| cookies << c.to_s }
+ when Hash then cookie.each { |_, c| cookies << c.to_s }
+ else cookies << cookie.to_s
end
- options.each { |k,v| headers[k] = v }
- end
+ @cgi.output_cookies.each { |c| cookies << c.to_s } if @cgi.output_cookies
- ""
+ headers['Set-Cookie'] = [headers['Set-Cookie'], cookies].flatten.compact
+ end
end
end
diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb
index 185518761d..8e6cfb41dc 100644..100755
--- a/actionpack/lib/action_controller/request.rb
+++ b/actionpack/lib/action_controller/request.rb
@@ -102,7 +102,7 @@ module ActionController
def if_modified_since
if since = env['HTTP_IF_MODIFIED_SINCE']
- Time.rfc2822(since)
+ Time.rfc2822(since) rescue nil
end
end
memoize :if_modified_since
@@ -199,10 +199,12 @@ module ActionController
# 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']
- end
+ 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'
diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb
index 4ea1d3121c..b12d50c773 100644
--- a/actionpack/lib/action_controller/rescue.rb
+++ b/actionpack/lib/action_controller/rescue.rb
@@ -182,7 +182,7 @@ module ActionController #:nodoc:
@template.instance_variable_set("@rescues_path", File.dirname(rescues_path("stub")))
@template.send!(:assign_variables_from_controller)
- @template.instance_variable_set("@contents", @template.render(:file => template_path_for_local_rescue(exception), :use_full_path => false))
+ @template.instance_variable_set("@contents", @template.render(:file => template_path_for_local_rescue(exception)))
response.content_type = Mime::HTML
render_for_file(rescues_path("layout"), response_code_for_rescue(exception))
diff --git a/actionpack/lib/action_controller/response.rb b/actionpack/lib/action_controller/response.rb
index a85fad0d39..5dac4128bb 100644
--- a/actionpack/lib/action_controller/response.rb
+++ b/actionpack/lib/action_controller/response.rb
@@ -40,6 +40,8 @@ module ActionController # :nodoc:
attr_accessor :session, :cookies, :assigns, :template, :layout
attr_accessor :redirected_to, :redirected_to_method_params
+ delegate :default_charset, :to => 'ActionController::Base'
+
def initialize
@body, @headers, @session, @assigns = "", DEFAULT_HEADERS.merge("cookie" => []), [], []
end
@@ -60,26 +62,44 @@ module ActionController # :nodoc:
# the character set information will also be included in the content type
# information.
def content_type=(mime_type)
- self.headers["Content-Type"] = charset ? "#{mime_type}; charset=#{charset}" : mime_type
+ self.headers["Content-Type"] =
+ if mime_type =~ /charset/ || (c = charset).nil?
+ mime_type.to_s
+ else
+ "#{mime_type}; charset=#{c}"
+ end
end
-
+
# Returns the response's content MIME type, or nil if content type has been set.
def content_type
content_type = String(headers["Content-Type"] || headers["type"]).split(";")[0]
content_type.blank? ? nil : content_type
end
-
- def charset=(encoding)
- self.headers["Content-Type"] = "#{content_type || Mime::HTML}; charset=#{encoding}"
+
+ # Set the charset of the Content-Type header. Set to nil to remove it.
+ # If no content type is set, it defaults to HTML.
+ def charset=(charset)
+ headers["Content-Type"] =
+ if charset
+ "#{content_type || Mime::HTML}; charset=#{charset}"
+ else
+ content_type || Mime::HTML.to_s
+ end
end
-
+
def charset
charset = String(headers["Content-Type"] || headers["type"]).split(";")[1]
charset.blank? ? nil : charset.strip.split("=")[1]
end
def last_modified
- Time.rfc2822(headers['Last-Modified'])
+ if last = headers['Last-Modified']
+ Time.httpdate(last)
+ end
+ end
+
+ def last_modified?
+ headers.include?('Last-Modified')
end
def last_modified=(utc_time)
@@ -87,6 +107,7 @@ module ActionController # :nodoc:
end
def etag; headers['ETag'] end
+ def etag?; headers.include?('ETag') end
def etag=(etag)
headers['ETag'] = %("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(etag))}")
end
@@ -97,23 +118,33 @@ module ActionController # :nodoc:
self.body = "<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"
end
+ def sending_file?
+ headers["Content-Transfer-Encoding"] == "binary"
+ end
+
+ def assign_default_content_type_and_charset!
+ self.content_type ||= Mime::HTML
+ self.charset ||= default_charset unless sending_file?
+ end
+
def prepare!
+ assign_default_content_type_and_charset!
+ set_content_length!
handle_conditional_get!
convert_content_type!
- set_content_length!
end
private
def handle_conditional_get!
if nonempty_ok_response?
- set_conditional_cache_control!
-
self.etag ||= body
if request && request.etag_matches?(etag)
self.status = '304 Not Modified'
self.body = ''
end
end
+
+ set_conditional_cache_control! if etag? || last_modified?
end
def nonempty_ok_response?
@@ -142,7 +173,9 @@ module ActionController # :nodoc:
# Don't set the Content-Length for block-based bodies as that would mean reading it all into memory. Not nice
# for, say, a 2GB streaming file.
def set_content_length!
- self.headers["Content-Length"] = body.size unless body.respond_to?(:call)
+ unless body.respond_to?(:call) || (status && status[0..2] == '304')
+ self.headers["Content-Length"] ||= body.size
+ end
end
end
end
diff --git a/actionpack/lib/action_controller/templates/rescues/diagnostics.erb b/actionpack/lib/action_controller/templates/rescues/diagnostics.erb
index 385c6c1b09..b5483eccae 100644
--- a/actionpack/lib/action_controller/templates/rescues/diagnostics.erb
+++ b/actionpack/lib/action_controller/templates/rescues/diagnostics.erb
@@ -6,6 +6,6 @@
</h1>
<pre><%=h @exception.clean_message %></pre>
-<%= render(:file => @rescues_path + "/_trace.erb", :use_full_path => false) %>
+<%= render(:file => @rescues_path + "/_trace.erb") %>
-<%= render(:file => @rescues_path + "/_request_and_response.erb", :use_full_path => false) %>
+<%= render(:file => @rescues_path + "/_request_and_response.erb") %>
diff --git a/actionpack/lib/action_controller/templates/rescues/template_error.erb b/actionpack/lib/action_controller/templates/rescues/template_error.erb
index 4aecc68d18..76fa3df89d 100644
--- a/actionpack/lib/action_controller/templates/rescues/template_error.erb
+++ b/actionpack/lib/action_controller/templates/rescues/template_error.erb
@@ -15,7 +15,7 @@
<% @real_exception = @exception
@exception = @exception.original_exception || @exception %>
-<%= render(:file => @rescues_path + "/_trace.erb", :use_full_path => false) %>
+<%= render(:file => @rescues_path + "/_trace.erb") %>
<% @exception = @real_exception %>
-<%= render(:file => @rescues_path + "/_request_and_response.erb", :use_full_path => false) %>
+<%= render(:file => @rescues_path + "/_request_and_response.erb") %>
diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb
index 0c705207e3..a11fa7cd10 100644
--- a/actionpack/lib/action_controller/test_process.rb
+++ b/actionpack/lib/action_controller/test_process.rb
@@ -138,7 +138,7 @@ module ActionController #:nodoc:
@host = "test.host"
@request_uri = "/"
@user_agent = "Rails Testing"
- self.remote_addr = "0.0.0.0"
+ self.remote_addr = "0.0.0.0"
@env["SERVER_PORT"] = 80
@env['REQUEST_METHOD'] = "GET"
end
@@ -160,16 +160,16 @@ module ActionController #:nodoc:
module TestResponseBehavior #:nodoc:
# The response code of the request
def response_code
- headers['Status'][0,3].to_i rescue 0
+ status[0,3].to_i rescue 0
end
-
+
# Returns a String to ensure compatibility with Net::HTTPResponse
def code
- headers['Status'].to_s.split(' ')[0]
+ status.to_s.split(' ')[0]
end
def message
- headers['Status'].to_s.split(' ',2)[1]
+ status.to_s.split(' ',2)[1]
end
# Was the response successful?
@@ -246,11 +246,11 @@ module ActionController #:nodoc:
# Does the specified template object exist?
def has_template_object?(name=nil)
- !template_objects[name].nil?
+ !template_objects[name].nil?
end
# Returns the response cookies, converted to a Hash of (name => CGI::Cookie) pairs
- #
+ #
# assert_equal ['AuthorOfNewPage'], r.cookies['author'].value
def cookies
headers['cookie'].inject({}) { |hash, cookie| hash[cookie.name] = cookie; hash }
@@ -322,7 +322,7 @@ module ActionController #:nodoc:
#
# Usage example, within a functional test:
# post :change_avatar, :avatar => ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + '/files/spongebob.png', 'image/png')
- #
+ #
# Pass a true third parameter to ensure the uploaded file is opened in binary mode (only required for Windows):
# post :change_avatar, :avatar => ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + '/files/spongebob.png', 'image/png', :binary)
require 'tempfile'
@@ -331,7 +331,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)
@@ -403,13 +403,13 @@ module ActionController #:nodoc:
end
alias xhr :xml_http_request
- def assigns(key = nil)
- if key.nil?
- @response.template.assigns
- else
- @response.template.assigns[key.to_s]
- end
- end
+ def assigns(key = nil)
+ if key.nil?
+ @response.template.assigns
+ else
+ @response.template.assigns[key.to_s]
+ end
+ end
def session
@response.session
@@ -468,7 +468,7 @@ module ActionController #:nodoc:
# post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png', :binary)
def fixture_file_upload(path, mime_type = nil, binary = false)
ActionController::TestUploadedFile.new(
- Test::Unit::TestCase.respond_to?(:fixture_path) ? Test::Unit::TestCase.fixture_path + path : path,
+ Test::Unit::TestCase.respond_to?(:fixture_path) ? Test::Unit::TestCase.fixture_path + path : path,
mime_type,
binary
)
@@ -476,7 +476,7 @@ module ActionController #:nodoc:
# A helper to make it easier to test different route configurations.
# This method temporarily replaces ActionController::Routing::Routes
- # with a new RouteSet instance.
+ # with a new RouteSet instance.
#
# The new instance is yielded to the passed block. Typically the block
# will create some routes using <tt>map.draw { map.connect ... }</tt>:
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index dd555b3792..0ed69f29bf 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -21,6 +21,15 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
+begin
+ require 'active_support'
+rescue LoadError
+ activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
+ if File.directory?(activesupport_path)
+ $:.unshift activesupport_path
+ require 'active_support'
+ end
+end
require 'action_view/template_handlers'
require 'action_view/renderable'
@@ -34,14 +43,11 @@ require 'action_view/base'
require 'action_view/partials'
require 'action_view/template_error'
-I18n.backend.populate do
- require 'action_view/locale/en-US.rb'
-end
+I18n.load_translations "#{File.dirname(__FILE__)}/action_view/locale/en-US.yml"
+
+require 'action_view/helpers'
ActionView::Base.class_eval do
include ActionView::Partials
-
- ActionView::Base.helper_modules.each do |helper_module|
- include helper_module
- end
+ include ActionView::Helpers
end
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index ad59d92086..c65048bfa0 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -158,6 +158,7 @@ module ActionView #:nodoc:
# See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details.
class Base
include ERB::Util
+ extend ActiveSupport::Memoizable
attr_accessor :base_path, :assigns, :template_extension
attr_accessor :controller
@@ -169,6 +170,7 @@ module ActionView #:nodoc:
class << self
delegate :erb_trim_mode=, :to => 'ActionView::TemplateHandlers::ERB'
+ delegate :logger, :to => 'ActionController::Base'
end
def self.cache_template_loading=(*args)
@@ -202,27 +204,28 @@ module ActionView #:nodoc:
end
include CompiledTemplates
- def self.helper_modules #:nodoc:
- helpers = []
- Dir.entries(File.expand_path("#{File.dirname(__FILE__)}/helpers")).sort.each do |file|
- next unless file =~ /^([a-z][a-z_]*_helper).rb$/
- require "action_view/helpers/#{$1}"
- helper_module_name = $1.camelize
- if Helpers.const_defined?(helper_module_name)
- helpers << Helpers.const_get(helper_module_name)
- end
- end
- return helpers
- end
-
def self.process_view_paths(value)
ActionView::PathSet.new(Array(value))
end
+ attr_reader :helpers
+
+ class ProxyModule < Module
+ def initialize(receiver)
+ @receiver = receiver
+ end
+
+ def include(*args)
+ super(*args)
+ @receiver.extend(*args)
+ end
+ end
+
def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc:
@assigns = assigns_for_first_render
@assigns_added = nil
@controller = controller
+ @helpers = ProxyModule.new(self)
self.view_paths = view_paths
end
@@ -238,7 +241,7 @@ module ActionView #:nodoc:
local_assigns ||= {}
if options.is_a?(String)
- render_file(options, nil, local_assigns)
+ render(:file => options, :locals => local_assigns)
elsif options == :update
update_page(&block)
elsif options.is_a?(Hash)
@@ -246,31 +249,34 @@ module ActionView #:nodoc:
if partial_layout = options.delete(:layout)
if block_given?
- wrap_content_for_layout capture(&block) do
+ begin
+ @_proc_for_layout = block
concat(render(options.merge(:partial => partial_layout)))
+ ensure
+ @_proc_for_layout = nil
end
else
- wrap_content_for_layout render(options) do
+ begin
+ original_content_for_layout, @content_for_layout = @content_for_layout, render(options)
render(options.merge(:partial => partial_layout))
+ ensure
+ @content_for_layout = original_content_for_layout
end
end
elsif options[:file]
- render_file(options[:file], nil, options[:locals])
- elsif options[:partial] && options[:collection]
- render_partial_collection(options[:partial], options[:collection], options[:spacer_template], options[:locals], options[:as])
+ if options[:use_full_path]
+ ActiveSupport::Deprecation.warn("use_full_path option has been deprecated and has no affect.", caller)
+ end
+
+ pick_template(options[:file]).render_template(self, options[:locals])
elsif options[:partial]
- render_partial(options[:partial], options[:object], options[:locals])
+ render_partial(options)
elsif options[:inline]
- render_inline(options[:inline], options[:locals], options[:type])
+ InlineTemplate.new(options[:inline], options[:type]).render(self, options[:locals])
end
end
end
- # Returns true is the file may be rendered implicitly.
- def file_public?(template_path)#:nodoc:
- template_path.split('/').last[0,1] != '_'
- end
-
# The format to be used when choosing between multiple templates with
# the same name but differing formats. See +Request#template_format+
# for more details.
@@ -322,7 +328,7 @@ module ActionView #:nodoc:
else
template = Template.new(template_path, view_paths)
- if self.class.warn_cache_misses && logger = ActionController::Base.logger
+ if self.class.warn_cache_misses && logger
logger.debug "[PERFORMANCE] Rendering a template that was " +
"not found in view path. Templates outside the view path are " +
"not cached and result in expensive disk operations. Move this " +
@@ -333,47 +339,9 @@ module ActionView #:nodoc:
template
end
end
-
- extend ActiveSupport::Memoizable
memoize :pick_template
private
- # Renders the template present at <tt>template_path</tt>. The hash in <tt>local_assigns</tt>
- # is made available as local variables.
- def render_file(template_path, use_full_path = nil, local_assigns = {}) #:nodoc:
- unless use_full_path == nil
- ActiveSupport::Deprecation.warn("use_full_path option has been deprecated and has no affect.", caller)
- end
-
- if defined?(ActionMailer) && defined?(ActionMailer::Base) && controller.is_a?(ActionMailer::Base) &&
- template_path.is_a?(String) && !template_path.include?("/")
- raise ActionViewError, <<-END_ERROR
- Due to changes in ActionMailer, you need to provide the mailer_name along with the template name.
-
- render "user_mailer/signup"
- render :file => "user_mailer/signup"
-
- If you are rendering a subtemplate, you must now use controller-like partial syntax:
-
- render :partial => 'signup' # no mailer_name necessary
- END_ERROR
- end
-
- template = pick_template(template_path)
- template.render_template(self, local_assigns)
- end
-
- def render_inline(text, local_assigns = {}, type = nil)
- InlineTemplate.new(text, type).render(self, local_assigns)
- end
-
- def wrap_content_for_layout(content)
- original_content_for_layout, @content_for_layout = @content_for_layout, content
- yield
- ensure
- @content_for_layout = original_content_for_layout
- end
-
# Evaluate the local assigns and pushes them to the view.
def evaluate_assigns
unless @assigns_added
@@ -392,11 +360,5 @@ module ActionView #:nodoc:
controller.response.content_type ||= content_type
end
end
-
- def execute(method, local_assigns = {})
- send(method, local_assigns) do |*names|
- instance_variable_get "@content_for_#{names.first || 'layout'}"
- end
- end
end
end
diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb
new file mode 100644
index 0000000000..05e1cf990a
--- /dev/null
+++ b/actionpack/lib/action_view/helpers.rb
@@ -0,0 +1,39 @@
+Dir.entries(File.expand_path("#{File.dirname(__FILE__)}/helpers")).sort.each do |file|
+ next unless file =~ /^([a-z][a-z_]*_helper).rb$/
+ require "action_view/helpers/#{$1}"
+end
+
+module ActionView #:nodoc:
+ module Helpers #:nodoc:
+ def self.included(base)
+ base.extend(ClassMethods)
+ end
+
+ module ClassMethods
+ include SanitizeHelper::ClassMethods
+ end
+
+ include ActiveRecordHelper
+ include AssetTagHelper
+ include AtomFeedHelper
+ include BenchmarkHelper
+ include CacheHelper
+ include CaptureHelper
+ include DateHelper
+ include DebugHelper
+ include FormCountryHelper
+ include FormHelper
+ include FormOptionsHelper
+ include FormTagHelper
+ include NumberHelper
+ include PrototypeHelper
+ include RecordIdentificationHelper
+ include RecordTagHelper
+ include SanitizeHelper
+ include ScriptaculousHelper
+ include TagHelper
+ include TextHelper
+ include TranslationHelper
+ include UrlHelper
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/active_record_helper.rb b/actionpack/lib/action_view/helpers/active_record_helper.rb
index fce03ff605..c339e10701 100644
--- a/actionpack/lib/action_view/helpers/active_record_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_record_helper.rb
@@ -189,15 +189,15 @@ module ActionView
end
options[:object_name] ||= params.first
- I18n.with_options :locale => options[:locale], :scope => [:active_record, :error] do |locale|
+ I18n.with_options :locale => options[:locale], :scope => [:activerecord, :errors, :template] do |locale|
header_message = if options.include?(:header_message)
options[:header_message]
else
object_name = options[:object_name].to_s.gsub('_', ' ')
- object_name = I18n.t(object_name, :default => object_name)
- locale.t :header_message, :count => count, :object_name => object_name
+ object_name = I18n.t(object_name, :default => object_name, :scope => [:activerecord, :models], :count => 1)
+ locale.t :header, :count => count, :model => object_name
end
- message = options.include?(:message) ? options[:message] : locale.t(:message)
+ message = options.include?(:message) ? options[:message] : locale.t(:body)
error_messages = objects.sum {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } }.join
contents = ''
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index c2b4f51c9c..623ed1e8df 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -612,7 +612,7 @@ module ActionView
end
def join_asset_file_contents(paths)
- paths.collect { |path| File.read(File.join(ASSETS_DIR, path.split("?").first)) }.join("\n\n")
+ paths.collect { |path| File.read(asset_file_path(path)) }.join("\n\n")
end
def write_asset_file_contents(joined_asset_path, asset_paths)
@@ -621,10 +621,14 @@ module ActionView
# Set mtime to the latest of the combined files to allow for
# consistent ETag without a shared filesystem.
- mt = asset_paths.map { |p| File.mtime(File.join(ASSETS_DIR, p)) }.max
+ mt = asset_paths.map { |p| File.mtime(asset_file_path(p)) }.max
File.utime(mt, mt, joined_asset_path)
end
+ def asset_file_path(path)
+ File.join(ASSETS_DIR, path.split('?').first)
+ end
+
def collect_asset_files(*path)
dir = path.first
diff --git a/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
index ebb1cb34bc..e65d5d1f60 100644
--- a/actionpack/lib/action_view/helpers/atom_feed_helper.rb
+++ b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
@@ -17,7 +17,7 @@ module ActionView
# # GET /posts.atom
# def index
# @posts = Post.find(:all)
- #
+ #
# respond_to do |format|
# format.html
# format.atom
@@ -29,12 +29,12 @@ module ActionView
# atom_feed do |feed|
# feed.title("My great blog!")
# feed.updated((@posts.first.created_at))
- #
+ #
# for post in @posts
# feed.entry(post) do |entry|
# entry.title(post.title)
# entry.content(post.body, :type => 'html')
- #
+ #
# entry.author do |author|
# author.name("DHH")
# end
@@ -47,8 +47,9 @@ module ActionView
# * <tt>:language</tt>: Defaults to "en-US".
# * <tt>:root_url</tt>: The HTML alternative that this feed is doubling for. Defaults to / on the current host.
# * <tt>:url</tt>: The URL for this feed. Defaults to the current URL.
- # * <tt>:schema_date</tt>: The date at which the tag scheme for the feed was first used. A good default is the year you
- # created the feed. See http://feedvalidator.org/docs/error/InvalidTAG.html for more information. If not specified,
+ # * <tt>:id</tt>: The id for this feed. Defaults to "tag:#{request.host},#{options[:schema_date]}:#{request.request_uri.split(".")[0]}"
+ # * <tt>:schema_date</tt>: The date at which the tag scheme for the feed was first used. A good default is the year you
+ # created the feed. See http://feedvalidator.org/docs/error/InvalidTAG.html for more information. If not specified,
# 2005 is used (as an "I don't care" value).
#
# Other namespaces can be added to the root element:
@@ -81,7 +82,7 @@ module ActionView
else
options[:schema_date] = "2005" # The Atom spec copyright date
end
-
+
xml = options[:xml] || eval("xml", block.binding)
xml.instruct!
@@ -89,10 +90,10 @@ module ActionView
feed_opts.merge!(options).reject!{|k,v| !k.to_s.match(/^xml/)}
xml.feed(feed_opts) do
- xml.id("tag:#{request.host},#{options[:schema_date]}:#{request.request_uri.split(".")[0]}")
+ xml.id(options[:id] || "tag:#{request.host},#{options[:schema_date]}:#{request.request_uri.split(".")[0]}")
xml.link(:rel => 'alternate', :type => 'text/html', :href => options[:root_url] || (request.protocol + request.host_with_port))
xml.link(:rel => 'self', :type => 'application/atom+xml', :href => options[:url] || request.url)
-
+
yield AtomFeedBuilder.new(xml, self, options)
end
end
@@ -102,7 +103,7 @@ module ActionView
def initialize(xml, view, feed_options = {})
@xml, @view, @feed_options = xml, view, feed_options
end
-
+
# Accepts a Date or Time object and inserts it in the proper format. If nil is passed, current time in UTC is used.
def updated(date_or_time = nil)
@xml.updated((date_or_time || Time.now.utc).xmlschema)
@@ -115,9 +116,10 @@ module ActionView
# * <tt>:published</tt>: Time first published. Defaults to the created_at attribute on the record if one such exists.
# * <tt>:updated</tt>: Time of update. Defaults to the updated_at attribute on the record if one such exists.
# * <tt>:url</tt>: The URL for this entry. Defaults to the polymorphic_url for the record.
+ # * <tt>:id</tt>: The ID for this entry. Defaults to "tag:#{@view.request.host},#{@feed_options[:schema_date]}:#{record.class}/#{record.id}"
def entry(record, options = {})
- @xml.entry do
- @xml.id("tag:#{@view.request.host},#{@feed_options[:schema_date]}:#{record.class}/#{record.id}")
+ @xml.entry do
+ @xml.id(options[:id] || "tag:#{@view.request.host},#{@feed_options[:schema_date]}:#{record.class}/#{record.id}")
if options[:published] || (record.respond_to?(:created_at) && record.created_at)
@xml.published((options[:published] || record.created_at).xmlschema)
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 9cb2ed9bca..e452b04b31 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -588,9 +588,7 @@ module ActionView
private
def include_helpers_from_context
- @context.extended_by.each do |mod|
- extend mod unless mod.name =~ /^ActionView::Helpers/
- end
+ extend @context.helpers if @context.respond_to?(:helpers)
extend GeneratorMethods
end
diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb
index c3c03394ee..435ba936e1 100644
--- a/actionpack/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb
@@ -1,22 +1,27 @@
require 'action_view/helpers/tag_helper'
-require 'html/document'
+
+begin
+ require 'html/document'
+rescue LoadError
+ html_scanner_path = "#{File.dirname(__FILE__)}/../../action_controller/vendor/html-scanner"
+ if File.directory?(html_scanner_path)
+ $:.unshift html_scanner_path
+ require 'html/document'
+ end
+end
module ActionView
module Helpers #:nodoc:
# The SanitizeHelper module provides a set of methods for scrubbing text of undesired HTML elements.
# These helper methods extend ActionView making them callable within your template files.
module SanitizeHelper
- def self.included(base)
- base.extend(ClassMethods)
- end
-
# This +sanitize+ helper will html encode all tags and strip all attributes that aren't specifically allowed.
# It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any
# tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters. Check out
# the extensive test suite.
#
# <%= sanitize @article.body %>
- #
+ #
# You can add or remove tags/attributes if you want to customize it a bit. See ActionView::Base for full docs on the
# available options. You can add tags/attributes for single uses of +sanitize+ by passing either the <tt>:attributes</tt> or <tt>:tags</tt> options:
#
@@ -27,27 +32,27 @@ module ActionView
# Custom Use (only the mentioned tags and attributes are allowed, nothing else)
#
# <%= sanitize @article.body, :tags => %w(table tr td), :attributes => %w(id class style)
- #
+ #
# Add table tags to the default allowed tags
- #
+ #
# Rails::Initializer.run do |config|
# config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
# end
- #
+ #
# Remove tags to the default allowed tags
- #
+ #
# Rails::Initializer.run do |config|
# config.after_initialize do
# ActionView::Base.sanitized_allowed_tags.delete 'div'
# end
# end
- #
+ #
# Change allowed default attributes
- #
+ #
# Rails::Initializer.run do |config|
# config.action_view.sanitized_allowed_attributes = 'id', 'class', 'style'
# end
- #
+ #
# Please note that sanitizing user-provided text does not guarantee that the
# resulting markup is valid (conforming to a document type) or even well-formed.
# The output may still contain e.g. unescaped '<', '>', '&' characters and
@@ -62,8 +67,8 @@ module ActionView
self.class.white_list_sanitizer.sanitize_css(style)
end
- # Strips all HTML tags from the +html+, including comments. This uses the
- # html-scanner tokenizer and so its HTML parsing ability is limited by
+ # Strips all HTML tags from the +html+, including comments. This uses the
+ # html-scanner tokenizer and so its HTML parsing ability is limited by
# that of html-scanner.
#
# ==== Examples
@@ -73,10 +78,10 @@ module ActionView
#
# strip_tags("<b>Bold</b> no more! <a href='more.html'>See more here</a>...")
# # => Bold no more! See more here...
- #
+ #
# strip_tags("<div id='top-bar'>Welcome to my website!</div>")
# # => Welcome to my website!
- def strip_tags(html)
+ def strip_tags(html)
self.class.full_sanitizer.sanitize(html)
end
@@ -96,21 +101,48 @@ module ActionView
end
module ClassMethods #:nodoc:
- def self.extended(base)
- class << base
- attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
-
- # we want these to be class methods on ActionView::Base, they'll get mattr_readers for these below.
- helper_def = [:sanitized_protocol_separator, :sanitized_uri_attributes, :sanitized_bad_tags, :sanitized_allowed_tags,
- :sanitized_allowed_attributes, :sanitized_allowed_css_properties, :sanitized_allowed_css_keywords,
- :sanitized_shorthand_css_properties, :sanitized_allowed_protocols, :sanitized_protocol_separator=].collect! do |prop|
- prop = prop.to_s
- "def #{prop}(#{:value if prop =~ /=$/}) white_list_sanitizer.#{prop.sub /sanitized_/, ''} #{:value if prop =~ /=$/} end"
- end.join("\n")
- eval helper_def
- end
- end
-
+ attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
+
+ def sanitized_protocol_separator
+ white_list_sanitizer.protocol_separator
+ end
+
+ def sanitized_uri_attributes
+ white_list_sanitizer.uri_attributes
+ end
+
+ def sanitized_bad_tags
+ white_list_sanitizer.bad_tags
+ end
+
+ def sanitized_allowed_tags
+ white_list_sanitizer.allowed_tags
+ end
+
+ def sanitized_allowed_attributes
+ white_list_sanitizer.allowed_attributes
+ end
+
+ def sanitized_allowed_css_properties
+ white_list_sanitizer.allowed_css_properties
+ end
+
+ def sanitized_allowed_css_keywords
+ white_list_sanitizer.allowed_css_keywords
+ end
+
+ def sanitized_shorthand_css_properties
+ white_list_sanitizer.shorthand_css_properties
+ end
+
+ def sanitized_allowed_protocols
+ white_list_sanitizer.allowed_protocols
+ end
+
+ def sanitized_protocol_separator=(value)
+ white_list_sanitizer.protocol_separator = value
+ end
+
# Gets the HTML::FullSanitizer instance used by +strip_tags+. Replace with
# any object that responds to +sanitize+.
#
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index f9096d0029..a5d43b90f4 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -1,5 +1,14 @@
require 'action_view/helpers/tag_helper'
-require 'html/document'
+
+begin
+ require 'html/document'
+rescue LoadError
+ html_scanner_path = "#{File.dirname(__FILE__)}/../../action_controller/vendor/html-scanner"
+ if File.directory?(html_scanner_path)
+ $:.unshift html_scanner_path
+ require 'html/document'
+ end
+end
module ActionView
module Helpers #:nodoc:
@@ -439,8 +448,10 @@ module ActionView
# array every time it is called. This can be used for example, to alternate
# classes for table rows. You can use named cycles to allow nesting in loops.
# Passing a Hash as the last parameter with a <tt>:name</tt> key will create a
- # named cycle. You can manually reset a cycle by calling reset_cycle and passing the
- # name of the cycle.
+ # named cycle. The default name for a cycle without a +:name+ key is
+ # <tt>"default"</tt>. You can manually reset a cycle by calling reset_cycle
+ # and passing the name of the cycle. The current cycle string can be obtained
+ # anytime using the current_cycle method.
#
# ==== Examples
# # Alternate CSS classes for even and odd numbers...
@@ -487,6 +498,23 @@ module ActionView
return cycle.to_s
end
+ # Returns the current cycle string after a cycle has been started. Useful
+ # for complex table highlighing or any other design need which requires
+ # the current cycle string in more than one place.
+ #
+ # ==== Example
+ # # Alternate background colors
+ # @items = [1,2,3,4]
+ # <% @items.each do |item| %>
+ # <div style="background-color:<%= cycle("red","white","blue") %>">
+ # <span style="background-color:<%= current_cycle %><%= item %></span>
+ # </div>
+ # <% end %>
+ def current_cycle(name = "default")
+ cycle = get_cycle(name)
+ cycle.current_value unless cycle.nil?
+ end
+
# Resets a cycle so that it starts from the first element the next time
# it is called. Pass in +name+ to reset a named cycle.
#
@@ -523,11 +551,29 @@ module ActionView
@index = 0
end
+ def current_value
+ @values[previous_index].to_s
+ end
+
def to_s
value = @values[@index].to_s
- @index = (@index + 1) % @values.size
+ @index = next_index
return value
end
+
+ private
+
+ def next_index
+ step_index(1)
+ end
+
+ def previous_index
+ step_index(-1)
+ end
+
+ def step_index(n)
+ (@index + n) % @values.size
+ end
end
private
diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb
index 60ac5c8790..de4c1d7689 100644
--- a/actionpack/lib/action_view/helpers/translation_helper.rb
+++ b/actionpack/lib/action_view/helpers/translation_helper.rb
@@ -11,10 +11,12 @@ module ActionView
keys = I18n.send :normalize_translation_keys, e.locale, e.key, e.options[:scope]
content_tag('span', keys.join(', '), :class => 'translation_missing')
end
+ alias :t :translate
def localize(*args)
I18n.localize *args
end
+ alias :l :localize
end
end
end \ No newline at end of file
diff --git a/actionpack/lib/action_view/locale/en-US.rb b/actionpack/lib/action_view/locale/en-US.rb
deleted file mode 100644
index 2c3676dca8..0000000000
--- a/actionpack/lib/action_view/locale/en-US.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-I18n.backend.store_translations :'en-US', {
- :datetime => {
- :distance_in_words => {
- :half_a_minute => 'half a minute',
- :less_than_x_seconds => ['less than 1 second', 'less than {{count}} seconds'],
- :x_seconds => ['1 second', '{{count}} seconds'],
- :less_than_x_minutes => ['less than a minute', 'less than {{count}} minutes'],
- :x_minutes => ['1 minute', '{{count}} minutes'],
- :about_x_hours => ['about 1 hour', 'about {{count}} hours'],
- :x_days => ['1 day', '{{count}} days'],
- :about_x_months => ['about 1 month', 'about {{count}} months'],
- :x_months => ['1 month', '{{count}} months'],
- :about_x_years => ['about 1 year', 'about {{count}} year'],
- :over_x_years => ['over 1 year', 'over {{count}} years']
- }
- },
- :number => {
- :format => {
- :precision => 3,
- :separator => '.',
- :delimiter => ','
- },
- :currency => {
- :format => {
- :unit => '$',
- :precision => 2,
- :format => '%u%n'
- }
- },
- :human => {
- :format => {
- :precision => 1,
- :delimiter => ''
- }
- },
- :percentage => {
- :format => {
- :delimiter => ''
- }
- },
- :precision => {
- :format => {
- :delimiter => ''
- }
- }
- },
- :active_record => {
- :error => {
- :header_message => ["1 error prohibited this {{object_name}} from being saved", "{{count}} errors prohibited this {{object_name}} from being saved"],
- :message => "There were problems with the following fields:"
- }
- }
-}
diff --git a/actionpack/lib/action_view/locale/en-US.yml b/actionpack/lib/action_view/locale/en-US.yml
new file mode 100644
index 0000000000..818f2f93bd
--- /dev/null
+++ b/actionpack/lib/action_view/locale/en-US.yml
@@ -0,0 +1,91 @@
+"en-US":
+ number:
+ # Used in number_with_delimiter()
+ # These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
+ format:
+ # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
+ separator: "."
+ # Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
+ delimiter: ","
+ # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
+ precision: 3
+
+ # Used in number_to_currency()
+ currency:
+ format:
+ # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
+ format: "%u%n"
+ unit: "$"
+ # These three are to override number.format and are optional
+ separator: "."
+ delimiter: ","
+ precision: 2
+
+ # Used in number_to_percentage()
+ percentage:
+ format:
+ # These three are to override number.format and are optional
+ # separator:
+ delimiter: ""
+ # precision:
+
+ # Used in number_to_precision()
+ precision:
+ format:
+ # These three are to override number.format and are optional
+ # separator:
+ delimiter: ""
+ # precision:
+
+ # Used in number_to_human_size()
+ human:
+ format:
+ # These three are to override number.format and are optional
+ # separator:
+ delimiter: ""
+ precision: 1
+
+ # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
+ datetime:
+ distance_in_words:
+ half_a_minute: "half a minute"
+ less_than_x_seconds:
+ one: "less than 1 second"
+ other: "less than {{count}} seconds"
+ x_seconds:
+ one: "1 second"
+ other: "{{count}} seconds"
+ less_than_x_minutes:
+ one: "less than a minute"
+ other: "less than {{count}} minutes"
+ x_minutes:
+ one: "1 minute"
+ other: "{{count}} minutes"
+ about_x_hours:
+ one: "about 1 hour"
+ other: "about {{count}} hours"
+ x_days:
+ one: "1 day"
+ other: "{{count}} days"
+ about_x_months:
+ one: "about 1 month"
+ other: "about {{count}} months"
+ x_months:
+ one: "1 month"
+ other: "{{count}} months"
+ about_x_years:
+ one: "about 1 year"
+ other: "about {{count}} years"
+ over_x_years:
+ one: "over 1 year"
+ other: "over {{count}} years"
+
+ activerecord:
+ errors:
+ template:
+ header:
+ one: "1 error prohibited this {{model}} from being saved"
+ other: "{{count}} errors prohibited this {{model}} from being saved"
+ # The variable :count is also available
+ body: "There were problems with the following fields:"
+
diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/partials.rb
index 894b88534c..443c49b870 100644
--- a/actionpack/lib/action_view/partials.rb
+++ b/actionpack/lib/action_view/partials.rb
@@ -1,14 +1,15 @@
module ActionView
- # There's also a convenience method for rendering sub templates within the current controller that depends on a single object
- # (we call this kind of sub templates for partials). It relies on the fact that partials should follow the naming convention of being
- # prefixed with an underscore -- as to separate them from regular templates that could be rendered on their own.
+ # There's also a convenience method for rendering sub templates within the current controller that depends on a
+ # single object (we call this kind of sub templates for partials). It relies on the fact that partials should
+ # follow the naming convention of being prefixed with an underscore -- as to separate them from regular
+ # templates that could be rendered on their own.
#
# In a template for Advertiser#account:
#
# <%= render :partial => "account" %>
#
- # This would render "advertiser/_account.erb" and pass the instance variable @account in as a local variable +account+ to
- # the template for display.
+ # This would render "advertiser/_account.erb" and pass the instance variable @account in as a local variable
+ # +account+ to the template for display.
#
# In another template for Advertiser#buy, we could have:
#
@@ -18,24 +19,24 @@ module ActionView
# <%= render :partial => "ad", :locals => { :ad => ad } %>
# <% end %>
#
- # This would first render "advertiser/_account.erb" with @buyer passed in as the local variable +account+, then render
- # "advertiser/_ad.erb" and pass the local variable +ad+ to the template for display.
+ # This would first render "advertiser/_account.erb" with @buyer passed in as the local variable +account+, then
+ # render "advertiser/_ad.erb" and pass the local variable +ad+ to the template for display.
#
# == Rendering a collection of partials
#
- # The example of partial use describes a familiar pattern where a template needs to iterate over an array and render a sub
- # template for each of the elements. This pattern has been implemented as a single method that accepts an array and renders
- # a partial by the same name as the elements contained within. So the three-lined example in "Using partials" can be rewritten
- # with a single line:
+ # The example of partial use describes a familiar pattern where a template needs to iterate over an array and
+ # render a sub template for each of the elements. This pattern has been implemented as a single method that
+ # accepts an array and renders a partial by the same name as the elements contained within. So the three-lined
+ # example in "Using partials" can be rewritten with a single line:
#
# <%= render :partial => "ad", :collection => @advertisements %>
#
- # This will render "advertiser/_ad.erb" and pass the local variable +ad+ to the template for display. An iteration counter
- # will automatically be made available to the template with a name of the form +partial_name_counter+. In the case of the
- # example above, the template would be fed +ad_counter+.
+ # This will render "advertiser/_ad.erb" and pass the local variable +ad+ to the template for display. An
+ # iteration counter will automatically be made available to the template with a name of the form
+ # +partial_name_counter+. In the case of the example above, the template would be fed +ad_counter+.
#
- # 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.
+ # 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.
#
# == Rendering shared partials
#
@@ -47,8 +48,9 @@ module ActionView
#
# == Rendering partials with layouts
#
- # Partials can have their own layouts applied to them. These layouts are different than the ones that are specified globally
- # for the entire action, but they work in a similar fashion. Imagine a list with two types of users:
+ # Partials can have their own layouts applied to them. These layouts are different than the ones that are
+ # specified globally for the entire action, but they work in a similar fashion. Imagine a list with two types
+ # of users:
#
# <%# app/views/users/index.html.erb &>
# Here's the administrator:
@@ -68,7 +70,7 @@ module ActionView
#
# <%# app/views/users/_editor.html.erb &>
# <div id="editor">
- # Deadline: $<%= user.deadline %>
+ # Deadline: <%= user.deadline %>
# <%= yield %>
# </div>
#
@@ -82,7 +84,7 @@ module ActionView
#
# Here's the editor:
# <div id="editor">
- # Deadline: $<%= user.deadline %>
+ # Deadline: <%= user.deadline %>
# Name: <%= user.name %>
# </div>
#
@@ -101,42 +103,83 @@ module ActionView
# </div>
#
# As you can see, the <tt>:locals</tt> hash is shared between both the partial and its layout.
+ #
+ # If you pass arguments to "yield" then this will be passed to the block. One way to use this is to pass
+ # an array to layout and treat it as an enumerable.
+ #
+ # <%# app/views/users/_user.html.erb &>
+ # <div class="user">
+ # Budget: $<%= user.budget %>
+ # <%= yield user %>
+ # </div>
+ #
+ # <%# app/views/users/index.html.erb &>
+ # <% render :layout => @users do |user| %>
+ # Title: <%= user.title %>
+ # <% end %>
+ #
+ # This will render the layout for each user and yield to the block, passing the user, each time.
+ #
+ # You can also yield multiple times in one layout and use block arguments to differentiate the sections.
+ #
+ # <%# app/views/users/_user.html.erb &>
+ # <div class="user">
+ # <%= yield user, :header %>
+ # Budget: $<%= user.budget %>
+ # <%= yield user, :footer %>
+ # </div>
+ #
+ # <%# app/views/users/index.html.erb &>
+ # <% render :layout => @users do |user, section| %>
+ # <%- case section when :header -%>
+ # Title: <%= user.title %>
+ # <%- when :footer -%>
+ # Deadline: <%= user.deadline %>
+ # <%- end -%>
+ # <% end %>
module Partials
extend ActiveSupport::Memoizable
private
- def render_partial(partial_path, object_assigns = nil, local_assigns = {}) #:nodoc:
- local_assigns ||= {}
+ def render_partial(options = {}) #:nodoc:
+ local_assigns = options[:locals] || {}
- case partial_path
+ case partial_path = options[:partial]
when String, Symbol, NilClass
- pick_template(find_partial_path(partial_path)).render_partial(self, object_assigns, local_assigns)
+ if options.has_key?(:collection)
+ render_partial_collection(options)
+ else
+ _pick_partial_template(partial_path).render_partial(self, options[:object], local_assigns)
+ end
when ActionView::Helpers::FormBuilder
builder_partial_path = partial_path.class.to_s.demodulize.underscore.sub(/_builder$/, '')
- render_partial(builder_partial_path, object_assigns, (local_assigns || {}).merge(builder_partial_path.to_sym => partial_path))
+ local_assigns.merge!(builder_partial_path.to_sym => partial_path)
+ render_partial(:partial => builder_partial_path, :object => options[:object], :locals => local_assigns)
when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope
- if partial_path.any?
- collection = partial_path
- render_partial_collection(nil, collection, nil, local_assigns)
- else
- ""
- end
+ render_partial_collection(options.except(:partial).merge(:collection => partial_path))
else
- render_partial(ActionController::RecordIdentifier.partial_path(partial_path, controller.class.controller_path), partial_path, local_assigns)
+ object = partial_path
+ render_partial(
+ :partial => ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path),
+ :object => object,
+ :locals => local_assigns
+ )
end
end
- def render_partial_collection(partial_path, collection, partial_spacer_template = nil, local_assigns = {}, as = nil) #:nodoc:
- return " " if collection.empty?
+ def render_partial_collection(options = {}) #:nodoc:
+ return nil if options[:collection].blank?
- local_assigns = local_assigns ? local_assigns.clone : {}
- spacer = partial_spacer_template ? render(:partial => partial_spacer_template) : ''
+ partial = options[:partial]
+ spacer = options[:spacer_template] ? render(:partial => options[:spacer_template]) : ''
+ local_assigns = options[:locals] ? options[:locals].clone : {}
+ as = options[:as]
index = 0
- collection.map do |object|
- _partial_path ||= partial_path || ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path)
- path = find_partial_path(_partial_path)
- template = pick_template(path)
+ options[:collection].map do |object|
+ _partial_path ||= partial ||
+ ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path)
+ template = _pick_partial_template(_partial_path)
local_assigns[template.counter_name] = index
result = template.render_partial(self, object, local_assigns, as)
index += 1
@@ -144,15 +187,17 @@ module ActionView
end.join(spacer)
end
- def find_partial_path(partial_path)
+ def _pick_partial_template(partial_path) #:nodoc:
if partial_path.include?('/')
- File.join(File.dirname(partial_path), "_#{File.basename(partial_path)}")
- elsif respond_to?(:controller)
- "#{controller.class.controller_path}/_#{partial_path}"
+ path = File.join(File.dirname(partial_path), "_#{File.basename(partial_path)}")
+ elsif controller
+ path = "#{controller.class.controller_path}/_#{partial_path}"
else
- "_#{partial_path}"
+ path = "_#{partial_path}"
end
+
+ pick_template(path)
end
- memoize :find_partial_path
+ memoize :_pick_partial_template
end
end
diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb
index d97f963540..d6bf2137af 100644
--- a/actionpack/lib/action_view/paths.rb
+++ b/actionpack/lib/action_view/paths.rb
@@ -1,9 +1,9 @@
module ActionView #:nodoc:
- class PathSet < ActiveSupport::TypedArray #:nodoc:
+ class PathSet < Array #:nodoc:
def self.type_cast(obj)
if obj.is_a?(String)
if Base.warn_cache_misses && defined?(Rails) && Rails.initialized?
- Rails.logger.debug "[PERFORMANCE] Processing view path during a " +
+ Base.logger.debug "[PERFORMANCE] Processing view path during a " +
"request. This an expense disk operation that should be done at " +
"boot. You can manually process this view path with " +
"ActionView::Base.process_view_paths(#{obj.inspect}) and set it " +
@@ -15,6 +15,30 @@ module ActionView #:nodoc:
end
end
+ def initialize(*args)
+ super(*args).map! { |obj| self.class.type_cast(obj) }
+ end
+
+ def <<(obj)
+ super(self.class.type_cast(obj))
+ end
+
+ def concat(array)
+ super(array.map! { |obj| self.class.type_cast(obj) })
+ end
+
+ def insert(index, obj)
+ super(index, self.class.type_cast(obj))
+ end
+
+ def push(*objs)
+ super(*objs.map { |obj| self.class.type_cast(obj) })
+ end
+
+ def unshift(*objs)
+ super(*objs.map { |obj| self.class.type_cast(obj) })
+ end
+
class Path #:nodoc:
def self.eager_load_templates!
@eager_load_templates = true
diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/renderable.rb
index 89ac500717..fa45edd436 100644
--- a/actionpack/lib/action_view/renderable.rb
+++ b/actionpack/lib/action_view/renderable.rb
@@ -31,7 +31,14 @@ module ActionView
view.send(:evaluate_assigns)
view.send(:set_controller_content_type, mime_type) if respond_to?(:mime_type)
- view.send(:execute, method_name(local_assigns), local_assigns)
+
+ view.send(method_name(local_assigns), local_assigns) do |*names|
+ if proc = view.instance_variable_get("@_proc_for_layout")
+ view.capture(*names, &proc)
+ else
+ view.instance_variable_get("@content_for_#{names.first || 'layout'}")
+ end
+ end
end
def method_name(local_assigns)
@@ -65,7 +72,7 @@ module ActionView
end_src
begin
- logger = ActionController::Base.logger
+ logger = defined?(ActionController) && Base.logger
logger.debug "Compiling template #{render_symbol}" if logger
ActionView::Base::CompiledTemplates.module_eval(source, filename, 0)
diff --git a/actionpack/lib/action_view/renderable_partial.rb b/actionpack/lib/action_view/renderable_partial.rb
index 342850f0f0..5203e57ead 100644
--- a/actionpack/lib/action_view/renderable_partial.rb
+++ b/actionpack/lib/action_view/renderable_partial.rb
@@ -16,7 +16,11 @@ module ActionView
memoize :counter_name
def render(view, local_assigns = {})
- ActionController::Base.benchmark("Rendered #{path_without_format_and_extension}", Logger::DEBUG, false) do
+ if defined? ActionController
+ ActionController::Base.benchmark("Rendered #{path_without_format_and_extension}", Logger::DEBUG, false) do
+ super
+ end
+ else
super
end
end
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 5dc6708431..64597b3d39 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -1,3 +1,5 @@
+require 'action_controller/mime_type'
+
module ActionView #:nodoc:
class Template
extend TemplateHandlers
diff --git a/actionpack/lib/action_view/template_error.rb b/actionpack/lib/action_view/template_error.rb
index 35fc07bdb2..2368662f31 100644
--- a/actionpack/lib/action_view/template_error.rb
+++ b/actionpack/lib/action_view/template_error.rb
@@ -7,7 +7,7 @@ module ActionView
attr_reader :original_exception
def initialize(template, assigns, original_exception)
- @base_path = template.base_path
+ @base_path = template.base_path.to_s
@assigns, @source, @original_exception = assigns.dup, template.source, original_exception
@file_path = template.filename
@backtrace = compute_backtrace
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index 1a3c93c283..adbb37fd09 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -25,9 +25,7 @@ module ActionView
end
end
- ActionView::Base.helper_modules.each do |helper_module|
- include helper_module
- end
+ include ActionView::Helpers
include ActionController::PolymorphicRoutes
include ActionController::RecordIdentifier
diff --git a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
index a82a1a3023..d75cb2b53a 100644
--- a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
+++ b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
@@ -39,6 +39,11 @@ class RenderPartialWithRecordIdentificationController < ActionController::Base
@developers = Developer.find(:all)
render :partial => @developers
end
+
+ def render_with_record_collection_and_spacer_template
+ @developer = Developer.find(1)
+ render :partial => @developer.projects, :spacer_template => 'test/partial_only'
+ end
end
class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase
@@ -81,6 +86,11 @@ class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase
assert_equal 'DavidJamisfixture_3fixture_4fixture_5fixture_6fixture_7fixture_8fixture_9fixture_10Jamis', @response.body
end
+ def test_render_with_record_collection_and_spacer_template
+ get :render_with_record_collection_and_spacer_template
+ assert_equal 'Active Recordonly partialActive Controller', @response.body
+ end
+
def test_rendering_partial_with_has_one_association
mascot = Company.find(1).mascot
get :render_with_has_one_association
diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb
index e1bc46bb56..ae71d62e11 100644
--- a/actionpack/test/controller/content_type_test.rb
+++ b/actionpack/test/controller/content_type_test.rb
@@ -19,6 +19,11 @@ class ContentTypeController < ActionController::Base
render :text => "hello world!"
end
+ def render_nil_charset_from_body
+ response.charset = nil
+ render :text => "hello world!"
+ end
+
def render_default_for_rhtml
end
@@ -85,8 +90,23 @@ class ContentTypeTest < Test::Unit::TestCase
def test_charset_from_body
get :render_charset_from_body
+ assert_equal Mime::HTML, @response.content_type
assert_equal "utf-16", @response.charset
+ end
+
+ def test_nil_charset_from_body
+ get :render_nil_charset_from_body
assert_equal Mime::HTML, @response.content_type
+ assert_equal "utf-8", @response.charset, @response.headers.inspect
+ end
+
+ def test_nil_default_for_rhtml
+ ContentTypeController.default_charset = nil
+ get :render_default_for_rhtml
+ assert_equal Mime::HTML, @response.content_type
+ assert_nil @response.charset, @response.headers.inspect
+ ensure
+ ContentTypeController.default_charset = "utf-8"
end
def test_default_for_rhtml
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 475e13897b..c986941140 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -253,7 +253,14 @@ class IntegrationProcessTest < ActionController::IntegrationTest
session :off
def get
- render :text => "OK", :status => 200
+ respond_to do |format|
+ format.html { render :text => "OK", :status => 200 }
+ format.js { render :text => "JS OK", :status => 200 }
+ end
+ end
+
+ def get_with_params
+ render :text => "foo: #{params[:foo]}", :status => 200
end
def post
@@ -265,6 +272,10 @@ class IntegrationProcessTest < ActionController::IntegrationTest
cookies["cookie_3"] = "chocolate"
render :text => "Gone", :status => 410
end
+
+ def redirect
+ redirect_to :action => "get"
+ end
end
def test_get
@@ -274,6 +285,9 @@ class IntegrationProcessTest < ActionController::IntegrationTest
assert_equal "OK", status_message
assert_equal "200 OK", response.headers["Status"]
assert_equal ["200 OK"], headers["status"]
+ assert_response 200
+ assert_response :success
+ assert_response :ok
assert_equal [], response.headers["cookie"]
assert_equal [], headers["cookie"]
assert_equal({}, cookies)
@@ -290,6 +304,9 @@ class IntegrationProcessTest < ActionController::IntegrationTest
assert_equal "Created", status_message
assert_equal "201 Created", response.headers["Status"]
assert_equal ["201 Created"], headers["status"]
+ assert_response 201
+ assert_response :success
+ assert_response :created
assert_equal [], response.headers["cookie"]
assert_equal [], headers["cookie"]
assert_equal({}, cookies)
@@ -308,23 +325,84 @@ class IntegrationProcessTest < ActionController::IntegrationTest
assert_equal "Gone", status_message
assert_equal "410 Gone", response.headers["Status"]
assert_equal ["410 Gone"], headers["status"]
- assert_equal nil, response.headers["Set-Cookie"]
+ assert_response 410
+ assert_response :gone
+ assert_equal ["cookie_1=; path=/", "cookie_3=chocolate; path=/"], response.headers["Set-Cookie"]
assert_equal ["cookie_1=; path=/", "cookie_3=chocolate; path=/"], headers['set-cookie']
- assert_equal [[], ["chocolate"]], response.headers["cookie"]
+ assert_equal [
+ CGI::Cookie::new("name" => "cookie_1", "value" => ""),
+ CGI::Cookie::new("name" => "cookie_3", "value" => "chocolate")
+ ], response.headers["cookie"]
assert_equal [], headers["cookie"]
assert_equal({"cookie_1"=>"", "cookie_2"=>"oatmeal", "cookie_3"=>"chocolate"}, cookies)
assert_equal "Gone", response.body
end
end
+ def test_redirect
+ with_test_route_set do
+ get '/redirect'
+ assert_equal 302, status
+ assert_equal "Found", status_message
+ assert_equal "302 Found", response.headers["Status"]
+ assert_equal ["302 Found"], headers["status"]
+ assert_response 302
+ assert_response :redirect
+ assert_response :found
+ assert_equal "<html><body>You are being <a href=\"http://www.example.com/get\">redirected</a>.</body></html>", response.body
+ assert_kind_of HTML::Document, html_document
+ assert_equal 1, request_count
+ end
+ end
+
+ def test_xml_http_request_get
+ with_test_route_set do
+ xhr :get, '/get'
+ assert_equal 200, status
+ assert_equal "OK", status_message
+ assert_equal "200 OK", response.headers["Status"]
+ assert_equal ["200 OK"], headers["status"]
+ assert_response 200
+ assert_response :success
+ assert_response :ok
+ assert_equal "JS OK", response.body
+ end
+ end
+
+ def test_get_with_query_string
+ with_test_route_set do
+ get '/get_with_params?foo=bar'
+ assert_equal '/get_with_params?foo=bar', request.env["REQUEST_URI"]
+ assert_equal '/get_with_params?foo=bar', request.request_uri
+ assert_equal nil, request.env["QUERY_STRING"]
+ assert_equal 'foo=bar', request.query_string
+ assert_equal 'bar', request.parameters['foo']
+
+ assert_equal 200, status
+ assert_equal "foo: bar", response.body
+ end
+ end
+
+ def test_get_with_parameters
+ with_test_route_set do
+ get '/get_with_params', :foo => "bar"
+ assert_equal '/get_with_params', request.env["REQUEST_URI"]
+ assert_equal '/get_with_params', request.request_uri
+ assert_equal 'foo=bar', request.env["QUERY_STRING"]
+ assert_equal 'foo=bar', request.query_string
+ assert_equal 'bar', request.parameters['foo']
+
+ assert_equal 200, status
+ assert_equal "foo: bar", response.body
+ end
+ end
+
private
def with_test_route_set
with_routing do |set|
set.draw do |map|
map.with_options :controller => "IntegrationProcessTest::Integration" do |c|
- c.connect '/get', :action => "get"
- c.connect '/post', :action => "post"
- c.connect '/cookie_monster', :action => "cookie_monster"
+ c.connect "/:action"
end
end
yield
diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb
index 72c01a9102..71f110f241 100644
--- a/actionpack/test/controller/layout_test.rb
+++ b/actionpack/test/controller/layout_test.rb
@@ -41,19 +41,19 @@ class LayoutAutoDiscoveryTest < Test::Unit::TestCase
@request.host = "www.nextangle.com"
end
-
+
def test_application_layout_is_default_when_no_controller_match
@controller = ProductController.new
get :hello
assert_equal 'layout_test.rhtml hello.rhtml', @response.body
end
-
+
def test_controller_name_layout_name_match
@controller = ItemController.new
get :hello
assert_equal 'item.rhtml hello.rhtml', @response.body
end
-
+
def test_third_party_template_library_auto_discovers_layout
ThirdPartyTemplateLibraryController.view_paths.reload!
@controller = ThirdPartyTemplateLibraryController.new
@@ -63,14 +63,14 @@ class LayoutAutoDiscoveryTest < Test::Unit::TestCase
assert_response :success
assert_equal 'Mab', @response.body
end
-
+
def test_namespaced_controllers_auto_detect_layouts
@controller = ControllerNameSpace::NestedController.new
get :hello
assert_equal 'layouts/controller_name_space/nested', @controller.active_layout
assert_equal 'controller_name_space/nested.rhtml hello.rhtml', @response.body
end
-
+
def test_namespaced_controllers_auto_detect_layouts
@controller = MultipleExtensions.new
get :hello
@@ -115,7 +115,7 @@ class ExemptFromLayoutTest < Test::Unit::TestCase
def test_rhtml_exempt_from_layout_status_should_prevent_layout_render
ActionController::Base.exempt_from_layout :rhtml
-
+
assert @controller.send!(:template_exempt_from_layout?, 'test.rhtml')
assert @controller.send!(:template_exempt_from_layout?, 'hello.rhtml')
@@ -156,19 +156,19 @@ class LayoutSetInResponseTest < Test::Unit::TestCase
get :hello
assert_equal 'layouts/layout_test', @response.layout
end
-
+
def test_layout_set_when_set_in_controller
@controller = HasOwnLayoutController.new
get :hello
assert_equal 'layouts/item', @response.layout
end
-
+
def test_layout_set_when_using_render
@controller = SetsLayoutInRenderController.new
get :hello
assert_equal 'layouts/third_party_template_library', @response.layout
end
-
+
def test_layout_is_not_set_when_none_rendered
@controller = RendersNoLayoutController.new
get :hello
@@ -249,4 +249,3 @@ class LayoutSymlinkedIsRenderedTest < Test::Unit::TestCase
assert_equal "layouts/symlinked/symlinked_layout", @response.layout
end
end
- \ No newline at end of file
diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb
index be99350cd2..82919b7777 100644
--- a/actionpack/test/controller/new_render_test.rb
+++ b/actionpack/test/controller/new_render_test.rb
@@ -435,6 +435,10 @@ class NewRenderTestController < ActionController::Base
render :action => "using_layout_around_block"
end
+ def render_using_layout_around_block_with_args
+ render :action => "using_layout_around_block_with_args"
+ end
+
def render_using_layout_around_block_in_main_layout_and_within_content_for_layout
render :action => "using_layout_around_block"
end
@@ -969,4 +973,9 @@ EOS
get :render_using_layout_around_block_in_main_layout_and_within_content_for_layout
assert_equal "Before (Anthony)\nInside from first block in layout\nAfter\nBefore (David)\nInside from block\nAfter\nBefore (Ramm)\nInside from second block in layout\nAfter\n", @response.body
end
+
+ def test_using_layout_around_block_with_args
+ get :render_using_layout_around_block_with_args
+ assert_equal "Before\narg1arg2\nAfter", @response.body
+ end
end
diff --git a/actionpack/test/controller/polymorphic_routes_test.rb b/actionpack/test/controller/polymorphic_routes_test.rb
index 3f52526f08..6ddf2826cd 100644
--- a/actionpack/test/controller/polymorphic_routes_test.rb
+++ b/actionpack/test/controller/polymorphic_routes_test.rb
@@ -60,6 +60,18 @@ uses_mocha 'polymorphic URL helpers' do
edit_polymorphic_url(@article)
end
+ def test_url_helper_prefixed_with_edit_with_url_options
+ @article.save
+ expects(:edit_article_url).with(@article, :param1 => '10')
+ edit_polymorphic_url(@article, :param1 => '10')
+ end
+
+ def test_url_helper_with_url_options
+ @article.save
+ expects(:article_url).with(@article, :param1 => '10')
+ polymorphic_url(@article, :param1 => '10')
+ end
+
def test_formatted_url_helper
expects(:formatted_article_url).with(@article, :pdf)
formatted_polymorphic_url([@article, :pdf])
@@ -67,10 +79,16 @@ uses_mocha 'polymorphic URL helpers' do
def test_format_option
@article.save
- expects(:article_url).with(@article, :pdf)
+ expects(:formatted_article_url).with(@article, :pdf)
polymorphic_url(@article, :format => :pdf)
end
+ def test_format_option_with_url_options
+ @article.save
+ expects(:formatted_article_url).with(@article, :pdf, :param1 => '10')
+ polymorphic_url(@article, :format => :pdf, :param1 => '10')
+ end
+
def test_id_and_format_option
@article.save
expects(:article_url).with(:id => @article, :format => :pdf)
@@ -147,7 +165,7 @@ uses_mocha 'polymorphic URL helpers' do
def test_nesting_with_array_containing_singleton_resource_and_format_option
@tag = Tag.new
@tag.save
- expects(:article_response_tag_url).with(@article, @tag, :pdf)
+ expects(:formatted_article_response_tag_url).with(@article, @tag, :pdf)
polymorphic_url([@article, :response, @tag], :format => :pdf)
end
diff --git a/actionpack/test/controller/rack_test.rb b/actionpack/test/controller/rack_test.rb
index d1650de1fc..d5e56b9584 100644
--- a/actionpack/test/controller/rack_test.rb
+++ b/actionpack/test/controller/rack_test.rb
@@ -236,10 +236,17 @@ class RackResponseTest < BaseRackTest
def test_simple_output
@response.body = "Hello, World!"
+ @response.prepare!
status, headers, body = @response.out(@output)
assert_equal "200 OK", status
- assert_equal({"Content-Type" => "text/html", "Cache-Control" => "no-cache", "Set-Cookie" => []}, headers)
+ assert_equal({
+ "Content-Type" => "text/html; charset=utf-8",
+ "Cache-Control" => "private, max-age=0, must-revalidate",
+ "ETag" => '"65a8e27d8879283831b664bd8b7f0ad4"',
+ "Set-Cookie" => [],
+ "Content-Length" => "13"
+ }, headers)
parts = []
body.each { |part| parts << part }
@@ -250,10 +257,11 @@ class RackResponseTest < BaseRackTest
@response.body = Proc.new do |response, output|
5.times { |n| output.write(n) }
end
+ @response.prepare!
status, headers, body = @response.out(@output)
assert_equal "200 OK", status
- assert_equal({"Content-Type" => "text/html", "Cache-Control" => "no-cache", "Set-Cookie" => []}, headers)
+ assert_equal({"Content-Type" => "text/html; charset=utf-8", "Cache-Control" => "no-cache", "Set-Cookie" => []}, headers)
parts = []
body.each { |part| parts << part }
@@ -265,13 +273,16 @@ class RackResponseTest < BaseRackTest
@request.cgi.send :instance_variable_set, '@output_cookies', [cookie]
@response.body = "Hello, World!"
+ @response.prepare!
status, headers, body = @response.out(@output)
assert_equal "200 OK", status
assert_equal({
- "Content-Type" => "text/html",
- "Cache-Control" => "no-cache",
- "Set-Cookie" => ["name=Josh; path="]
+ "Content-Type" => "text/html; charset=utf-8",
+ "Cache-Control" => "private, max-age=0, must-revalidate",
+ "ETag" => '"65a8e27d8879283831b664bd8b7f0ad4"',
+ "Set-Cookie" => ["name=Josh; path="],
+ "Content-Length" => "13"
}, headers)
parts = []
@@ -285,18 +296,18 @@ class RackResponseHeadersTest < BaseRackTest
super
@response = ActionController::RackResponse.new(@request)
@output = StringIO.new('')
- @response.headers['Status'] = 200
+ @response.headers['Status'] = "200 OK"
end
def test_content_type
[204, 304].each do |c|
- @response.headers['Status'] = c
- assert !response_headers.has_key?("Content-Type")
+ @response.headers['Status'] = c.to_s
+ assert !response_headers.has_key?("Content-Type"), "#{c} should not have Content-Type header"
end
[200, 302, 404, 500].each do |c|
- @response.headers['Status'] = c
- assert response_headers.has_key?("Content-Type")
+ @response.headers['Status'] = c.to_s
+ assert response_headers.has_key?("Content-Type"), "#{c} did not have Content-Type header"
end
end
@@ -305,8 +316,8 @@ class RackResponseHeadersTest < BaseRackTest
end
private
-
- def response_headers
- @response.out(@output)[1]
- end
+ def response_headers
+ @response.prepare!
+ @response.out(@output)[1]
+ end
end
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 1b9b12acc6..3008f5ca03 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -329,7 +329,7 @@ class RenderTest < Test::Unit::TestCase
def test_render_text_with_nil
get :render_text_with_nil
assert_response 200
- assert_equal '', @response.body
+ assert_equal ' ', @response.body
end
def test_render_text_with_false
diff --git a/actionpack/test/controller/request_test.rb b/actionpack/test/controller/request_test.rb
index 226c1ac018..e79a0ea76b 100644
--- a/actionpack/test/controller/request_test.rb
+++ b/actionpack/test/controller/request_test.rb
@@ -17,6 +17,9 @@ class RequestTest < Test::Unit::TestCase
@request.remote_addr = '1.2.3.4'
assert_equal '1.2.3.4', @request.remote_ip(true)
+ @request.remote_addr = '1.2.3.4,3.4.5.6'
+ assert_equal '1.2.3.4', @request.remote_ip(true)
+
@request.env['HTTP_CLIENT_IP'] = '2.3.4.5'
assert_equal '1.2.3.4', @request.remote_ip(true)
@@ -397,7 +400,6 @@ class RequestTest < Test::Unit::TestCase
end
end
-
class UrlEncodedRequestParameterParsingTest < Test::Unit::TestCase
def setup
@query_string = "action=create_customer&full_name=David%20Heinemeier%20Hansson&customerId=1"
@@ -509,7 +511,6 @@ class UrlEncodedRequestParameterParsingTest < Test::Unit::TestCase
)
end
-
def test_request_hash_parsing
query = {
"note[viewers][viewer][][type]" => ["User", "Group"],
@@ -521,7 +522,6 @@ class UrlEncodedRequestParameterParsingTest < Test::Unit::TestCase
assert_equal(expected, ActionController::AbstractRequest.parse_request_parameters(query))
end
-
def test_parse_params
input = {
"customers[boston][first][name]" => [ "David" ],
@@ -704,7 +704,6 @@ class UrlEncodedRequestParameterParsingTest < Test::Unit::TestCase
end
end
-
class MultipartRequestParameterParsingTest < Test::Unit::TestCase
FIXTURE_PATH = File.dirname(__FILE__) + '/../fixtures/multipart'
@@ -852,20 +851,20 @@ class XmlParamsParsingTest < Test::Unit::TestCase
private
def parse_body(body)
- env = { 'CONTENT_TYPE' => 'application/xml',
+ env = { 'rack.input' => StringIO.new(body),
+ 'CONTENT_TYPE' => 'application/xml',
'CONTENT_LENGTH' => body.size.to_s }
- cgi = ActionController::Integration::Session::StubCGI.new(env, body)
- ActionController::CgiRequest.new(cgi).request_parameters
+ ActionController::RackRequest.new(env).request_parameters
end
end
class LegacyXmlParamsParsingTest < XmlParamsParsingTest
private
def parse_body(body)
- env = { 'HTTP_X_POST_DATA_FORMAT' => 'xml',
- 'CONTENT_LENGTH' => body.size.to_s }
- cgi = ActionController::Integration::Session::StubCGI.new(env, body)
- ActionController::CgiRequest.new(cgi).request_parameters
+ env = { 'rack.input' => StringIO.new(body),
+ 'HTTP_X_POST_DATA_FORMAT' => 'xml',
+ 'CONTENT_LENGTH' => body.size.to_s }
+ ActionController::RackRequest.new(env).request_parameters
end
end
@@ -884,9 +883,9 @@ class JsonParamsParsingTest < Test::Unit::TestCase
private
def parse_body(body,content_type)
- env = { 'CONTENT_TYPE' => content_type,
+ env = { 'rack.input' => StringIO.new(body),
+ 'CONTENT_TYPE' => content_type,
'CONTENT_LENGTH' => body.size.to_s }
- cgi = ActionController::Integration::Session::StubCGI.new(env, body)
- ActionController::CgiRequest.new(cgi).request_parameters
+ ActionController::RackRequest.new(env).request_parameters
end
end
diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb
index 58d9ca537f..9eff34a542 100644
--- a/actionpack/test/controller/test_test.rb
+++ b/actionpack/test/controller/test_test.rb
@@ -531,6 +531,11 @@ XML
assert_equal content_type, file.content_type
assert_equal file.path, file.local_path
assert_equal expected, file.read
+
+ new_content_type = "new content_type"
+ file.content_type = new_content_type
+ assert_equal new_content_type, file.content_type
+
end
def test_test_uploaded_file_with_binary
diff --git a/actionpack/test/fixtures/test/_layout_for_block_with_args.html.erb b/actionpack/test/fixtures/test/_layout_for_block_with_args.html.erb
new file mode 100644
index 0000000000..307533208d
--- /dev/null
+++ b/actionpack/test/fixtures/test/_layout_for_block_with_args.html.erb
@@ -0,0 +1,3 @@
+Before
+<%= yield 'arg1', 'arg2' %>
+After \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/using_layout_around_block_with_args.html.erb b/actionpack/test/fixtures/test/using_layout_around_block_with_args.html.erb
new file mode 100644
index 0000000000..71b1f30ad0
--- /dev/null
+++ b/actionpack/test/fixtures/test/using_layout_around_block_with_args.html.erb
@@ -0,0 +1 @@
+<% render(:layout => "layout_for_block_with_args") do |*args| %><%= args.join %><% end %> \ No newline at end of file
diff --git a/actionpack/test/template/active_record_helper_i18n_test.rb b/actionpack/test/template/active_record_helper_i18n_test.rb
index feec64aa30..7ba9659814 100644
--- a/actionpack/test/template/active_record_helper_i18n_test.rb
+++ b/actionpack/test/template/active_record_helper_i18n_test.rb
@@ -10,37 +10,37 @@ class ActiveRecordHelperI18nTest < Test::Unit::TestCase
@object_name = 'book'
stubs(:content_tag).returns 'content_tag'
- I18n.stubs(:t).with(:'header_message', :locale => 'en-US', :scope => [:active_record, :error], :count => 1, :object_name => '').returns "1 error prohibited this from being saved"
- I18n.stubs(:t).with(:'message', :locale => 'en-US', :scope => [:active_record, :error]).returns 'There were problems with the following fields:'
+ I18n.stubs(:t).with(:'header', :locale => 'en-US', :scope => [:activerecord, :errors, :template], :count => 1, :model => '').returns "1 error prohibited this from being saved"
+ I18n.stubs(:t).with(:'body', :locale => 'en-US', :scope => [:activerecord, :errors, :template]).returns 'There were problems with the following fields:'
end
- def test_error_messages_for_given_a_header_message_option_it_does_not_translate_header_message
- I18n.expects(:translate).with(:'header_message', :locale => 'en-US', :scope => [:active_record, :error], :count => 1, :object_name => '').never
+ def test_error_messages_for_given_a_header_option_it_does_not_translate_header_message
+ I18n.expects(:translate).with(:'header', :locale => 'en-US', :scope => [:activerecord, :errors, :template], :count => 1, :model => '').never
error_messages_for(:object => @object, :header_message => 'header message', :locale => 'en-US')
end
- def test_error_messages_for_given_no_header_message_option_it_translates_header_message
- I18n.expects(:t).with(:'header_message', :locale => 'en-US', :scope => [:active_record, :error], :count => 1, :object_name => '').returns 'header message'
- I18n.expects(:t).with('', :default => '').once.returns ''
+ def test_error_messages_for_given_no_header_option_it_translates_header_message
+ I18n.expects(:t).with(:'header', :locale => 'en-US', :scope => [:activerecord, :errors, :template], :count => 1, :model => '').returns 'header message'
+ I18n.expects(:t).with('', :default => '', :count => 1, :scope => [:activerecord, :models]).once.returns ''
error_messages_for(:object => @object, :locale => 'en-US')
end
def test_error_messages_for_given_a_message_option_it_does_not_translate_message
- I18n.expects(:t).with(:'message', :locale => 'en-US', :scope => [:active_record, :error]).never
- I18n.expects(:t).with('', :default => '').once.returns ''
+ I18n.expects(:t).with(:'body', :locale => 'en-US', :scope => [:activerecord, :errors, :template]).never
+ I18n.expects(:t).with('', :default => '', :count => 1, :scope => [:activerecord, :models]).once.returns ''
error_messages_for(:object => @object, :message => 'message', :locale => 'en-US')
end
def test_error_messages_for_given_no_message_option_it_translates_message
- I18n.expects(:t).with(:'message', :locale => 'en-US', :scope => [:active_record, :error]).returns 'There were problems with the following fields:'
- I18n.expects(:t).with('', :default => '').once.returns ''
+ I18n.expects(:t).with(:'body', :locale => 'en-US', :scope => [:activerecord, :errors, :template]).returns 'There were problems with the following fields:'
+ I18n.expects(:t).with('', :default => '', :count => 1, :scope => [:activerecord, :models]).once.returns ''
error_messages_for(:object => @object, :locale => 'en-US')
end
def test_error_messages_for_given_object_name_it_translates_object_name
- I18n.expects(:t).with(:header_message, :locale => 'en-US', :scope => [:active_record, :error], :count => 1, :object_name => @object_name).returns "1 error prohibited this #{@object_name} from being saved"
- I18n.expects(:t).with(@object_name, :default => @object_name).once.returns @object_name
+ I18n.expects(:t).with(:header, :locale => 'en-US', :scope => [:activerecord, :errors, :template], :count => 1, :model => @object_name).returns "1 error prohibited this #{@object_name} from being saved"
+ I18n.expects(:t).with(@object_name, :default => @object_name, :count => 1, :scope => [:activerecord, :models]).once.returns @object_name
error_messages_for(:object => @object, :locale => 'en-US', :object_name => @object_name)
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/test/template/atom_feed_helper_test.rb b/actionpack/test/template/atom_feed_helper_test.rb
index 9f7e5b4c6c..ef31ab2c76 100644
--- a/actionpack/test/template/atom_feed_helper_test.rb
+++ b/actionpack/test/template/atom_feed_helper_test.rb
@@ -74,12 +74,30 @@ class ScrollsController < ActionController::Base
end
end
EOT
+ FEEDS["feed_with_overridden_ids"] = <<-EOT
+ atom_feed({:id => 'tag:test.rubyonrails.org,2008:test/'}) do |feed|
+ feed.title("My great blog!")
+ feed.updated((@scrolls.first.created_at))
+
+ for scroll in @scrolls
+ feed.entry(scroll, :id => "tag:test.rubyonrails.org,2008:"+scroll.id.to_s) do |entry|
+ entry.title(scroll.title)
+ entry.content(scroll.body, :type => 'html')
+ entry.tag!('app:edited', Time.now)
+
+ entry.author do |author|
+ author.name("DHH")
+ end
+ end
+ end
+ end
+ EOT
def index
@scrolls = [
Scroll.new(1, "1", "Hello One", "Something <i>COOL!</i>", Time.utc(2007, 12, 12, 15), Time.utc(2007, 12, 12, 15)),
Scroll.new(2, "2", "Hello Two", "Something Boring", Time.utc(2007, 12, 12, 15)),
]
-
+
render :inline => FEEDS[params[:id]], :type => :builder
end
@@ -98,21 +116,21 @@ class AtomFeedTest < Test::Unit::TestCase
@request.host = "www.nextangle.com"
end
-
+
def test_feed_should_use_default_language_if_none_is_given
with_restful_routing(:scrolls) do
get :index, :id => "defaults"
assert_match %r{xml:lang="en-US"}, @response.body
end
end
-
+
def test_feed_should_include_two_entries
with_restful_routing(:scrolls) do
get :index, :id => "defaults"
assert_select "entry", 2
end
end
-
+
def test_entry_should_only_use_published_if_created_at_is_present
with_restful_routing(:scrolls) do
get :index, :id => "defaults"
@@ -167,7 +185,16 @@ class AtomFeedTest < Test::Unit::TestCase
end
end
- private
+ def test_feed_should_allow_overriding_ids
+ with_restful_routing(:scrolls) do
+ get :index, :id => "feed_with_overridden_ids"
+ assert_select "id", :text => "tag:test.rubyonrails.org,2008:test/"
+ assert_select "entry id", :text => "tag:test.rubyonrails.org,2008:1"
+ assert_select "entry id", :text => "tag:test.rubyonrails.org,2008:2"
+ end
+ end
+
+private
def with_restful_routing(resources)
with_routing do |set|
set.draw do |map|
diff --git a/actionpack/test/template/date_helper_i18n_test.rb b/actionpack/test/template/date_helper_i18n_test.rb
index 2b40074498..bf3b2588c8 100644
--- a/actionpack/test/template/date_helper_i18n_test.rb
+++ b/actionpack/test/template/date_helper_i18n_test.rb
@@ -47,6 +47,28 @@ class DateHelperDistanceOfTimeInWordsI18nTests < Test::Unit::TestCase
I18n.expects(:t).with(key, options)
distance_of_time_in_words(@from, to, include_seconds, :locale => 'en-US')
end
+
+ def test_distance_of_time_pluralizations
+ { [:'less_than_x_seconds', 1] => 'less than 1 second',
+ [:'less_than_x_seconds', 2] => 'less than 2 seconds',
+ [:'less_than_x_minutes', 1] => 'less than a minute',
+ [:'less_than_x_minutes', 2] => 'less than 2 minutes',
+ [:'x_minutes', 1] => '1 minute',
+ [:'x_minutes', 2] => '2 minutes',
+ [:'about_x_hours', 1] => 'about 1 hour',
+ [:'about_x_hours', 2] => 'about 2 hours',
+ [:'x_days', 1] => '1 day',
+ [:'x_days', 2] => '2 days',
+ [:'about_x_years', 1] => 'about 1 year',
+ [:'about_x_years', 2] => 'about 2 years',
+ [:'over_x_years', 1] => 'over 1 year',
+ [:'over_x_years', 2] => 'over 2 years'
+
+ }.each do |args, expected|
+ key, count = *args
+ assert_equal expected, I18n.t(key, :count => count, :scope => 'datetime.distance_in_words')
+ end
+ end
end
end
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index 31cfdce531..f3c8dbcae9 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -87,6 +87,18 @@ class ViewRenderTest < Test::Unit::TestCase
@view.render(:partial => "test/local_inspector", :collection => [ Customer.new("mary") ])
end
+ def test_render_partial_with_empty_collection_should_return_nil
+ assert_nil @view.render(:partial => "test/customer", :collection => [])
+ end
+
+ def test_render_partial_with_nil_collection_should_return_nil
+ assert_nil @view.render(:partial => "test/customer", :collection => nil)
+ end
+
+ def test_render_partial_with_empty_array_should_return_nil
+ assert_nil @view.render(:partial => [])
+ end
+
# TODO: The reason for this test is unclear, improve documentation
def test_render_partial_and_fallback_to_layout
assert_equal "Before (Josh)\n\nAfter", @view.render(:partial => "test/layout_for_partial", :locals => { :name => "Josh" })
diff --git a/actionpack/test/template/sanitize_helper_test.rb b/actionpack/test/template/sanitize_helper_test.rb
index e5427d9dc1..f715071bbc 100644
--- a/actionpack/test/template/sanitize_helper_test.rb
+++ b/actionpack/test/template/sanitize_helper_test.rb
@@ -11,9 +11,9 @@ class SanitizeHelperTest < ActionView::TestCase
assert_equal "Dont touch me", strip_links("Dont touch me")
assert_equal "<a<a", strip_links("<a<a")
assert_equal "on my mind\nall day long", strip_links("<a href='almost'>on my mind</a>\n<A href='almost'>all day long</A>")
- assert_equal "0wn3d", strip_links("<a href='http://www.rubyonrails.com/'><a href='http://www.rubyonrails.com/' onlclick='steal()'>0wn3d</a></a>")
- assert_equal "Magic", strip_links("<a href='http://www.rubyonrails.com/'>Mag<a href='http://www.ruby-lang.org/'>ic")
- assert_equal "FrrFox", strip_links("<href onlclick='steal()'>FrrFox</a></href>")
+ assert_equal "0wn3d", strip_links("<a href='http://www.rubyonrails.com/'><a href='http://www.rubyonrails.com/' onlclick='steal()'>0wn3d</a></a>")
+ assert_equal "Magic", strip_links("<a href='http://www.rubyonrails.com/'>Mag<a href='http://www.ruby-lang.org/'>ic")
+ assert_equal "FrrFox", strip_links("<href onlclick='steal()'>FrrFox</a></href>")
assert_equal "My mind\nall <b>day</b> long", strip_links("<a href='almost'>My mind</a>\n<A href='almost'>all <b>day</b> long</A>")
assert_equal "all <b>day</b> long", strip_links("<<a>a href='hello'>all <b>day</b> long<</A>/a>")
end
diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb
index a31d532567..5f9f715819 100644
--- a/actionpack/test/template/text_helper_test.rb
+++ b/actionpack/test/template/text_helper_test.rb
@@ -369,6 +369,40 @@ class TextHelperTest < ActionView::TestCase
assert_equal("red", cycle("red", "blue", :name => "colors"))
end
+ def test_current_cycle_with_default_name
+ cycle("even","odd")
+ assert_equal "even", current_cycle
+ cycle("even","odd")
+ assert_equal "odd", current_cycle
+ cycle("even","odd")
+ assert_equal "even", current_cycle
+ end
+
+ def test_current_cycle_with_named_cycles
+ cycle("red", "blue", :name => "colors")
+ assert_equal "red", current_cycle("colors")
+ cycle("red", "blue", :name => "colors")
+ assert_equal "blue", current_cycle("colors")
+ cycle("red", "blue", :name => "colors")
+ assert_equal "red", current_cycle("colors")
+ end
+
+ def test_current_cycle_safe_call
+ assert_nothing_raised { current_cycle }
+ assert_nothing_raised { current_cycle("colors") }
+ end
+
+ def test_current_cycle_with_more_than_two_names
+ cycle(1,2,3)
+ assert_equal "1", current_cycle
+ cycle(1,2,3)
+ assert_equal "2", current_cycle
+ cycle(1,2,3)
+ assert_equal "3", current_cycle
+ cycle(1,2,3)
+ assert_equal "1", current_cycle
+ end
+
def test_default_named_cycle
assert_equal("1", cycle(1, 2, 3))
assert_equal("2", cycle(1, 2, 3, :name => "default"))
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index 3065d33c1b..85e967ac1c 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
require 'abstract_unit'
RequestMock = Struct.new("Request", :request_uri, :protocol, :host_with_port, :env)