Merge branch 'bzr/golem' of /Users/distler/Sites/code/instiki
This commit is contained in:
commit
af22bc67e6
|
@ -1,3 +1,12 @@
|
||||||
|
* 0.16.5: Rails 2.3.2
|
||||||
|
|
||||||
|
* Runs on the Stable Release, Rails 2.3.2.
|
||||||
|
* Support for audio/speex audio files.
|
||||||
|
* Updated for itex2MML 1.3.7. (You should
|
||||||
|
upgrade that, as well.)
|
||||||
|
* Tests for BlahTeX/PNG (if installed).
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
* 0.16.4
|
* 0.16.4
|
||||||
|
|
||||||
New Features:
|
New Features:
|
||||||
|
|
|
@ -57,6 +57,7 @@ class ApplicationController < ActionController::Base
|
||||||
'.mov' => 'video/quicktime',
|
'.mov' => 'video/quicktime',
|
||||||
'.mp3' => 'audio/mpeg',
|
'.mp3' => 'audio/mpeg',
|
||||||
'.mp4' => 'video/mp4',
|
'.mp4' => 'video/mp4',
|
||||||
|
'.spx' => 'audio/speex',
|
||||||
'.txt' => 'text/plain',
|
'.txt' => 'text/plain',
|
||||||
'.tex' => 'text/plain',
|
'.tex' => 'text/plain',
|
||||||
'.wav' => 'audio/x-wav',
|
'.wav' => 'audio/x-wav',
|
||||||
|
@ -72,6 +73,7 @@ class ApplicationController < ActionController::Base
|
||||||
'audio/mpeg' => 'inline',
|
'audio/mpeg' => 'inline',
|
||||||
'audio/x-wav' => 'inline',
|
'audio/x-wav' => 'inline',
|
||||||
'audio/x-aiff' => 'inline',
|
'audio/x-aiff' => 'inline',
|
||||||
|
'audio/speex' => 'inline',
|
||||||
'audio/ogg' => 'inline',
|
'audio/ogg' => 'inline',
|
||||||
'video/ogg' => 'inline',
|
'video/ogg' => 'inline',
|
||||||
'video/mp4' => 'inline',
|
'video/mp4' => 'inline',
|
||||||
|
@ -260,7 +262,7 @@ module Instiki
|
||||||
module VERSION #:nodoc:
|
module VERSION #:nodoc:
|
||||||
MAJOR = 0
|
MAJOR = 0
|
||||||
MINOR = 16
|
MINOR = 16
|
||||||
TINY = 4
|
TINY = 5
|
||||||
SUFFIX = '(MML+)'
|
SUFFIX = '(MML+)'
|
||||||
PRERELEASE = false
|
PRERELEASE = false
|
||||||
if PRERELEASE
|
if PRERELEASE
|
||||||
|
|
|
@ -208,9 +208,9 @@ class WikiControllerTest < ActionController::TestCase
|
||||||
# end
|
# end
|
||||||
|
|
||||||
else
|
else
|
||||||
puts 'Warning: tests involving pdflatex are very slow, therefore they are disabled by default.'
|
# puts 'Warning: tests involving pdflatex are very slow, therefore they are disabled by default.'
|
||||||
puts ' Set environment variable INSTIKI_TEST_PDFLATEX or global Ruby variable'
|
# puts ' Set environment variable INSTIKI_TEST_PDFLATEX or global Ruby variable'
|
||||||
puts ' $INSTIKI_TEST_PDFLATEX to enable them.'
|
# puts ' $INSTIKI_TEST_PDFLATEX to enable them.'
|
||||||
end
|
end
|
||||||
|
|
||||||
# def test_export_tex
|
# def test_export_tex
|
||||||
|
|
5
vendor/rails/actionmailer/CHANGELOG
vendored
5
vendor/rails/actionmailer/CHANGELOG
vendored
|
@ -1,10 +1,7 @@
|
||||||
*2.3.1 [RC2] (March 5, 2009)*
|
*2.3.2 [Final] (March 15, 2009)*
|
||||||
|
|
||||||
* Fixed that ActionMailer should send correctly formatted Return-Path in MAIL FROM for SMTP #1842 [Matt Jones]
|
* Fixed that ActionMailer should send correctly formatted Return-Path in MAIL FROM for SMTP #1842 [Matt Jones]
|
||||||
|
|
||||||
|
|
||||||
*2.3.0 [RC1] (February 1st, 2009)*
|
|
||||||
|
|
||||||
* Fixed RFC-2045 quoted-printable bug #1421 [squadette]
|
* Fixed RFC-2045 quoted-printable bug #1421 [squadette]
|
||||||
|
|
||||||
* Fixed that no body charset would be set when there are attachments present #740 [Paweł Kondzior]
|
* Fixed that no body charset would be set when there are attachments present #740 [Paweł Kondzior]
|
||||||
|
|
2
vendor/rails/actionmailer/Rakefile
vendored
2
vendor/rails/actionmailer/Rakefile
vendored
|
@ -55,7 +55,7 @@ spec = Gem::Specification.new do |s|
|
||||||
s.rubyforge_project = "actionmailer"
|
s.rubyforge_project = "actionmailer"
|
||||||
s.homepage = "http://www.rubyonrails.org"
|
s.homepage = "http://www.rubyonrails.org"
|
||||||
|
|
||||||
s.add_dependency('actionpack', '= 2.3.1' + PKG_BUILD)
|
s.add_dependency('actionpack', '= 2.3.2' + PKG_BUILD)
|
||||||
|
|
||||||
s.has_rdoc = true
|
s.has_rdoc = true
|
||||||
s.requirements << 'none'
|
s.requirements << 'none'
|
||||||
|
|
|
@ -479,7 +479,7 @@ module ActionMailer #:nodoc:
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
unless @parts.empty?
|
unless @parts.empty?
|
||||||
@content_type = "multipart/alternative"
|
@content_type = "multipart/alternative" if @content_type !~ /^multipart/
|
||||||
@parts = sort_parts(@parts, @implicit_parts_order)
|
@parts = sort_parts(@parts, @implicit_parts_order)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1150,7 +1150,7 @@ if __FILE__ == $0
|
||||||
assert_equal(Text::Format::JUSTIFY, @format_o.format_style)
|
assert_equal(Text::Format::JUSTIFY, @format_o.format_style)
|
||||||
assert_match(/^of freedom, and that government of the people, by the people, for the$/,
|
assert_match(/^of freedom, and that government of the people, by the people, for the$/,
|
||||||
@format_o.format(GETTYSBURG).split("\n")[-3])
|
@format_o.format(GETTYSBURG).split("\n")[-3])
|
||||||
assert_raises(ArgumentError) { @format_o.format_style = 33 }
|
assert_raise(ArgumentError) { @format_o.format_style = 33 }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_tag_paragraph
|
def test_tag_paragraph
|
||||||
|
|
|
@ -2,7 +2,7 @@ module ActionMailer
|
||||||
module VERSION #:nodoc:
|
module VERSION #:nodoc:
|
||||||
MAJOR = 2
|
MAJOR = 2
|
||||||
MINOR = 3
|
MINOR = 3
|
||||||
TINY = 1
|
TINY = 2
|
||||||
|
|
||||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,10 +21,12 @@ class AutoLayoutMailer < ActionMailer::Base
|
||||||
body render(:inline => "Hello, <%= @world %>", :layout => false, :body => { :world => "Earth" })
|
body render(:inline => "Hello, <%= @world %>", :layout => false, :body => { :world => "Earth" })
|
||||||
end
|
end
|
||||||
|
|
||||||
def multipart(recipient)
|
def multipart(recipient, type = nil)
|
||||||
recipients recipient
|
recipients recipient
|
||||||
subject "You have a mail"
|
subject "You have a mail"
|
||||||
from "tester@example.com"
|
from "tester@example.com"
|
||||||
|
|
||||||
|
content_type(type) if type
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -64,6 +66,7 @@ class LayoutMailerTest < Test::Unit::TestCase
|
||||||
|
|
||||||
def test_should_pickup_multipart_layout
|
def test_should_pickup_multipart_layout
|
||||||
mail = AutoLayoutMailer.create_multipart(@recipient)
|
mail = AutoLayoutMailer.create_multipart(@recipient)
|
||||||
|
assert_equal "multipart/alternative", mail.content_type
|
||||||
assert_equal 2, mail.parts.size
|
assert_equal 2, mail.parts.size
|
||||||
|
|
||||||
assert_equal 'text/plain', mail.parts.first.content_type
|
assert_equal 'text/plain', mail.parts.first.content_type
|
||||||
|
@ -73,6 +76,31 @@ class LayoutMailerTest < Test::Unit::TestCase
|
||||||
assert_equal "Hello from layout text/html multipart", mail.parts.last.body
|
assert_equal "Hello from layout text/html multipart", mail.parts.last.body
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_should_pickup_multipartmixed_layout
|
||||||
|
mail = AutoLayoutMailer.create_multipart(@recipient, "multipart/mixed")
|
||||||
|
assert_equal "multipart/mixed", mail.content_type
|
||||||
|
assert_equal 2, mail.parts.size
|
||||||
|
|
||||||
|
assert_equal 'text/plain', mail.parts.first.content_type
|
||||||
|
assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
|
||||||
|
|
||||||
|
assert_equal 'text/html', mail.parts.last.content_type
|
||||||
|
assert_equal "Hello from layout text/html multipart", mail.parts.last.body
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_should_fix_multipart_layout
|
||||||
|
mail = AutoLayoutMailer.create_multipart(@recipient, "text/plain")
|
||||||
|
assert_equal "multipart/alternative", mail.content_type
|
||||||
|
assert_equal 2, mail.parts.size
|
||||||
|
|
||||||
|
assert_equal 'text/plain', mail.parts.first.content_type
|
||||||
|
assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
|
||||||
|
|
||||||
|
assert_equal 'text/html', mail.parts.last.content_type
|
||||||
|
assert_equal "Hello from layout text/html multipart", mail.parts.last.body
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def test_should_pickup_layout_given_to_render
|
def test_should_pickup_layout_given_to_render
|
||||||
mail = AutoLayoutMailer.create_spam(@recipient)
|
mail = AutoLayoutMailer.create_spam(@recipient)
|
||||||
assert_equal "Spammer layout Hello, Earth", mail.body.strip
|
assert_equal "Spammer layout Hello, Earth", mail.body.strip
|
||||||
|
|
|
@ -1069,7 +1069,7 @@ class RespondToTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_still_raise_exception_with_expected_message_when_calling_an_undefined_method
|
def test_should_still_raise_exception_with_expected_message_when_calling_an_undefined_method
|
||||||
error = assert_raises NoMethodError do
|
error = assert_raise NoMethodError do
|
||||||
RespondToMailer.not_a_method
|
RespondToMailer.not_a_method
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ class TestHelperMailerTest < ActionMailer::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_determine_default_mailer_raises_correct_error
|
def test_determine_default_mailer_raises_correct_error
|
||||||
assert_raises(ActionMailer::NonInferrableMailerError) do
|
assert_raise(ActionMailer::NonInferrableMailerError) do
|
||||||
self.class.determine_default_mailer("NotAMailerTest")
|
self.class.determine_default_mailer("NotAMailerTest")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -84,7 +84,7 @@ class TestHelperMailerTest < ActionMailer::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assert_emails_too_few_sent
|
def test_assert_emails_too_few_sent
|
||||||
error = assert_raises ActiveSupport::TestCase::Assertion do
|
error = assert_raise ActiveSupport::TestCase::Assertion do
|
||||||
assert_emails 2 do
|
assert_emails 2 do
|
||||||
TestHelperMailer.deliver_test
|
TestHelperMailer.deliver_test
|
||||||
end
|
end
|
||||||
|
@ -94,7 +94,7 @@ class TestHelperMailerTest < ActionMailer::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assert_emails_too_many_sent
|
def test_assert_emails_too_many_sent
|
||||||
error = assert_raises ActiveSupport::TestCase::Assertion do
|
error = assert_raise ActiveSupport::TestCase::Assertion do
|
||||||
assert_emails 1 do
|
assert_emails 1 do
|
||||||
TestHelperMailer.deliver_test
|
TestHelperMailer.deliver_test
|
||||||
TestHelperMailer.deliver_test
|
TestHelperMailer.deliver_test
|
||||||
|
@ -105,7 +105,7 @@ class TestHelperMailerTest < ActionMailer::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assert_no_emails_failure
|
def test_assert_no_emails_failure
|
||||||
error = assert_raises ActiveSupport::TestCase::Assertion do
|
error = assert_raise ActiveSupport::TestCase::Assertion do
|
||||||
assert_no_emails do
|
assert_no_emails do
|
||||||
TestHelperMailer.deliver_test
|
TestHelperMailer.deliver_test
|
||||||
end
|
end
|
||||||
|
|
7
vendor/rails/actionpack/CHANGELOG
vendored
7
vendor/rails/actionpack/CHANGELOG
vendored
|
@ -1,4 +1,4 @@
|
||||||
*2.3.1 [RC2] (March 5, 2009)*
|
*2.3.2 [Final] (March 15, 2009)*
|
||||||
|
|
||||||
* Fixed that redirection would just log the options, not the final url (which lead to "Redirected to #<Post:0x23150b8>") [DHH]
|
* Fixed that redirection would just log the options, not the final url (which lead to "Redirected to #<Post:0x23150b8>") [DHH]
|
||||||
|
|
||||||
|
@ -6,15 +6,14 @@
|
||||||
|
|
||||||
* Fixed that passing a custom form builder would be forwarded to nested fields_for calls #2023 [Eloy Duran/Nate Wiger]
|
* Fixed that passing a custom form builder would be forwarded to nested fields_for calls #2023 [Eloy Duran/Nate Wiger]
|
||||||
|
|
||||||
|
* Form option helpers now support disabled option tags and the use of lambdas for selecting/disabling option tags from collections #837 [Tekin]
|
||||||
|
|
||||||
* Added partial scoping to TranslationHelper#translate, so if you call translate(".foo") from the people/index.html.erb template, you'll actually be calling I18n.translate("people.index.foo") [DHH]
|
* Added partial scoping to TranslationHelper#translate, so if you call translate(".foo") from the people/index.html.erb template, you'll actually be calling I18n.translate("people.index.foo") [DHH]
|
||||||
|
|
||||||
* Fix a syntax error in current_page?() that was prevent matches against URL's with multiple query parameters #1385, #1868 [chris finne/Andrew White]
|
* Fix a syntax error in current_page?() that was prevent matches against URL's with multiple query parameters #1385, #1868 [chris finne/Andrew White]
|
||||||
|
|
||||||
* Added localized rescue template when I18n.locale is set (ex: public/404.da.html) #1835 [José Valim]
|
* Added localized rescue template when I18n.locale is set (ex: public/404.da.html) #1835 [José Valim]
|
||||||
|
|
||||||
|
|
||||||
*2.3.0 [RC1] (February 1st, 2009)*
|
|
||||||
|
|
||||||
* Make the form_for and fields_for helpers support the new Active Record nested update options. #1202 [Eloy Duran]
|
* Make the form_for and fields_for helpers support the new Active Record nested update options. #1202 [Eloy Duran]
|
||||||
|
|
||||||
<% form_for @person do |person_form| %>
|
<% form_for @person do |person_form| %>
|
||||||
|
|
3
vendor/rails/actionpack/Rakefile
vendored
3
vendor/rails/actionpack/Rakefile
vendored
|
@ -80,8 +80,7 @@ spec = Gem::Specification.new do |s|
|
||||||
s.has_rdoc = true
|
s.has_rdoc = true
|
||||||
s.requirements << 'none'
|
s.requirements << 'none'
|
||||||
|
|
||||||
s.add_dependency('activesupport', '= 2.3.1' + PKG_BUILD)
|
s.add_dependency('activesupport', '= 2.3.2' + PKG_BUILD)
|
||||||
s.add_dependency('rack', '>= 0.9.0')
|
|
||||||
|
|
||||||
s.require_path = 'lib'
|
s.require_path = 'lib'
|
||||||
s.autorequire = 'action_controller'
|
s.autorequire = 'action_controller'
|
||||||
|
|
|
@ -31,7 +31,12 @@ rescue LoadError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'action_controller/vendor/rack-1.0/rack'
|
begin
|
||||||
|
gem 'rack', '~> 1.0.0'
|
||||||
|
require 'rack'
|
||||||
|
rescue Gem::LoadError
|
||||||
|
require 'action_controller/vendor/rack-1.0/rack'
|
||||||
|
end
|
||||||
|
|
||||||
module ActionController
|
module ActionController
|
||||||
# TODO: Review explicit to see if they will automatically be handled by
|
# TODO: Review explicit to see if they will automatically be handled by
|
||||||
|
|
|
@ -907,13 +907,15 @@ module ActionController #:nodoc:
|
||||||
extra_options[:template] = options
|
extra_options[:template] = options
|
||||||
end
|
end
|
||||||
|
|
||||||
|
options = extra_options
|
||||||
|
elsif !options.is_a?(Hash)
|
||||||
|
extra_options[:partial] = options
|
||||||
options = extra_options
|
options = extra_options
|
||||||
end
|
end
|
||||||
|
|
||||||
layout = pick_layout(options)
|
layout = pick_layout(options)
|
||||||
response.layout = layout.path_without_format_and_extension if layout
|
response.layout = layout.path_without_format_and_extension if layout
|
||||||
logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger && layout
|
logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger && layout
|
||||||
layout = layout.path_without_format_and_extension if layout
|
|
||||||
|
|
||||||
if content_type = options[:content_type]
|
if content_type = options[:content_type]
|
||||||
response.content_type = content_type.to_s
|
response.content_type = content_type.to_s
|
||||||
|
@ -1206,10 +1208,12 @@ module ActionController #:nodoc:
|
||||||
cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip }
|
cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip }
|
||||||
|
|
||||||
cache_control << "max-age=#{seconds}"
|
cache_control << "max-age=#{seconds}"
|
||||||
|
cache_control.delete("no-cache")
|
||||||
if options[:public]
|
if options[:public]
|
||||||
cache_control.delete("private")
|
cache_control.delete("private")
|
||||||
cache_control.delete("no-cache")
|
|
||||||
cache_control << "public"
|
cache_control << "public"
|
||||||
|
else
|
||||||
|
cache_control << "private"
|
||||||
end
|
end
|
||||||
|
|
||||||
# This allows for additional headers to be passed through like 'max-stale' => 5.hours
|
# This allows for additional headers to be passed through like 'max-stale' => 5.hours
|
||||||
|
|
|
@ -129,24 +129,23 @@ module ActionController #:nodoc:
|
||||||
attr_reader :path, :extension
|
attr_reader :path, :extension
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def path_for(controller, options, infer_extension=true)
|
def path_for(controller, options, infer_extension = true)
|
||||||
new(controller, options, infer_extension).path
|
new(controller, options, infer_extension).path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# When true, infer_extension will look up the cache path extension from the request's path & format.
|
# When true, infer_extension will look up the cache path extension from the request's path & format.
|
||||||
# This is desirable when reading and writing the cache, but not when expiring the cache - expire_action should expire the same files regardless of the request format.
|
# This is desirable when reading and writing the cache, but not when expiring the cache -
|
||||||
def initialize(controller, options = {}, infer_extension=true)
|
# expire_action should expire the same files regardless of the request format.
|
||||||
if infer_extension and options.is_a? Hash
|
def initialize(controller, options = {}, infer_extension = true)
|
||||||
request_extension = extract_extension(controller.request)
|
if infer_extension
|
||||||
options = options.reverse_merge(:format => request_extension)
|
extract_extension(controller.request)
|
||||||
|
options = options.reverse_merge(:format => @extension) if options.is_a?(Hash)
|
||||||
end
|
end
|
||||||
|
|
||||||
path = controller.url_for(options).split('://').last
|
path = controller.url_for(options).split('://').last
|
||||||
normalize!(path)
|
normalize!(path)
|
||||||
if infer_extension
|
add_extension!(path, @extension)
|
||||||
@extension = request_extension
|
|
||||||
add_extension!(path, @extension)
|
|
||||||
end
|
|
||||||
@path = URI.unescape(path)
|
@path = URI.unescape(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -162,13 +161,7 @@ module ActionController #:nodoc:
|
||||||
def extract_extension(request)
|
def extract_extension(request)
|
||||||
# Don't want just what comes after the last '.' to accommodate multi part extensions
|
# Don't want just what comes after the last '.' to accommodate multi part extensions
|
||||||
# such as tar.gz.
|
# such as tar.gz.
|
||||||
extension = request.path[/^[^.]+\.(.+)$/, 1]
|
@extension = request.path[/^[^.]+\.(.+)$/, 1] || request.cache_format
|
||||||
|
|
||||||
# If there's no extension in the path, check request.format
|
|
||||||
if extension.nil?
|
|
||||||
extension = request.cache_format
|
|
||||||
end
|
|
||||||
extension
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -68,8 +68,11 @@ module ActionController
|
||||||
#
|
#
|
||||||
# Simple Digest example:
|
# Simple Digest example:
|
||||||
#
|
#
|
||||||
|
# require 'digest/md5'
|
||||||
# class PostsController < ApplicationController
|
# class PostsController < ApplicationController
|
||||||
# USERS = {"dhh" => "secret"}
|
# REALM = "SuperSecret"
|
||||||
|
# USERS = {"dhh" => "secret", #plain text password
|
||||||
|
# "dap" => Digest:MD5::hexdigest(["dap",REALM,"secret"].join(":")) #ha1 digest password
|
||||||
#
|
#
|
||||||
# before_filter :authenticate, :except => [:index]
|
# before_filter :authenticate, :except => [:index]
|
||||||
#
|
#
|
||||||
|
@ -83,14 +86,18 @@ module ActionController
|
||||||
#
|
#
|
||||||
# private
|
# private
|
||||||
# def authenticate
|
# def authenticate
|
||||||
# authenticate_or_request_with_http_digest(realm) do |username|
|
# authenticate_or_request_with_http_digest(REALM) do |username|
|
||||||
# USERS[username]
|
# USERS[username]
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# NOTE: The +authenticate_or_request_with_http_digest+ block must return the user's password so the framework can appropriately
|
# NOTE: The +authenticate_or_request_with_http_digest+ block must return the user's password or the ha1 digest hash so the framework can appropriately
|
||||||
# hash it to check the user's credentials. Returning +nil+ will cause authentication to fail.
|
# hash to check the user's credentials. Returning +nil+ will cause authentication to fail.
|
||||||
|
# Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
|
||||||
|
# the password file or database is compromised, the attacker would be able to use the ha1 hash to
|
||||||
|
# authenticate as the user at this +realm+, but would not have the user's password to try using at
|
||||||
|
# other sites.
|
||||||
#
|
#
|
||||||
# On shared hosts, Apache sometimes doesn't pass authentication headers to
|
# On shared hosts, Apache sometimes doesn't pass authentication headers to
|
||||||
# FCGI instances. If your environment matches this description and you cannot
|
# FCGI instances. If your environment matches this description and you cannot
|
||||||
|
@ -177,26 +184,37 @@ module ActionController
|
||||||
end
|
end
|
||||||
|
|
||||||
# Raises error unless the request credentials response value matches the expected value.
|
# Raises error unless the request credentials response value matches the expected value.
|
||||||
|
# First try the password as a ha1 digest password. If this fails, then try it as a plain
|
||||||
|
# text password.
|
||||||
def validate_digest_response(request, realm, &password_procedure)
|
def validate_digest_response(request, realm, &password_procedure)
|
||||||
credentials = decode_credentials_header(request)
|
credentials = decode_credentials_header(request)
|
||||||
valid_nonce = validate_nonce(request, credentials[:nonce])
|
valid_nonce = validate_nonce(request, credentials[:nonce])
|
||||||
|
|
||||||
if valid_nonce && realm == credentials[:realm] && opaque(request.session.session_id) == credentials[:opaque]
|
if valid_nonce && realm == credentials[:realm] && opaque == credentials[:opaque]
|
||||||
password = password_procedure.call(credentials[:username])
|
password = password_procedure.call(credentials[:username])
|
||||||
expected = expected_response(request.env['REQUEST_METHOD'], credentials[:uri], credentials, password)
|
|
||||||
expected == credentials[:response]
|
[true, false].any? do |password_is_ha1|
|
||||||
|
expected = expected_response(request.env['REQUEST_METHOD'], request.env['REQUEST_URI'], credentials, password, password_is_ha1)
|
||||||
|
expected == credentials[:response]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the expected response for a request of +http_method+ to +uri+ with the decoded +credentials+ and the expected +password+
|
# Returns the expected response for a request of +http_method+ to +uri+ with the decoded +credentials+ and the expected +password+
|
||||||
def expected_response(http_method, uri, credentials, password)
|
# Optional parameter +password_is_ha1+ is set to +true+ by default, since best practice is to store ha1 digest instead
|
||||||
ha1 = ::Digest::MD5.hexdigest([credentials[:username], credentials[:realm], password].join(':'))
|
# of a plain-text password.
|
||||||
|
def expected_response(http_method, uri, credentials, password, password_is_ha1=true)
|
||||||
|
ha1 = password_is_ha1 ? password : ha1(credentials, password)
|
||||||
ha2 = ::Digest::MD5.hexdigest([http_method.to_s.upcase, uri].join(':'))
|
ha2 = ::Digest::MD5.hexdigest([http_method.to_s.upcase, uri].join(':'))
|
||||||
::Digest::MD5.hexdigest([ha1, credentials[:nonce], credentials[:nc], credentials[:cnonce], credentials[:qop], ha2].join(':'))
|
::Digest::MD5.hexdigest([ha1, credentials[:nonce], credentials[:nc], credentials[:cnonce], credentials[:qop], ha2].join(':'))
|
||||||
end
|
end
|
||||||
|
|
||||||
def encode_credentials(http_method, credentials, password)
|
def ha1(credentials, password)
|
||||||
credentials[:response] = expected_response(http_method, credentials[:uri], credentials, password)
|
::Digest::MD5.hexdigest([credentials[:username], credentials[:realm], password].join(':'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def encode_credentials(http_method, credentials, password, password_is_ha1)
|
||||||
|
credentials[:response] = expected_response(http_method, credentials[:uri], credentials, password, password_is_ha1)
|
||||||
"Digest " + credentials.sort_by {|x| x[0].to_s }.inject([]) {|a, v| a << "#{v[0]}='#{v[1]}'" }.join(', ')
|
"Digest " + credentials.sort_by {|x| x[0].to_s }.inject([]) {|a, v| a << "#{v[0]}='#{v[1]}'" }.join(', ')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -213,8 +231,7 @@ module ActionController
|
||||||
end
|
end
|
||||||
|
|
||||||
def authentication_header(controller, realm)
|
def authentication_header(controller, realm)
|
||||||
session_id = controller.request.session.session_id
|
controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce}", opaque="#{opaque}")
|
||||||
controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce(session_id)}", opaque="#{opaque(session_id)}")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def authentication_request(controller, realm, message = nil)
|
def authentication_request(controller, realm, message = nil)
|
||||||
|
@ -252,23 +269,36 @@ module ActionController
|
||||||
# POST or PUT requests and a time-stamp for GET requests. For more details on the issues involved see Section 4
|
# POST or PUT requests and a time-stamp for GET requests. For more details on the issues involved see Section 4
|
||||||
# of this document.
|
# of this document.
|
||||||
#
|
#
|
||||||
# The nonce is opaque to the client.
|
# The nonce is opaque to the client. Composed of Time, and hash of Time with secret
|
||||||
def nonce(session_id, time = Time.now)
|
# key from the Rails session secret generated upon creation of project. Ensures
|
||||||
|
# the time cannot be modifed by client.
|
||||||
|
def nonce(time = Time.now)
|
||||||
t = time.to_i
|
t = time.to_i
|
||||||
hashed = [t, session_id]
|
hashed = [t, secret_key]
|
||||||
digest = ::Digest::MD5.hexdigest(hashed.join(":"))
|
digest = ::Digest::MD5.hexdigest(hashed.join(":"))
|
||||||
Base64.encode64("#{t}:#{digest}").gsub("\n", '')
|
Base64.encode64("#{t}:#{digest}").gsub("\n", '')
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_nonce(request, value)
|
# Might want a shorter timeout depending on whether the request
|
||||||
|
# is a PUT or POST, and if client is browser or web service.
|
||||||
|
# Can be much shorter if the Stale directive is implemented. This would
|
||||||
|
# allow a user to use new nonce without prompting user again for their
|
||||||
|
# username and password.
|
||||||
|
def validate_nonce(request, value, seconds_to_timeout=5*60)
|
||||||
t = Base64.decode64(value).split(":").first.to_i
|
t = Base64.decode64(value).split(":").first.to_i
|
||||||
nonce(request.session.session_id, t) == value && (t - Time.now.to_i).abs <= 10 * 60
|
nonce(t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
|
||||||
end
|
end
|
||||||
|
|
||||||
# Opaque based on digest of session_id
|
# Opaque based on random generation - but changing each request?
|
||||||
def opaque(session_id)
|
def opaque()
|
||||||
Base64.encode64(::Digest::MD5::hexdigest(session_id)).gsub("\n", '')
|
::Digest::MD5.hexdigest(secret_key)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Set in /initializers/session_store.rb, and loaded even if sessions are not in use.
|
||||||
|
def secret_key
|
||||||
|
ActionController::Base.session_options[:secret]
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ require 'active_support/test_case'
|
||||||
module ActionController
|
module ActionController
|
||||||
module Integration #:nodoc:
|
module Integration #:nodoc:
|
||||||
# An integration Session instance represents a set of requests and responses
|
# An integration Session instance represents a set of requests and responses
|
||||||
# performed sequentially by some virtual user. Becase you can instantiate
|
# performed sequentially by some virtual user. Because you can instantiate
|
||||||
# multiple sessions and run them side-by-side, you can also mimic (to some
|
# multiple sessions and run them side-by-side, you can also mimic (to some
|
||||||
# limited extent) multiple simultaneous users interacting with your system.
|
# limited extent) multiple simultaneous users interacting with your system.
|
||||||
#
|
#
|
||||||
|
|
|
@ -198,7 +198,7 @@ module ActionController #:nodoc:
|
||||||
# is called and the return value is used. Likewise if the layout was specified as an inline method (through a proc or method
|
# is called and the return value is used. Likewise if the layout was specified as an inline method (through a proc or method
|
||||||
# object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return
|
# object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return
|
||||||
# weblog/standard, but <tt>layout "standard"</tt> will return layouts/standard.
|
# weblog/standard, but <tt>layout "standard"</tt> will return layouts/standard.
|
||||||
def active_layout(passed_layout = nil)
|
def active_layout(passed_layout = nil, options = {})
|
||||||
layout = passed_layout || default_layout
|
layout = passed_layout || default_layout
|
||||||
return layout if layout.respond_to?(:render)
|
return layout if layout.respond_to?(:render)
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ module ActionController #:nodoc:
|
||||||
else layout
|
else layout
|
||||||
end
|
end
|
||||||
|
|
||||||
find_layout(active_layout, default_template_format) if active_layout
|
find_layout(active_layout, default_template_format, options[:html_fallback]) if active_layout
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -220,8 +220,8 @@ module ActionController #:nodoc:
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_layout(layout, format) #:nodoc:
|
def find_layout(layout, format, html_fallback=false) #:nodoc:
|
||||||
view_paths.find_template(layout.to_s =~ /layouts\// ? layout : "layouts/#{layout}", format, false)
|
view_paths.find_template(layout.to_s =~ /layouts\// ? layout : "layouts/#{layout}", format, html_fallback)
|
||||||
rescue ActionView::MissingTemplate
|
rescue ActionView::MissingTemplate
|
||||||
raise if Mime::Type.lookup_by_extension(format.to_s).html?
|
raise if Mime::Type.lookup_by_extension(format.to_s).html?
|
||||||
end
|
end
|
||||||
|
@ -234,7 +234,7 @@ module ActionController #:nodoc:
|
||||||
when NilClass, TrueClass
|
when NilClass, TrueClass
|
||||||
active_layout if action_has_layout? && candidate_for_layout?(:template => default_template_name)
|
active_layout if action_has_layout? && candidate_for_layout?(:template => default_template_name)
|
||||||
else
|
else
|
||||||
active_layout(layout)
|
active_layout(layout, :html_fallback => true)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
active_layout if action_has_layout? && candidate_for_layout?(options)
|
active_layout if action_has_layout? && candidate_for_layout?(options)
|
||||||
|
|
|
@ -163,7 +163,8 @@ module ActionController
|
||||||
if parent.is_a?(Symbol) || parent.is_a?(String)
|
if parent.is_a?(Symbol) || parent.is_a?(String)
|
||||||
string << "#{parent}_"
|
string << "#{parent}_"
|
||||||
else
|
else
|
||||||
string << "#{RecordIdentifier.__send__("singular_class_name", parent)}_"
|
string << "#{RecordIdentifier.__send__("plural_class_name", parent)}".singularize
|
||||||
|
string << "_"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -171,7 +172,9 @@ module ActionController
|
||||||
if record.is_a?(Symbol) || record.is_a?(String)
|
if record.is_a?(Symbol) || record.is_a?(String)
|
||||||
route << "#{record}_"
|
route << "#{record}_"
|
||||||
else
|
else
|
||||||
route << "#{RecordIdentifier.__send__("#{inflection}_class_name", record)}_"
|
route << "#{RecordIdentifier.__send__("plural_class_name", record)}"
|
||||||
|
route = route.singularize if inflection == :singular
|
||||||
|
route << "_"
|
||||||
end
|
end
|
||||||
|
|
||||||
action_prefix(options) + namespace + route + routing_type(options).to_s
|
action_prefix(options) + namespace + route + routing_type(options).to_s
|
||||||
|
|
|
@ -442,6 +442,7 @@ EOM
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset_session
|
def reset_session
|
||||||
|
@env['rack.session.options'].delete(:id)
|
||||||
@env['rack.session'] = {}
|
@env['rack.session'] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ module ActionController
|
||||||
end
|
end
|
||||||
|
|
||||||
def shallow_path_prefix
|
def shallow_path_prefix
|
||||||
@shallow_path_prefix ||= "#{path_prefix unless @options[:shallow]}"
|
@shallow_path_prefix ||= @options[:shallow] ? @options[:namespace].try(:sub, /\/$/, '') : path_prefix
|
||||||
end
|
end
|
||||||
|
|
||||||
def member_path
|
def member_path
|
||||||
|
@ -103,7 +103,7 @@ module ActionController
|
||||||
end
|
end
|
||||||
|
|
||||||
def shallow_name_prefix
|
def shallow_name_prefix
|
||||||
@shallow_name_prefix ||= "#{name_prefix unless @options[:shallow]}"
|
@shallow_name_prefix ||= @options[:shallow] ? @options[:namespace].try(:gsub, /\//, '_') : name_prefix
|
||||||
end
|
end
|
||||||
|
|
||||||
def nesting_name_prefix
|
def nesting_name_prefix
|
||||||
|
@ -630,7 +630,7 @@ module ActionController
|
||||||
action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
|
action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
|
||||||
action_path ||= Base.resources_path_names[action] || action
|
action_path ||= Base.resources_path_names[action] || action
|
||||||
|
|
||||||
map_resource_routes(map, resource, action, "#{resource.member_path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", m)
|
map_resource_routes(map, resource, action, "#{resource.member_path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", m, { :force_id => true })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -641,9 +641,9 @@ module ActionController
|
||||||
map_resource_routes(map, resource, :destroy, resource.member_path, route_path)
|
map_resource_routes(map, resource, :destroy, resource.member_path, route_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def map_resource_routes(map, resource, action, route_path, route_name = nil, method = nil)
|
def map_resource_routes(map, resource, action, route_path, route_name = nil, method = nil, resource_options = {} )
|
||||||
if resource.has_action?(action)
|
if resource.has_action?(action)
|
||||||
action_options = action_options_for(action, resource, method)
|
action_options = action_options_for(action, resource, method, resource_options)
|
||||||
formatted_route_path = "#{route_path}.:format"
|
formatted_route_path = "#{route_path}.:format"
|
||||||
|
|
||||||
if route_name && @set.named_routes[route_name.to_sym].nil?
|
if route_name && @set.named_routes[route_name.to_sym].nil?
|
||||||
|
@ -660,9 +660,10 @@ module ActionController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def action_options_for(action, resource, method = nil)
|
def action_options_for(action, resource, method = nil, resource_options = {})
|
||||||
default_options = { :action => action.to_s }
|
default_options = { :action => action.to_s }
|
||||||
require_id = !resource.kind_of?(SingletonResource)
|
require_id = !resource.kind_of?(SingletonResource)
|
||||||
|
force_id = resource_options[:force_id] && !resource.kind_of?(SingletonResource)
|
||||||
|
|
||||||
case default_options[:action]
|
case default_options[:action]
|
||||||
when "index", "new"; default_options.merge(add_conditions_for(resource.conditions, method || :get)).merge(resource.requirements)
|
when "index", "new"; default_options.merge(add_conditions_for(resource.conditions, method || :get)).merge(resource.requirements)
|
||||||
|
@ -670,7 +671,7 @@ module ActionController
|
||||||
when "show", "edit"; default_options.merge(add_conditions_for(resource.conditions, method || :get)).merge(resource.requirements(require_id))
|
when "show", "edit"; default_options.merge(add_conditions_for(resource.conditions, method || :get)).merge(resource.requirements(require_id))
|
||||||
when "update"; default_options.merge(add_conditions_for(resource.conditions, method || :put)).merge(resource.requirements(require_id))
|
when "update"; default_options.merge(add_conditions_for(resource.conditions, method || :put)).merge(resource.requirements(require_id))
|
||||||
when "destroy"; default_options.merge(add_conditions_for(resource.conditions, method || :delete)).merge(resource.requirements(require_id))
|
when "destroy"; default_options.merge(add_conditions_for(resource.conditions, method || :delete)).merge(resource.requirements(require_id))
|
||||||
else default_options.merge(add_conditions_for(resource.conditions, method)).merge(resource.requirements)
|
else default_options.merge(add_conditions_for(resource.conditions, method)).merge(resource.requirements(force_id))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -267,7 +267,7 @@ module ActionController
|
||||||
module Routing
|
module Routing
|
||||||
SEPARATORS = %w( / . ? )
|
SEPARATORS = %w( / . ? )
|
||||||
|
|
||||||
HTTP_METHODS = [:get, :head, :post, :put, :delete]
|
HTTP_METHODS = [:get, :head, :post, :put, :delete, :options]
|
||||||
|
|
||||||
ALLOWED_REQUIREMENTS_FOR_OPTIMISATION = [:controller, :action].to_set
|
ALLOWED_REQUIREMENTS_FOR_OPTIMISATION = [:controller, :action].to_set
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,8 @@ module ActionController
|
||||||
path = "/#{path}" unless path[0] == ?/
|
path = "/#{path}" unless path[0] == ?/
|
||||||
path = "#{path}/" unless path[-1] == ?/
|
path = "#{path}/" unless path[-1] == ?/
|
||||||
|
|
||||||
path = "/#{options[:path_prefix].to_s.gsub(/^\//,'')}#{path}" if options[:path_prefix]
|
prefix = options[:path_prefix].to_s.gsub(/^\//,'')
|
||||||
|
path = "/#{prefix}#{path}" unless prefix.blank?
|
||||||
|
|
||||||
segments = segments_for_route_path(path)
|
segments = segments_for_route_path(path)
|
||||||
defaults, requirements, conditions = divide_route_options(segments, options)
|
defaults, requirements, conditions = divide_route_options(segments, options)
|
||||||
|
|
|
@ -98,7 +98,6 @@ module ActionController
|
||||||
if Array === item
|
if Array === item
|
||||||
i += 1
|
i += 1
|
||||||
start = (i == 1)
|
start = (i == 1)
|
||||||
final = (i == list.size)
|
|
||||||
tag, sub = item
|
tag, sub = item
|
||||||
if tag == :dynamic
|
if tag == :dynamic
|
||||||
body += padding + "#{start ? 'if' : 'elsif'} true\n"
|
body += padding + "#{start ? 'if' : 'elsif'} true\n"
|
||||||
|
|
|
@ -556,7 +556,7 @@ module HTML
|
||||||
end
|
end
|
||||||
|
|
||||||
# Attribute value.
|
# Attribute value.
|
||||||
next if statement.sub!(/^\[\s*([[:alpha:]][\w\-]*)\s*((?:[~|^$*])?=)?\s*('[^']*'|"[^*]"|[^\]]*)\s*\]/) do |match|
|
next if statement.sub!(/^\[\s*([[:alpha:]][\w\-:]*)\s*((?:[~|^$*])?=)?\s*('[^']*'|"[^*]"|[^\]]*)\s*\]/) do |match|
|
||||||
name, equality, value = $1, $2, $3
|
name, equality, value = $1, $2, $3
|
||||||
if value == "?"
|
if value == "?"
|
||||||
value = values.shift
|
value = values.shift
|
||||||
|
|
|
@ -23,14 +23,16 @@ module Rack
|
||||||
|
|
||||||
# Return the Rack release as a dotted string.
|
# Return the Rack release as a dotted string.
|
||||||
def self.release
|
def self.release
|
||||||
"0.4"
|
"1.0 bundled"
|
||||||
end
|
end
|
||||||
|
|
||||||
autoload :Builder, "rack/builder"
|
autoload :Builder, "rack/builder"
|
||||||
autoload :Cascade, "rack/cascade"
|
autoload :Cascade, "rack/cascade"
|
||||||
|
autoload :Chunked, "rack/chunked"
|
||||||
autoload :CommonLogger, "rack/commonlogger"
|
autoload :CommonLogger, "rack/commonlogger"
|
||||||
autoload :ConditionalGet, "rack/conditionalget"
|
autoload :ConditionalGet, "rack/conditionalget"
|
||||||
autoload :ContentLength, "rack/content_length"
|
autoload :ContentLength, "rack/content_length"
|
||||||
|
autoload :ContentType, "rack/content_type"
|
||||||
autoload :File, "rack/file"
|
autoload :File, "rack/file"
|
||||||
autoload :Deflater, "rack/deflater"
|
autoload :Deflater, "rack/deflater"
|
||||||
autoload :Directory, "rack/directory"
|
autoload :Directory, "rack/directory"
|
||||||
|
|
|
@ -8,8 +8,8 @@ module Rack
|
||||||
|
|
||||||
attr_accessor :realm
|
attr_accessor :realm
|
||||||
|
|
||||||
def initialize(app, &authenticator)
|
def initialize(app, realm=nil, &authenticator)
|
||||||
@app, @authenticator = app, authenticator
|
@app, @realm, @authenticator = app, realm, authenticator
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ module Rack
|
||||||
|
|
||||||
attr_writer :passwords_hashed
|
attr_writer :passwords_hashed
|
||||||
|
|
||||||
def initialize(app)
|
def initialize(*args)
|
||||||
super
|
super
|
||||||
@passwords_hashed = nil
|
@passwords_hashed = nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,7 +8,7 @@ module Rack
|
||||||
class Request < Auth::AbstractRequest
|
class Request < Auth::AbstractRequest
|
||||||
|
|
||||||
def method
|
def method
|
||||||
@env['REQUEST_METHOD']
|
@env['rack.methodoverride.original_method'] || @env['REQUEST_METHOD']
|
||||||
end
|
end
|
||||||
|
|
||||||
def digest?
|
def digest?
|
||||||
|
|
|
@ -34,11 +34,7 @@ module Rack
|
||||||
end
|
end
|
||||||
|
|
||||||
def use(middleware, *args, &block)
|
def use(middleware, *args, &block)
|
||||||
@ins << if block_given?
|
@ins << lambda { |app| middleware.new(app, *args, &block) }
|
||||||
lambda { |app| middleware.new(app, *args, &block) }
|
|
||||||
else
|
|
||||||
lambda { |app| middleware.new(app, *args) }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def run(app)
|
def run(app)
|
||||||
|
|
49
vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/chunked.rb
vendored
Normal file
49
vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/chunked.rb
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
require 'rack/utils'
|
||||||
|
|
||||||
|
module Rack
|
||||||
|
|
||||||
|
# Middleware that applies chunked transfer encoding to response bodies
|
||||||
|
# when the response does not include a Content-Length header.
|
||||||
|
class Chunked
|
||||||
|
include Rack::Utils
|
||||||
|
|
||||||
|
def initialize(app)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
status, headers, body = @app.call(env)
|
||||||
|
headers = HeaderHash.new(headers)
|
||||||
|
|
||||||
|
if env['HTTP_VERSION'] == 'HTTP/1.0' ||
|
||||||
|
STATUS_WITH_NO_ENTITY_BODY.include?(status) ||
|
||||||
|
headers['Content-Length'] ||
|
||||||
|
headers['Transfer-Encoding']
|
||||||
|
[status, headers.to_hash, body]
|
||||||
|
else
|
||||||
|
dup.chunk(status, headers, body)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def chunk(status, headers, body)
|
||||||
|
@body = body
|
||||||
|
headers.delete('Content-Length')
|
||||||
|
headers['Transfer-Encoding'] = 'chunked'
|
||||||
|
[status, headers.to_hash, self]
|
||||||
|
end
|
||||||
|
|
||||||
|
def each
|
||||||
|
term = "\r\n"
|
||||||
|
@body.each do |chunk|
|
||||||
|
size = bytesize(chunk)
|
||||||
|
next if size == 0
|
||||||
|
yield [size.to_s(16), term, chunk, term].join
|
||||||
|
end
|
||||||
|
yield ["0", term, "", term].join
|
||||||
|
end
|
||||||
|
|
||||||
|
def close
|
||||||
|
@body.close if @body.respond_to?(:close)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,21 +3,23 @@ require 'rack/utils'
|
||||||
module Rack
|
module Rack
|
||||||
# Sets the Content-Length header on responses with fixed-length bodies.
|
# Sets the Content-Length header on responses with fixed-length bodies.
|
||||||
class ContentLength
|
class ContentLength
|
||||||
|
include Rack::Utils
|
||||||
|
|
||||||
def initialize(app)
|
def initialize(app)
|
||||||
@app = app
|
@app = app
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
status, headers, body = @app.call(env)
|
status, headers, body = @app.call(env)
|
||||||
headers = Utils::HeaderHash.new(headers)
|
headers = HeaderHash.new(headers)
|
||||||
|
|
||||||
if !Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) &&
|
if !STATUS_WITH_NO_ENTITY_BODY.include?(status) &&
|
||||||
!headers['Content-Length'] &&
|
!headers['Content-Length'] &&
|
||||||
!headers['Transfer-Encoding'] &&
|
!headers['Transfer-Encoding'] &&
|
||||||
(body.respond_to?(:to_ary) || body.respond_to?(:to_str))
|
(body.respond_to?(:to_ary) || body.respond_to?(:to_str))
|
||||||
|
|
||||||
body = [body] if body.respond_to?(:to_str) # rack 0.4 compat
|
body = [body] if body.respond_to?(:to_str) # rack 0.4 compat
|
||||||
length = body.to_ary.inject(0) { |len, part| len + part.length }
|
length = body.to_ary.inject(0) { |len, part| len + bytesize(part) }
|
||||||
headers['Content-Length'] = length.to_s
|
headers['Content-Length'] = length.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
23
vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/content_type.rb
vendored
Normal file
23
vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/content_type.rb
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
require 'rack/utils'
|
||||||
|
|
||||||
|
module Rack
|
||||||
|
|
||||||
|
# Sets the Content-Type header on responses which don't have one.
|
||||||
|
#
|
||||||
|
# Builder Usage:
|
||||||
|
# use Rack::ContentType, "text/plain"
|
||||||
|
#
|
||||||
|
# When no content type argument is provided, "text/html" is assumed.
|
||||||
|
class ContentType
|
||||||
|
def initialize(app, content_type = "text/html")
|
||||||
|
@app, @content_type = app, content_type
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
status, headers, body = @app.call(env)
|
||||||
|
headers = Utils::HeaderHash.new(headers)
|
||||||
|
headers['Content-Type'] ||= @content_type
|
||||||
|
[status, headers.to_hash, body]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -36,12 +36,12 @@ module Rack
|
||||||
mtime = headers.key?("Last-Modified") ?
|
mtime = headers.key?("Last-Modified") ?
|
||||||
Time.httpdate(headers["Last-Modified"]) : Time.now
|
Time.httpdate(headers["Last-Modified"]) : Time.now
|
||||||
body = self.class.gzip(body, mtime)
|
body = self.class.gzip(body, mtime)
|
||||||
size = body.respond_to?(:bytesize) ? body.bytesize : body.size
|
size = Rack::Utils.bytesize(body)
|
||||||
headers = headers.merge("Content-Encoding" => "gzip", "Content-Length" => size.to_s)
|
headers = headers.merge("Content-Encoding" => "gzip", "Content-Length" => size.to_s)
|
||||||
[status, headers, [body]]
|
[status, headers, [body]]
|
||||||
when "deflate"
|
when "deflate"
|
||||||
body = self.class.deflate(body)
|
body = self.class.deflate(body)
|
||||||
size = body.respond_to?(:bytesize) ? body.bytesize : body.size
|
size = Rack::Utils.bytesize(body)
|
||||||
headers = headers.merge("Content-Encoding" => "deflate", "Content-Length" => size.to_s)
|
headers = headers.merge("Content-Encoding" => "deflate", "Content-Length" => size.to_s)
|
||||||
[status, headers, [body]]
|
[status, headers, [body]]
|
||||||
when "identity"
|
when "identity"
|
||||||
|
|
|
@ -70,7 +70,7 @@ table { width:100%%; }
|
||||||
return unless @path_info.include? ".."
|
return unless @path_info.include? ".."
|
||||||
|
|
||||||
body = "Forbidden\n"
|
body = "Forbidden\n"
|
||||||
size = body.respond_to?(:bytesize) ? body.bytesize : body.size
|
size = Rack::Utils.bytesize(body)
|
||||||
return [403, {"Content-Type" => "text/plain","Content-Length" => size.to_s}, [body]]
|
return [403, {"Content-Type" => "text/plain","Content-Length" => size.to_s}, [body]]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -89,6 +89,8 @@ table { width:100%%; }
|
||||||
type = stat.directory? ? 'directory' : Mime.mime_type(ext)
|
type = stat.directory? ? 'directory' : Mime.mime_type(ext)
|
||||||
size = stat.directory? ? '-' : filesize_format(size)
|
size = stat.directory? ? '-' : filesize_format(size)
|
||||||
mtime = stat.mtime.httpdate
|
mtime = stat.mtime.httpdate
|
||||||
|
url << '/' if stat.directory?
|
||||||
|
basename << '/' if stat.directory?
|
||||||
|
|
||||||
@files << [ url, basename, size, type, mtime ]
|
@files << [ url, basename, size, type, mtime ]
|
||||||
end
|
end
|
||||||
|
@ -120,7 +122,7 @@ table { width:100%%; }
|
||||||
|
|
||||||
def entity_not_found
|
def entity_not_found
|
||||||
body = "Entity not found: #{@path_info}\n"
|
body = "Entity not found: #{@path_info}\n"
|
||||||
size = body.respond_to?(:bytesize) ? body.bytesize : body.size
|
size = Rack::Utils.bytesize(body)
|
||||||
return [404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]]
|
return [404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ module Rack
|
||||||
body = self
|
body = self
|
||||||
else
|
else
|
||||||
body = [F.read(@path)]
|
body = [F.read(@path)]
|
||||||
size = body.first.size
|
size = Utils.bytesize(body.first)
|
||||||
end
|
end
|
||||||
|
|
||||||
[200, {
|
[200, {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
require 'rack/content_length'
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
module Handler
|
module Handler
|
||||||
class CGI
|
class CGI
|
||||||
|
@ -6,6 +8,8 @@ module Rack
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.serve(app)
|
def self.serve(app)
|
||||||
|
app = ContentLength.new(app)
|
||||||
|
|
||||||
env = ENV.to_hash
|
env = ENV.to_hash
|
||||||
env.delete "HTTP_CONTENT_LENGTH"
|
env.delete "HTTP_CONTENT_LENGTH"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
require 'fcgi'
|
require 'fcgi'
|
||||||
require 'socket'
|
require 'socket'
|
||||||
|
require 'rack/content_length'
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
module Handler
|
module Handler
|
||||||
|
@ -29,6 +30,8 @@ module Rack
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.serve(request, app)
|
def self.serve(request, app)
|
||||||
|
app = Rack::ContentLength.new(app)
|
||||||
|
|
||||||
env = request.env
|
env = request.env
|
||||||
env.delete "HTTP_CONTENT_LENGTH"
|
env.delete "HTTP_CONTENT_LENGTH"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
require 'lsapi'
|
require 'lsapi'
|
||||||
#require 'cgi'
|
require 'rack/content_length'
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
module Handler
|
module Handler
|
||||||
class LSWS
|
class LSWS
|
||||||
|
@ -9,11 +10,13 @@ module Rack
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
def self.serve(app)
|
def self.serve(app)
|
||||||
|
app = Rack::ContentLength.new(app)
|
||||||
|
|
||||||
env = ENV.to_hash
|
env = ENV.to_hash
|
||||||
env.delete "HTTP_CONTENT_LENGTH"
|
env.delete "HTTP_CONTENT_LENGTH"
|
||||||
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
|
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
|
||||||
env.update({"rack.version" => [0,1],
|
env.update({"rack.version" => [0,1],
|
||||||
"rack.input" => $stdin,
|
"rack.input" => StringIO.new($stdin.read.to_s),
|
||||||
"rack.errors" => $stderr,
|
"rack.errors" => $stderr,
|
||||||
"rack.multithread" => false,
|
"rack.multithread" => false,
|
||||||
"rack.multiprocess" => true,
|
"rack.multiprocess" => true,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
require 'mongrel'
|
require 'mongrel'
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
|
require 'rack/content_length'
|
||||||
|
require 'rack/chunked'
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
module Handler
|
module Handler
|
||||||
|
@ -33,7 +35,7 @@ module Rack
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(app)
|
def initialize(app)
|
||||||
@app = app
|
@app = Rack::Chunked.new(Rack::ContentLength.new(app))
|
||||||
end
|
end
|
||||||
|
|
||||||
def process(request, response)
|
def process(request, response)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
require 'scgi'
|
require 'scgi'
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
|
require 'rack/content_length'
|
||||||
|
require 'rack/chunked'
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
module Handler
|
module Handler
|
||||||
|
@ -14,7 +16,7 @@ module Rack
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(settings = {})
|
def initialize(settings = {})
|
||||||
@app = settings[:app]
|
@app = Rack::Chunked.new(Rack::ContentLength.new(settings[:app]))
|
||||||
@log = Object.new
|
@log = Object.new
|
||||||
def @log.info(*args); end
|
def @log.info(*args); end
|
||||||
def @log.error(*args); end
|
def @log.error(*args); end
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
require "thin"
|
require "thin"
|
||||||
|
require "rack/content_length"
|
||||||
|
require "rack/chunked"
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
module Handler
|
module Handler
|
||||||
class Thin
|
class Thin
|
||||||
def self.run(app, options={})
|
def self.run(app, options={})
|
||||||
|
app = Rack::Chunked.new(Rack::ContentLength.new(app))
|
||||||
server = ::Thin::Server.new(options[:Host] || '0.0.0.0',
|
server = ::Thin::Server.new(options[:Host] || '0.0.0.0',
|
||||||
options[:Port] || 8080,
|
options[:Port] || 8080,
|
||||||
app)
|
app)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
require 'webrick'
|
require 'webrick'
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
|
require 'rack/content_length'
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
module Handler
|
module Handler
|
||||||
|
@ -14,7 +15,7 @@ module Rack
|
||||||
|
|
||||||
def initialize(server, app)
|
def initialize(server, app)
|
||||||
super server
|
super server
|
||||||
@app = app
|
@app = Rack::ContentLength.new(app)
|
||||||
end
|
end
|
||||||
|
|
||||||
def service(req, res)
|
def service(req, res)
|
||||||
|
@ -35,7 +36,12 @@ module Rack
|
||||||
env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
|
env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
|
||||||
env["QUERY_STRING"] ||= ""
|
env["QUERY_STRING"] ||= ""
|
||||||
env["REQUEST_PATH"] ||= "/"
|
env["REQUEST_PATH"] ||= "/"
|
||||||
env.delete "PATH_INFO" if env["PATH_INFO"] == ""
|
if env["PATH_INFO"] == ""
|
||||||
|
env.delete "PATH_INFO"
|
||||||
|
else
|
||||||
|
path, n = req.request_uri.path, env["SCRIPT_NAME"].length
|
||||||
|
env["PATH_INFO"] = path[n, path.length-n]
|
||||||
|
end
|
||||||
|
|
||||||
status, headers, body = @app.call(env)
|
status, headers, body = @app.call(env)
|
||||||
begin
|
begin
|
||||||
|
|
|
@ -88,7 +88,9 @@ module Rack
|
||||||
## within the application. This may be an
|
## within the application. This may be an
|
||||||
## empty string, if the request URL targets
|
## empty string, if the request URL targets
|
||||||
## the application root and does not have a
|
## the application root and does not have a
|
||||||
## trailing slash.
|
## trailing slash. This information should be
|
||||||
|
## decoded by the server if it comes from a
|
||||||
|
## URL.
|
||||||
|
|
||||||
## <tt>QUERY_STRING</tt>:: The portion of the request URL that
|
## <tt>QUERY_STRING</tt>:: The portion of the request URL that
|
||||||
## follows the <tt>?</tt>, if any. May be
|
## follows the <tt>?</tt>, if any. May be
|
||||||
|
@ -372,59 +374,43 @@ module Rack
|
||||||
|
|
||||||
## === The Content-Length
|
## === The Content-Length
|
||||||
def check_content_length(status, headers, env)
|
def check_content_length(status, headers, env)
|
||||||
chunked_response = false
|
|
||||||
headers.each { |key, value|
|
|
||||||
if key.downcase == 'transfer-encoding'
|
|
||||||
chunked_response = value.downcase != 'identity'
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
headers.each { |key, value|
|
headers.each { |key, value|
|
||||||
if key.downcase == 'content-length'
|
if key.downcase == 'content-length'
|
||||||
## There must be a <tt>Content-Length</tt>, except when the
|
## There must not be a <tt>Content-Length</tt> header when the
|
||||||
## +Status+ is 1xx, 204 or 304, in which case there must be none
|
## +Status+ is 1xx, 204 or 304.
|
||||||
## given.
|
|
||||||
assert("Content-Length header found in #{status} response, not allowed") {
|
assert("Content-Length header found in #{status} response, not allowed") {
|
||||||
not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
|
not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
|
||||||
}
|
}
|
||||||
|
|
||||||
assert('Content-Length header should not be used if body is chunked') {
|
|
||||||
not chunked_response
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes = 0
|
bytes = 0
|
||||||
string_body = true
|
string_body = true
|
||||||
|
|
||||||
@body.each { |part|
|
if @body.respond_to?(:to_ary)
|
||||||
unless part.kind_of?(String)
|
@body.each { |part|
|
||||||
string_body = false
|
unless part.kind_of?(String)
|
||||||
break
|
string_body = false
|
||||||
end
|
break
|
||||||
|
end
|
||||||
|
|
||||||
bytes += (part.respond_to?(:bytesize) ? part.bytesize : part.size)
|
bytes += Rack::Utils.bytesize(part)
|
||||||
}
|
|
||||||
|
|
||||||
if env["REQUEST_METHOD"] == "HEAD"
|
|
||||||
assert("Response body was given for HEAD request, but should be empty") {
|
|
||||||
bytes == 0
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
if string_body
|
if env["REQUEST_METHOD"] == "HEAD"
|
||||||
assert("Content-Length header was #{value}, but should be #{bytes}") {
|
assert("Response body was given for HEAD request, but should be empty") {
|
||||||
value == bytes.to_s
|
bytes == 0
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
if string_body
|
||||||
|
assert("Content-Length header was #{value}, but should be #{bytes}") {
|
||||||
|
value == bytes.to_s
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ String, Array ].include?(@body.class) && !chunked_response
|
|
||||||
assert('No Content-Length header found') {
|
|
||||||
Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
## === The Body
|
## === The Body
|
||||||
|
|
|
@ -16,6 +16,8 @@ module Rack
|
||||||
# Your application's +call+ should end returning Response#finish.
|
# Your application's +call+ should end returning Response#finish.
|
||||||
|
|
||||||
class Response
|
class Response
|
||||||
|
attr_accessor :length
|
||||||
|
|
||||||
def initialize(body=[], status=200, header={}, &block)
|
def initialize(body=[], status=200, header={}, &block)
|
||||||
@status = status
|
@status = status
|
||||||
@header = Utils::HeaderHash.new({"Content-Type" => "text/html"}.
|
@header = Utils::HeaderHash.new({"Content-Type" => "text/html"}.
|
||||||
|
|
|
@ -27,7 +27,7 @@ module Rack
|
||||||
message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s
|
message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s
|
||||||
detail = env["rack.showstatus.detail"] || message
|
detail = env["rack.showstatus.detail"] || message
|
||||||
body = @template.result(binding)
|
body = @template.result(binding)
|
||||||
size = body.respond_to?(:bytesize) ? body.bytesize : body.size
|
size = Rack::Utils.bytesize(body)
|
||||||
[status, headers.merge("Content-Type" => "text/html", "Content-Length" => size.to_s), [body]]
|
[status, headers.merge("Content-Type" => "text/html", "Content-Length" => size.to_s), [body]]
|
||||||
else
|
else
|
||||||
[status, headers, body]
|
[status, headers, body]
|
||||||
|
|
|
@ -12,7 +12,11 @@ module Rack
|
||||||
# first, since they are most specific.
|
# first, since they are most specific.
|
||||||
|
|
||||||
class URLMap
|
class URLMap
|
||||||
def initialize(map)
|
def initialize(map = {})
|
||||||
|
remap(map)
|
||||||
|
end
|
||||||
|
|
||||||
|
def remap(map)
|
||||||
@mapping = map.map { |location, app|
|
@mapping = map.map { |location, app|
|
||||||
if location =~ %r{\Ahttps?://(.*?)(/.*)}
|
if location =~ %r{\Ahttps?://(.*?)(/.*)}
|
||||||
host, location = $1, $2
|
host, location = $1, $2
|
||||||
|
|
|
@ -144,6 +144,19 @@ module Rack
|
||||||
end
|
end
|
||||||
module_function :select_best_encoding
|
module_function :select_best_encoding
|
||||||
|
|
||||||
|
# Return the bytesize of String; uses String#length under Ruby 1.8 and
|
||||||
|
# String#bytesize under 1.9.
|
||||||
|
if ''.respond_to?(:bytesize)
|
||||||
|
def bytesize(string)
|
||||||
|
string.bytesize
|
||||||
|
end
|
||||||
|
else
|
||||||
|
def bytesize(string)
|
||||||
|
string.size
|
||||||
|
end
|
||||||
|
end
|
||||||
|
module_function :bytesize
|
||||||
|
|
||||||
# Context allows the use of a compatible middleware at different points
|
# Context allows the use of a compatible middleware at different points
|
||||||
# in a request handling stack. A compatible middleware must define
|
# in a request handling stack. A compatible middleware must define
|
||||||
# #context which should take the arguments env and app. The first of which
|
# #context which should take the arguments env and app. The first of which
|
||||||
|
@ -359,7 +372,7 @@ module Rack
|
||||||
data = body
|
data = body
|
||||||
end
|
end
|
||||||
|
|
||||||
Utils.normalize_params(params, name, data)
|
Utils.normalize_params(params, name, data) unless data.nil?
|
||||||
|
|
||||||
break if buf.empty? || content_length == -1
|
break if buf.empty? || content_length == -1
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ module ActionPack #:nodoc:
|
||||||
module VERSION #:nodoc:
|
module VERSION #:nodoc:
|
||||||
MAJOR = 2
|
MAJOR = 2
|
||||||
MINOR = 3
|
MINOR = 3
|
||||||
TINY = 1
|
TINY = 2
|
||||||
|
|
||||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||||
end
|
end
|
||||||
|
|
18
vendor/rails/actionpack/lib/action_view/base.rb
vendored
18
vendor/rails/actionpack/lib/action_view/base.rb
vendored
|
@ -221,10 +221,12 @@ module ActionView #:nodoc:
|
||||||
def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc:
|
def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc:
|
||||||
@assigns = assigns_for_first_render
|
@assigns = assigns_for_first_render
|
||||||
@assigns_added = nil
|
@assigns_added = nil
|
||||||
@_render_stack = []
|
|
||||||
@controller = controller
|
@controller = controller
|
||||||
@helpers = ProxyModule.new(self)
|
@helpers = ProxyModule.new(self)
|
||||||
self.view_paths = view_paths
|
self.view_paths = view_paths
|
||||||
|
|
||||||
|
@_first_render = nil
|
||||||
|
@_current_render = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_reader :view_paths
|
attr_reader :view_paths
|
||||||
|
@ -286,7 +288,19 @@ module ActionView #:nodoc:
|
||||||
# Access the current template being rendered.
|
# Access the current template being rendered.
|
||||||
# Returns a ActionView::Template object.
|
# Returns a ActionView::Template object.
|
||||||
def template
|
def template
|
||||||
@_render_stack.last
|
@_current_render
|
||||||
|
end
|
||||||
|
|
||||||
|
def template=(template) #:nodoc:
|
||||||
|
@_first_render ||= template
|
||||||
|
@_current_render = template
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_template(current_template)
|
||||||
|
last_template, self.template = template, current_template
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
self.template = last_template
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -121,7 +121,7 @@ module ActionView
|
||||||
if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) &&
|
if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) &&
|
||||||
(errors = obj.errors.on(method))
|
(errors = obj.errors.on(method))
|
||||||
content_tag("div",
|
content_tag("div",
|
||||||
"#{options[:prepend_text]}#{errors.is_a?(Array) ? errors.first : errors}#{options[:append_text]}",
|
"#{options[:prepend_text]}#{ERB::Util.html_escape(errors.is_a?(Array) ? errors.first : errors)}#{options[:append_text]}",
|
||||||
:class => options[:css_class]
|
:class => options[:css_class]
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
|
@ -198,7 +198,7 @@ module ActionView
|
||||||
locale.t :header, :count => count, :model => object_name
|
locale.t :header, :count => count, :model => object_name
|
||||||
end
|
end
|
||||||
message = options.include?(:message) ? options[:message] : locale.t(:body)
|
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
|
error_messages = objects.sum {|object| object.errors.full_messages.map {|msg| content_tag(:li, ERB::Util.html_escape(msg)) } }.join
|
||||||
|
|
||||||
contents = ''
|
contents = ''
|
||||||
contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
|
contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
|
||||||
|
|
|
@ -876,8 +876,8 @@ module ActionView
|
||||||
input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
|
input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
|
||||||
end
|
end
|
||||||
|
|
||||||
# Given an ordering of datetime components, create the selection html
|
# Given an ordering of datetime components, create the selection HTML
|
||||||
# and join them with their appropriate seperators
|
# and join them with their appropriate separators.
|
||||||
def build_selects_from_types(order)
|
def build_selects_from_types(order)
|
||||||
select = ''
|
select = ''
|
||||||
order.reverse.each do |type|
|
order.reverse.each do |type|
|
||||||
|
|
|
@ -360,8 +360,8 @@ module ActionView
|
||||||
end
|
end
|
||||||
|
|
||||||
if confirm = options.delete("confirm")
|
if confirm = options.delete("confirm")
|
||||||
options["onclick"] ||= ''
|
options["onclick"] ||= 'return true;'
|
||||||
options["onclick"] << "return #{confirm_javascript_function(confirm)};"
|
options["onclick"] = "if (!#{confirm_javascript_function(confirm)}) return false; #{options['onclick']}"
|
||||||
end
|
end
|
||||||
|
|
||||||
tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys)
|
tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys)
|
||||||
|
|
|
@ -15,6 +15,7 @@ module ActionView
|
||||||
# * <tt>:country_code</tt> - Sets the country code for the phone number.
|
# * <tt>:country_code</tt> - Sets the country code for the phone number.
|
||||||
#
|
#
|
||||||
# ==== Examples
|
# ==== Examples
|
||||||
|
# number_to_phone(5551234) # => 555-1234
|
||||||
# number_to_phone(1235551234) # => 123-555-1234
|
# number_to_phone(1235551234) # => 123-555-1234
|
||||||
# number_to_phone(1235551234, :area_code => true) # => (123) 555-1234
|
# number_to_phone(1235551234, :area_code => true) # => (123) 555-1234
|
||||||
# number_to_phone(1235551234, :delimiter => " ") # => 123 555 1234
|
# number_to_phone(1235551234, :delimiter => " ") # => 123 555 1234
|
||||||
|
@ -37,7 +38,8 @@ module ActionView
|
||||||
str << if area_code
|
str << if area_code
|
||||||
number.gsub!(/([0-9]{1,3})([0-9]{3})([0-9]{4}$)/,"(\\1) \\2#{delimiter}\\3")
|
number.gsub!(/([0-9]{1,3})([0-9]{3})([0-9]{4}$)/,"(\\1) \\2#{delimiter}\\3")
|
||||||
else
|
else
|
||||||
number.gsub!(/([0-9]{1,3})([0-9]{3})([0-9]{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
|
number.gsub!(/([0-9]{0,3})([0-9]{3})([0-9]{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
|
||||||
|
number.starts_with?('-') ? number.slice!(1..-1) : number
|
||||||
end
|
end
|
||||||
str << " x #{extension}" unless extension.blank?
|
str << " x #{extension}" unless extension.blank?
|
||||||
str
|
str
|
||||||
|
@ -138,7 +140,7 @@ module ActionView
|
||||||
# number_with_delimiter(12345678) # => 12,345,678
|
# number_with_delimiter(12345678) # => 12,345,678
|
||||||
# number_with_delimiter(12345678.05) # => 12,345,678.05
|
# number_with_delimiter(12345678.05) # => 12,345,678.05
|
||||||
# number_with_delimiter(12345678, :delimiter => ".") # => 12.345.678
|
# number_with_delimiter(12345678, :delimiter => ".") # => 12.345.678
|
||||||
# number_with_delimiter(12345678, :seperator => ",") # => 12,345,678
|
# number_with_delimiter(12345678, :separator => ",") # => 12,345,678
|
||||||
# number_with_delimiter(98765432.98, :delimiter => " ", :separator => ",")
|
# number_with_delimiter(98765432.98, :delimiter => " ", :separator => ",")
|
||||||
# # => 98 765 432,98
|
# # => 98 765 432,98
|
||||||
#
|
#
|
||||||
|
|
|
@ -107,7 +107,7 @@ module ActionView
|
||||||
# on the page in an Ajax response.
|
# on the page in an Ajax response.
|
||||||
module PrototypeHelper
|
module PrototypeHelper
|
||||||
unless const_defined? :CALLBACKS
|
unless const_defined? :CALLBACKS
|
||||||
CALLBACKS = Set.new([ :uninitialized, :loading, :loaded,
|
CALLBACKS = Set.new([ :create, :uninitialized, :loading, :loaded,
|
||||||
:interactive, :complete, :failure, :success ] +
|
:interactive, :complete, :failure, :success ] +
|
||||||
(100..599).to_a)
|
(100..599).to_a)
|
||||||
AJAX_OPTIONS = Set.new([ :before, :after, :condition, :url,
|
AJAX_OPTIONS = Set.new([ :before, :after, :condition, :url,
|
||||||
|
|
|
@ -536,8 +536,9 @@ module ActionView
|
||||||
text.gsub(AUTO_LINK_RE) do
|
text.gsub(AUTO_LINK_RE) do
|
||||||
href = $&
|
href = $&
|
||||||
punctuation = ''
|
punctuation = ''
|
||||||
# detect already linked URLs
|
left, right = $`, $'
|
||||||
if $` =~ /<a\s[^>]*href="$/
|
# detect already linked URLs and URLs in the middle of a tag
|
||||||
|
if left =~ /<[^>]+$/ && right =~ /^[^>]*>/
|
||||||
# do not change string; URL is alreay linked
|
# do not change string; URL is alreay linked
|
||||||
href
|
href
|
||||||
else
|
else
|
||||||
|
|
|
@ -61,7 +61,7 @@ module ActionView #:nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return Template.new(original_template_path, original_template_path =~ /\A\// ? "" : ".") if File.file?(original_template_path)
|
return Template.new(original_template_path, original_template_path.to_s =~ /\A\// ? "" : ".") if File.file?(original_template_path)
|
||||||
|
|
||||||
raise MissingTemplate.new(self, original_template_path, format)
|
raise MissingTemplate.new(self, original_template_path, format)
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,23 +27,19 @@ module ActionView
|
||||||
def render(view, local_assigns = {})
|
def render(view, local_assigns = {})
|
||||||
compile(local_assigns)
|
compile(local_assigns)
|
||||||
|
|
||||||
stack = view.instance_variable_get(:@_render_stack)
|
view.with_template self do
|
||||||
stack.push(self)
|
view.send(:_evaluate_assigns_and_ivars)
|
||||||
|
view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
|
||||||
|
|
||||||
view.send(:_evaluate_assigns_and_ivars)
|
view.send(method_name(local_assigns), local_assigns) do |*names|
|
||||||
view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
|
ivar = :@_proc_for_layout
|
||||||
|
if !view.instance_variable_defined?(:"@content_for_#{names.first}") && view.instance_variable_defined?(ivar) && (proc = view.instance_variable_get(ivar))
|
||||||
result = view.send(method_name(local_assigns), local_assigns) do |*names|
|
view.capture(*names, &proc)
|
||||||
ivar = :@_proc_for_layout
|
elsif view.instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
|
||||||
if !view.instance_variable_defined?(:"@content_for_#{names.first}") && view.instance_variable_defined?(ivar) && (proc = view.instance_variable_get(ivar))
|
view.instance_variable_get(ivar)
|
||||||
view.capture(*names, &proc)
|
end
|
||||||
elsif view.instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
|
|
||||||
view.instance_variable_get(ivar)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
stack.pop
|
|
||||||
result
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def method_name(local_assigns)
|
def method_name(local_assigns)
|
||||||
|
|
|
@ -218,7 +218,7 @@ module ActionView #:nodoc:
|
||||||
# Returns file split into an array
|
# Returns file split into an array
|
||||||
# [base_path, name, locale, format, extension]
|
# [base_path, name, locale, format, extension]
|
||||||
def split(file)
|
def split(file)
|
||||||
if m = file.match(/^(.*\/)?([^\.]+)\.(.*)$/)
|
if m = file.to_s.match(/^(.*\/)?([^\.]+)\.(.*)$/)
|
||||||
base_path = m[1]
|
base_path = m[1]
|
||||||
name = m[2]
|
name = m[2]
|
||||||
extensions = m[3]
|
extensions = m[3]
|
||||||
|
|
|
@ -21,8 +21,15 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
|
||||||
render :text => "foo: #{session[:foo].inspect}"
|
render :text => "foo: #{session[:foo].inspect}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_session_id
|
||||||
|
session[:foo]
|
||||||
|
render :text => "#{request.session_options[:id]}"
|
||||||
|
end
|
||||||
|
|
||||||
def call_reset_session
|
def call_reset_session
|
||||||
|
session[:bar]
|
||||||
reset_session
|
reset_session
|
||||||
|
session[:bar] = "baz"
|
||||||
head :ok
|
head :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -71,6 +78,7 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
|
||||||
get '/set_session_value'
|
get '/set_session_value'
|
||||||
assert_response :success
|
assert_response :success
|
||||||
assert cookies['_session_id']
|
assert cookies['_session_id']
|
||||||
|
session_id = cookies['_session_id']
|
||||||
|
|
||||||
get '/call_reset_session'
|
get '/call_reset_session'
|
||||||
assert_response :success
|
assert_response :success
|
||||||
|
@ -79,6 +87,23 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
|
||||||
get '/get_session_value'
|
get '/get_session_value'
|
||||||
assert_response :success
|
assert_response :success
|
||||||
assert_equal 'foo: nil', response.body
|
assert_equal 'foo: nil', response.body
|
||||||
|
|
||||||
|
get '/get_session_id'
|
||||||
|
assert_response :success
|
||||||
|
assert_not_equal session_id, response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_getting_session_id
|
||||||
|
with_test_route_set do
|
||||||
|
get '/set_session_value'
|
||||||
|
assert_response :success
|
||||||
|
assert cookies['_session_id']
|
||||||
|
session_id = cookies['_session_id']
|
||||||
|
|
||||||
|
get '/get_session_id'
|
||||||
|
assert_response :success
|
||||||
|
assert_equal session_id, response.body
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_failure(message, &block)
|
def assert_failure(message, &block)
|
||||||
e = assert_raises(Assertion, &block)
|
e = assert_raise(Assertion, &block)
|
||||||
assert_match(message, e.message) if Regexp === message
|
assert_match(message, e.message) if Regexp === message
|
||||||
assert_equal(message, e.message) if String === message
|
assert_equal(message, e.message) if String === message
|
||||||
end
|
end
|
||||||
|
@ -95,24 +95,24 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
def test_equality_true_false
|
def test_equality_true_false
|
||||||
render_html %Q{<div id="1"></div><div id="2"></div>}
|
render_html %Q{<div id="1"></div><div id="2"></div>}
|
||||||
assert_nothing_raised { assert_select "div" }
|
assert_nothing_raised { assert_select "div" }
|
||||||
assert_raises(Assertion) { assert_select "p" }
|
assert_raise(Assertion) { assert_select "p" }
|
||||||
assert_nothing_raised { assert_select "div", true }
|
assert_nothing_raised { assert_select "div", true }
|
||||||
assert_raises(Assertion) { assert_select "p", true }
|
assert_raise(Assertion) { assert_select "p", true }
|
||||||
assert_raises(Assertion) { assert_select "div", false }
|
assert_raise(Assertion) { assert_select "div", false }
|
||||||
assert_nothing_raised { assert_select "p", false }
|
assert_nothing_raised { assert_select "p", false }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_equality_string_and_regexp
|
def test_equality_string_and_regexp
|
||||||
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
|
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
|
||||||
assert_nothing_raised { assert_select "div", "foo" }
|
assert_nothing_raised { assert_select "div", "foo" }
|
||||||
assert_raises(Assertion) { assert_select "div", "bar" }
|
assert_raise(Assertion) { assert_select "div", "bar" }
|
||||||
assert_nothing_raised { assert_select "div", :text=>"foo" }
|
assert_nothing_raised { assert_select "div", :text=>"foo" }
|
||||||
assert_raises(Assertion) { assert_select "div", :text=>"bar" }
|
assert_raise(Assertion) { assert_select "div", :text=>"bar" }
|
||||||
assert_nothing_raised { assert_select "div", /(foo|bar)/ }
|
assert_nothing_raised { assert_select "div", /(foo|bar)/ }
|
||||||
assert_raises(Assertion) { assert_select "div", /foobar/ }
|
assert_raise(Assertion) { assert_select "div", /foobar/ }
|
||||||
assert_nothing_raised { assert_select "div", :text=>/(foo|bar)/ }
|
assert_nothing_raised { assert_select "div", :text=>/(foo|bar)/ }
|
||||||
assert_raises(Assertion) { assert_select "div", :text=>/foobar/ }
|
assert_raise(Assertion) { assert_select "div", :text=>/foobar/ }
|
||||||
assert_raises(Assertion) { assert_select "p", :text=>/foobar/ }
|
assert_raise(Assertion) { assert_select "p", :text=>/foobar/ }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_equality_of_html
|
def test_equality_of_html
|
||||||
|
@ -120,17 +120,17 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
text = "\"This is not a big problem,\" he said."
|
text = "\"This is not a big problem,\" he said."
|
||||||
html = "<em>\"This is <strong>not</strong> a big problem,\"</em> he said."
|
html = "<em>\"This is <strong>not</strong> a big problem,\"</em> he said."
|
||||||
assert_nothing_raised { assert_select "p", text }
|
assert_nothing_raised { assert_select "p", text }
|
||||||
assert_raises(Assertion) { assert_select "p", html }
|
assert_raise(Assertion) { assert_select "p", html }
|
||||||
assert_nothing_raised { assert_select "p", :html=>html }
|
assert_nothing_raised { assert_select "p", :html=>html }
|
||||||
assert_raises(Assertion) { assert_select "p", :html=>text }
|
assert_raise(Assertion) { assert_select "p", :html=>text }
|
||||||
# No stripping for pre.
|
# No stripping for pre.
|
||||||
render_html %Q{<pre>\n<em>"This is <strong>not</strong> a big problem,"</em> he said.\n</pre>}
|
render_html %Q{<pre>\n<em>"This is <strong>not</strong> a big problem,"</em> he said.\n</pre>}
|
||||||
text = "\n\"This is not a big problem,\" he said.\n"
|
text = "\n\"This is not a big problem,\" he said.\n"
|
||||||
html = "\n<em>\"This is <strong>not</strong> a big problem,\"</em> he said.\n"
|
html = "\n<em>\"This is <strong>not</strong> a big problem,\"</em> he said.\n"
|
||||||
assert_nothing_raised { assert_select "pre", text }
|
assert_nothing_raised { assert_select "pre", text }
|
||||||
assert_raises(Assertion) { assert_select "pre", html }
|
assert_raise(Assertion) { assert_select "pre", html }
|
||||||
assert_nothing_raised { assert_select "pre", :html=>html }
|
assert_nothing_raised { assert_select "pre", :html=>html }
|
||||||
assert_raises(Assertion) { assert_select "pre", :html=>text }
|
assert_raise(Assertion) { assert_select "pre", :html=>text }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_counts
|
def test_counts
|
||||||
|
@ -210,12 +210,12 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
assert_nothing_raised { assert_select "div", "bar" }
|
assert_nothing_raised { assert_select "div", "bar" }
|
||||||
assert_nothing_raised { assert_select "div", /\w*/ }
|
assert_nothing_raised { assert_select "div", /\w*/ }
|
||||||
assert_nothing_raised { assert_select "div", /\w*/, :count=>2 }
|
assert_nothing_raised { assert_select "div", /\w*/, :count=>2 }
|
||||||
assert_raises(Assertion) { assert_select "div", :text=>"foo", :count=>2 }
|
assert_raise(Assertion) { assert_select "div", :text=>"foo", :count=>2 }
|
||||||
assert_nothing_raised { assert_select "div", :html=>"<span>bar</span>" }
|
assert_nothing_raised { assert_select "div", :html=>"<span>bar</span>" }
|
||||||
assert_nothing_raised { assert_select "div", :html=>"<span>bar</span>" }
|
assert_nothing_raised { assert_select "div", :html=>"<span>bar</span>" }
|
||||||
assert_nothing_raised { assert_select "div", :html=>/\w*/ }
|
assert_nothing_raised { assert_select "div", :html=>/\w*/ }
|
||||||
assert_nothing_raised { assert_select "div", :html=>/\w*/, :count=>2 }
|
assert_nothing_raised { assert_select "div", :html=>/\w*/, :count=>2 }
|
||||||
assert_raises(Assertion) { assert_select "div", :html=>"<span>foo</span>", :count=>2 }
|
assert_raise(Assertion) { assert_select "div", :html=>"<span>foo</span>", :count=>2 }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -253,7 +253,12 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
page.insert_html :top, "test1", "<div id=\"1\">foo</div>"
|
page.insert_html :top, "test1", "<div id=\"1\">foo</div>"
|
||||||
page.insert_html :bottom, "test2", "<div id=\"2\">foo</div>"
|
page.insert_html :bottom, "test2", "<div id=\"2\">foo</div>"
|
||||||
end
|
end
|
||||||
assert_raises(Assertion) {assert_select_rjs :insert, :top, "test2"}
|
assert_raise(Assertion) {assert_select_rjs :insert, :top, "test2"}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_elect_with_xml_namespace_attributes
|
||||||
|
render_html %Q{<link xlink:href="http://nowhere.com"></link>}
|
||||||
|
assert_nothing_raised { assert_select "link[xlink:href=http://nowhere.com]" }
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -331,7 +336,7 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
# Test that we fail if there is nothing to pick.
|
# Test that we fail if there is nothing to pick.
|
||||||
def test_assert_select_rjs_fails_if_nothing_to_pick
|
def test_assert_select_rjs_fails_if_nothing_to_pick
|
||||||
render_rjs { }
|
render_rjs { }
|
||||||
assert_raises(Assertion) { assert_select_rjs }
|
assert_raise(Assertion) { assert_select_rjs }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assert_select_rjs_with_unicode
|
def test_assert_select_rjs_with_unicode
|
||||||
|
@ -346,10 +351,10 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
if str.respond_to?(:force_encoding)
|
if str.respond_to?(:force_encoding)
|
||||||
str.force_encoding(Encoding::UTF_8)
|
str.force_encoding(Encoding::UTF_8)
|
||||||
assert_select str, /\343\203\201..\343\203\210/u
|
assert_select str, /\343\203\201..\343\203\210/u
|
||||||
assert_raises(Assertion) { assert_select str, /\343\203\201.\343\203\210/u }
|
assert_raise(Assertion) { assert_select str, /\343\203\201.\343\203\210/u }
|
||||||
else
|
else
|
||||||
assert_select str, Regexp.new("\343\203\201..\343\203\210",0,'U')
|
assert_select str, Regexp.new("\343\203\201..\343\203\210",0,'U')
|
||||||
assert_raises(Assertion) { assert_select str, Regexp.new("\343\203\201.\343\203\210",0,'U') }
|
assert_raise(Assertion) { assert_select str, Regexp.new("\343\203\201.\343\203\210",0,'U') }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -373,7 +378,7 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
assert_select "div", 1
|
assert_select "div", 1
|
||||||
assert_select "#3"
|
assert_select "#3"
|
||||||
end
|
end
|
||||||
assert_raises(Assertion) { assert_select_rjs "test4" }
|
assert_raise(Assertion) { assert_select_rjs "test4" }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assert_select_rjs_for_replace
|
def test_assert_select_rjs_for_replace
|
||||||
|
@ -391,7 +396,7 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
assert_select "div", 1
|
assert_select "div", 1
|
||||||
assert_select "#1"
|
assert_select "#1"
|
||||||
end
|
end
|
||||||
assert_raises(Assertion) { assert_select_rjs :replace, "test2" }
|
assert_raise(Assertion) { assert_select_rjs :replace, "test2" }
|
||||||
# Replace HTML.
|
# Replace HTML.
|
||||||
assert_select_rjs :replace_html do
|
assert_select_rjs :replace_html do
|
||||||
assert_select "div", 1
|
assert_select "div", 1
|
||||||
|
@ -401,7 +406,7 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
assert_select "div", 1
|
assert_select "div", 1
|
||||||
assert_select "#2"
|
assert_select "#2"
|
||||||
end
|
end
|
||||||
assert_raises(Assertion) { assert_select_rjs :replace_html, "test1" }
|
assert_raise(Assertion) { assert_select_rjs :replace_html, "test1" }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assert_select_rjs_for_chained_replace
|
def test_assert_select_rjs_for_chained_replace
|
||||||
|
@ -419,7 +424,7 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
assert_select "div", 1
|
assert_select "div", 1
|
||||||
assert_select "#1"
|
assert_select "#1"
|
||||||
end
|
end
|
||||||
assert_raises(Assertion) { assert_select_rjs :chained_replace, "test2" }
|
assert_raise(Assertion) { assert_select_rjs :chained_replace, "test2" }
|
||||||
# Replace HTML.
|
# Replace HTML.
|
||||||
assert_select_rjs :chained_replace_html do
|
assert_select_rjs :chained_replace_html do
|
||||||
assert_select "div", 1
|
assert_select "div", 1
|
||||||
|
@ -429,7 +434,7 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
assert_select "div", 1
|
assert_select "div", 1
|
||||||
assert_select "#2"
|
assert_select "#2"
|
||||||
end
|
end
|
||||||
assert_raises(Assertion) { assert_select_rjs :replace_html, "test1" }
|
assert_raise(Assertion) { assert_select_rjs :replace_html, "test1" }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Simple remove
|
# Simple remove
|
||||||
|
@ -575,7 +580,7 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
assert_select "div", 1
|
assert_select "div", 1
|
||||||
assert_select "#3"
|
assert_select "#3"
|
||||||
end
|
end
|
||||||
assert_raises(Assertion) { assert_select_rjs :insert_html, "test1" }
|
assert_raise(Assertion) { assert_select_rjs :insert_html, "test1" }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Positioned insert.
|
# Positioned insert.
|
||||||
|
@ -608,8 +613,8 @@ class AssertSelectTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assert_select_rjs_raise_errors
|
def test_assert_select_rjs_raise_errors
|
||||||
assert_raises(ArgumentError) { assert_select_rjs(:destroy) }
|
assert_raise(ArgumentError) { assert_select_rjs(:destroy) }
|
||||||
assert_raises(ArgumentError) { assert_select_rjs(:insert, :left) }
|
assert_raise(ArgumentError) { assert_select_rjs(:insert, :left) }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Simple selection from a single result.
|
# Simple selection from a single result.
|
||||||
|
@ -701,7 +706,7 @@ EOF
|
||||||
#
|
#
|
||||||
|
|
||||||
def test_assert_select_email
|
def test_assert_select_email
|
||||||
assert_raises(Assertion) { assert_select_email {} }
|
assert_raise(Assertion) { assert_select_email {} }
|
||||||
AssertSelectMailer.deliver_test "<div><p>foo</p><p>bar</p></div>"
|
AssertSelectMailer.deliver_test "<div><p>foo</p><p>bar</p></div>"
|
||||||
assert_select_email do
|
assert_select_email do
|
||||||
assert_select "div:root" do
|
assert_select "div:root" do
|
||||||
|
|
|
@ -428,6 +428,20 @@ class ActionCacheTest < ActionController::TestCase
|
||||||
assert_equal 'application/xml', @response.content_type
|
assert_equal 'application/xml', @response.content_type
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_correct_content_type_is_returned_for_cache_hit_on_action_with_string_key
|
||||||
|
# run it twice to cache it the first time
|
||||||
|
get :show, :format => 'xml'
|
||||||
|
get :show, :format => 'xml'
|
||||||
|
assert_equal 'application/xml', @response.content_type
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_correct_content_type_is_returned_for_cache_hit_on_action_with_string_key_from_proc
|
||||||
|
# run it twice to cache it the first time
|
||||||
|
get :edit, :id => 1, :format => 'xml'
|
||||||
|
get :edit, :id => 1, :format => 'xml'
|
||||||
|
assert_equal 'application/xml', @response.content_type
|
||||||
|
end
|
||||||
|
|
||||||
def test_empty_path_is_normalized
|
def test_empty_path_is_normalized
|
||||||
@mock_controller.mock_url_for = 'http://example.org/'
|
@mock_controller.mock_url_for = 'http://example.org/'
|
||||||
@mock_controller.mock_path = '/'
|
@mock_controller.mock_path = '/'
|
||||||
|
|
|
@ -9,3 +9,11 @@ end
|
||||||
|
|
||||||
class GoodCustomer < Customer
|
class GoodCustomer < Customer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Quiz
|
||||||
|
class Question < Struct.new(:name, :id)
|
||||||
|
def to_param
|
||||||
|
id.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -134,7 +134,7 @@ HTML
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_invalid_document_raises_exception_when_strict
|
def test_invalid_document_raises_exception_when_strict
|
||||||
assert_raises RuntimeError do
|
assert_raise RuntimeError do
|
||||||
doc = HTML::Document.new("<html>
|
doc = HTML::Document.new("<html>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -5,7 +5,8 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
|
||||||
before_filter :authenticate, :only => :index
|
before_filter :authenticate, :only => :index
|
||||||
before_filter :authenticate_with_request, :only => :display
|
before_filter :authenticate_with_request, :only => :display
|
||||||
|
|
||||||
USERS = { 'lifo' => 'world', 'pretty' => 'please' }
|
USERS = { 'lifo' => 'world', 'pretty' => 'please',
|
||||||
|
'dhh' => ::Digest::MD5::hexdigest(["dhh","SuperSecret","secret"].join(":"))}
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render :text => "Hello Secret"
|
render :text => "Hello Secret"
|
||||||
|
@ -107,8 +108,42 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
|
||||||
assert_equal 'Definitely Maybe', @response.body
|
assert_equal 'Definitely Maybe', @response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
test "authentication request with relative URI" do
|
test "authentication request with valid credential and nil session" do
|
||||||
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:uri => "/", :username => 'pretty', :password => 'please')
|
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please')
|
||||||
|
|
||||||
|
# session_id = "" in functional test, but is +nil+ in real life
|
||||||
|
@request.session.session_id = nil
|
||||||
|
get :display
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert assigns(:logged_in)
|
||||||
|
assert_equal 'Definitely Maybe', @response.body
|
||||||
|
end
|
||||||
|
|
||||||
|
test "authentication request with request-uri that doesn't match credentials digest-uri" do
|
||||||
|
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please')
|
||||||
|
@request.env['REQUEST_URI'] = "/http_digest_authentication_test/dummy_digest/altered/uri"
|
||||||
|
get :display
|
||||||
|
|
||||||
|
assert_response :unauthorized
|
||||||
|
assert_equal "Authentication Failed", @response.body
|
||||||
|
end
|
||||||
|
|
||||||
|
test "authentication request with absolute uri" do
|
||||||
|
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:uri => "http://test.host/http_digest_authentication_test/dummy_digest/display",
|
||||||
|
:username => 'pretty', :password => 'please')
|
||||||
|
@request.env['REQUEST_URI'] = "http://test.host/http_digest_authentication_test/dummy_digest/display"
|
||||||
|
get :display
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert assigns(:logged_in)
|
||||||
|
assert_equal 'Definitely Maybe', @response.body
|
||||||
|
end
|
||||||
|
|
||||||
|
test "authentication request with password stored as ha1 digest hash" do
|
||||||
|
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'dhh',
|
||||||
|
:password => ::Digest::MD5::hexdigest(["dhh","SuperSecret","secret"].join(":")),
|
||||||
|
:password_is_ha1 => true)
|
||||||
get :display
|
get :display
|
||||||
|
|
||||||
assert_response :success
|
assert_response :success
|
||||||
|
@ -119,18 +154,22 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
|
||||||
private
|
private
|
||||||
|
|
||||||
def encode_credentials(options)
|
def encode_credentials(options)
|
||||||
options.reverse_merge!(:nc => "00000001", :cnonce => "0a4f113b")
|
options.reverse_merge!(:nc => "00000001", :cnonce => "0a4f113b", :password_is_ha1 => false)
|
||||||
password = options.delete(:password)
|
password = options.delete(:password)
|
||||||
|
|
||||||
# Perform unautheticated get to retrieve digest parameters to use on subsequent request
|
# Set in /initializers/session_store.rb. Used as secret in generating nonce
|
||||||
|
# to prevent tampering of timestamp
|
||||||
|
ActionController::Base.session_options[:secret] = "session_options_secret"
|
||||||
|
|
||||||
|
# Perform unauthenticated GET to retrieve digest parameters to use on subsequent request
|
||||||
get :index
|
get :index
|
||||||
|
|
||||||
assert_response :unauthorized
|
assert_response :unauthorized
|
||||||
|
|
||||||
credentials = decode_credentials(@response.headers['WWW-Authenticate'])
|
credentials = decode_credentials(@response.headers['WWW-Authenticate'])
|
||||||
credentials.merge!(options)
|
credentials.merge!(options)
|
||||||
credentials.reverse_merge!(:uri => "http://#{@request.host}#{@request.env['REQUEST_URI']}")
|
credentials.reverse_merge!(:uri => "#{@request.env['REQUEST_URI']}")
|
||||||
ActionController::HttpAuthentication::Digest.encode_credentials("GET", credentials, password)
|
ActionController::HttpAuthentication::Digest.encode_credentials("GET", credentials, password, options[:password_is_ha1])
|
||||||
end
|
end
|
||||||
|
|
||||||
def decode_credentials(header)
|
def decode_credentials(header)
|
||||||
|
|
|
@ -2,7 +2,7 @@ require 'abstract_unit'
|
||||||
|
|
||||||
class SessionTest < Test::Unit::TestCase
|
class SessionTest < Test::Unit::TestCase
|
||||||
StubApp = lambda { |env|
|
StubApp = lambda { |env|
|
||||||
[200, {"Content-Type" => "text/html", "Content-Length" => "13"}, "Hello, World!"]
|
[200, {"Content-Type" => "text/html", "Content-Length" => "13"}, ["Hello, World!"]]
|
||||||
}
|
}
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
|
@ -389,9 +389,9 @@ class MetalTest < ActionController::IntegrationTest
|
||||||
class Poller
|
class Poller
|
||||||
def self.call(env)
|
def self.call(env)
|
||||||
if env["PATH_INFO"] =~ /^\/success/
|
if env["PATH_INFO"] =~ /^\/success/
|
||||||
[200, {"Content-Type" => "text/plain", "Content-Length" => "12"}, "Hello World!"]
|
[200, {"Content-Type" => "text/plain", "Content-Length" => "12"}, ["Hello World!"]]
|
||||||
else
|
else
|
||||||
[404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, '']
|
[404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -79,6 +79,10 @@ end
|
||||||
class DefaultLayoutController < LayoutTest
|
class DefaultLayoutController < LayoutTest
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class AbsolutePathLayoutController < LayoutTest
|
||||||
|
layout File.expand_path(File.expand_path(__FILE__) + '/../../fixtures/layout_tests/layouts/layout_test.rhtml')
|
||||||
|
end
|
||||||
|
|
||||||
class HasOwnLayoutController < LayoutTest
|
class HasOwnLayoutController < LayoutTest
|
||||||
layout 'item'
|
layout 'item'
|
||||||
end
|
end
|
||||||
|
@ -137,12 +141,18 @@ class LayoutSetInResponseTest < ActionController::TestCase
|
||||||
ensure
|
ensure
|
||||||
ActionController::Base.exempt_from_layout.delete(/\.rhtml$/)
|
ActionController::Base.exempt_from_layout.delete(/\.rhtml$/)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_layout_is_picked_from_the_controller_instances_view_path
|
def test_layout_is_picked_from_the_controller_instances_view_path
|
||||||
@controller = PrependsViewPathController.new
|
@controller = PrependsViewPathController.new
|
||||||
get :hello
|
get :hello
|
||||||
assert_equal 'layouts/alt', @response.layout
|
assert_equal 'layouts/alt', @response.layout
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_absolute_pathed_layout
|
||||||
|
@controller = AbsolutePathLayoutController.new
|
||||||
|
get :hello
|
||||||
|
assert_equal "layout_test.rhtml hello.rhtml", @response.body.strip
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class RenderWithTemplateOptionController < LayoutTest
|
class RenderWithTemplateOptionController < LayoutTest
|
||||||
|
|
|
@ -469,7 +469,7 @@ class MimeControllerTest < ActionController::TestCase
|
||||||
assert_equal '<html><div id="html_missing">Hello future from Firefox!</div></html>', @response.body
|
assert_equal '<html><div id="html_missing">Hello future from Firefox!</div></html>', @response.body
|
||||||
|
|
||||||
@request.accept = "text/iphone"
|
@request.accept = "text/iphone"
|
||||||
assert_raises(ActionView::MissingTemplate) { get :iphone_with_html_response_type_without_layout }
|
assert_raise(ActionView::MissingTemplate) { get :iphone_with_html_response_type_without_layout }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,20 @@ class Tag < Article
|
||||||
def response_id; 1 end
|
def response_id; 1 end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Tax
|
||||||
|
attr_reader :id
|
||||||
|
def save; @id = 1 end
|
||||||
|
def new_record?; @id.nil? end
|
||||||
|
def name
|
||||||
|
model = self.class.name.downcase
|
||||||
|
@id.nil? ? "new #{model}" : "#{model} ##{@id}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Fax < Tax
|
||||||
|
def store_id; 1 end
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: test nested models
|
# TODO: test nested models
|
||||||
class Response::Nested < Response; end
|
class Response::Nested < Response; end
|
||||||
|
|
||||||
|
@ -27,6 +41,8 @@ class PolymorphicRoutesTest < ActiveSupport::TestCase
|
||||||
def setup
|
def setup
|
||||||
@article = Article.new
|
@article = Article.new
|
||||||
@response = Response.new
|
@response = Response.new
|
||||||
|
@tax = Tax.new
|
||||||
|
@fax = Fax.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_with_record
|
def test_with_record
|
||||||
|
@ -205,4 +221,73 @@ class PolymorphicRoutesTest < ActiveSupport::TestCase
|
||||||
polymorphic_url(path)
|
polymorphic_url(path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Tests for names where .plural.singular doesn't round-trip
|
||||||
|
def test_with_irregular_plural_record
|
||||||
|
@tax.save
|
||||||
|
expects(:taxis_url).with(@tax)
|
||||||
|
polymorphic_url(@tax)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_with_irregular_plural_new_record
|
||||||
|
expects(:taxes_url).with()
|
||||||
|
@tax.expects(:new_record?).returns(true)
|
||||||
|
polymorphic_url(@tax)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_with_irregular_plural_record_and_action
|
||||||
|
expects(:new_taxis_url).with()
|
||||||
|
@tax.expects(:new_record?).never
|
||||||
|
polymorphic_url(@tax, :action => 'new')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_irregular_plural_url_helper_prefixed_with_new
|
||||||
|
expects(:new_taxis_url).with()
|
||||||
|
new_polymorphic_url(@tax)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_irregular_plural_url_helper_prefixed_with_edit
|
||||||
|
@tax.save
|
||||||
|
expects(:edit_taxis_url).with(@tax)
|
||||||
|
edit_polymorphic_url(@tax)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_with_nested_irregular_plurals
|
||||||
|
@fax.save
|
||||||
|
expects(:taxis_faxis_url).with(@tax, @fax)
|
||||||
|
polymorphic_url([@tax, @fax])
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_with_nested_unsaved_irregular_plurals
|
||||||
|
expects(:taxis_faxes_url).with(@tax)
|
||||||
|
polymorphic_url([@tax, @fax])
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_with_irregular_plural_array_and_namespace
|
||||||
|
expects(:new_admin_taxis_url).with()
|
||||||
|
polymorphic_url([:admin, @tax], :action => 'new')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_unsaved_with_irregular_plural_array_and_namespace
|
||||||
|
expects(:admin_taxes_url).with()
|
||||||
|
polymorphic_url([:admin, @tax])
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_nesting_with_irregular_plurals_and_array_ending_in_singleton_resource
|
||||||
|
expects(:taxis_faxis_url).with(@tax)
|
||||||
|
polymorphic_url([@tax, :faxis])
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_with_array_containing_single_irregular_plural_object
|
||||||
|
@tax.save
|
||||||
|
expects(:taxis_url).with(@tax)
|
||||||
|
polymorphic_url([nil, @tax])
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_with_array_containing_single_name_irregular_plural
|
||||||
|
@tax.save
|
||||||
|
expects(:taxes_url)
|
||||||
|
polymorphic_url([:taxes])
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -212,7 +212,7 @@ class RedirectTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_redirect_to_back_with_no_referer
|
def test_redirect_to_back_with_no_referer
|
||||||
assert_raises(ActionController::RedirectBackError) {
|
assert_raise(ActionController::RedirectBackError) {
|
||||||
@request.env["HTTP_REFERER"] = nil
|
@request.env["HTTP_REFERER"] = nil
|
||||||
get :redirect_to_back
|
get :redirect_to_back
|
||||||
}
|
}
|
||||||
|
@ -239,7 +239,7 @@ class RedirectTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_redirect_to_nil
|
def test_redirect_to_nil
|
||||||
assert_raises(ActionController::ActionControllerError) do
|
assert_raise(ActionController::ActionControllerError) do
|
||||||
get :redirect_to_nil
|
get :redirect_to_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -157,6 +157,11 @@ class TestController < ActionController::Base
|
||||||
render :file => 'test/dot.directory/render_file_with_ivar'
|
render :file => 'test/dot.directory/render_file_with_ivar'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render_file_using_pathname
|
||||||
|
@secret = 'in the sauce'
|
||||||
|
render :file => Pathname.new(File.dirname(__FILE__)).join('..', 'fixtures', 'test', 'dot.directory', 'render_file_with_ivar.erb')
|
||||||
|
end
|
||||||
|
|
||||||
def render_file_from_template
|
def render_file_from_template
|
||||||
@secret = 'in the sauce'
|
@secret = 'in the sauce'
|
||||||
@path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb'))
|
@path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb'))
|
||||||
|
@ -313,6 +318,10 @@ class TestController < ActionController::Base
|
||||||
def render_implicit_js_template_without_layout
|
def render_implicit_js_template_without_layout
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render_html_explicit_template_and_layout
|
||||||
|
render :template => 'test/render_implicit_html_template_from_xhr_request', :layout => 'layouts/default_html'
|
||||||
|
end
|
||||||
|
|
||||||
def formatted_html_erb
|
def formatted_html_erb
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -678,6 +687,14 @@ class TestController < ActionController::Base
|
||||||
render :partial => "hash_object", :object => {:first_name => "Sam"}
|
render :partial => "hash_object", :object => {:first_name => "Sam"}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def partial_with_nested_object
|
||||||
|
render :partial => "quiz/questions/question", :object => Quiz::Question.new("first")
|
||||||
|
end
|
||||||
|
|
||||||
|
def partial_with_nested_object_shorthand
|
||||||
|
render Quiz::Question.new("first")
|
||||||
|
end
|
||||||
|
|
||||||
def partial_hash_collection
|
def partial_hash_collection
|
||||||
render :partial => "hash_object", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ]
|
render :partial => "hash_object", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ]
|
||||||
end
|
end
|
||||||
|
@ -720,6 +737,8 @@ class TestController < ActionController::Base
|
||||||
"delete_with_js", "update_page", "update_page_with_instance_variables"
|
"delete_with_js", "update_page", "update_page_with_instance_variables"
|
||||||
|
|
||||||
"layouts/standard"
|
"layouts/standard"
|
||||||
|
when "render_implicit_js_template_without_layout"
|
||||||
|
"layouts/default_html"
|
||||||
when "action_talk_to_layout", "layout_overriding_layout"
|
when "action_talk_to_layout", "layout_overriding_layout"
|
||||||
"layouts/talk_from_action"
|
"layouts/talk_from_action"
|
||||||
when "render_implicit_html_template_from_xhr_request"
|
when "render_implicit_html_template_from_xhr_request"
|
||||||
|
@ -817,6 +836,11 @@ class RenderTest < ActionController::TestCase
|
||||||
assert_equal "<html>hello world, I'm here!</html>", @response.body
|
assert_equal "<html>hello world, I'm here!</html>", @response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_xhr_with_render_text_and_layout
|
||||||
|
xhr :get, :render_text_hello_world_with_layout
|
||||||
|
assert_equal "<html>hello world, I'm here!</html>", @response.body
|
||||||
|
end
|
||||||
|
|
||||||
def test_do_with_render_action_and_layout_false
|
def test_do_with_render_action_and_layout_false
|
||||||
get :hello_world_with_layout_false
|
get :hello_world_with_layout_false
|
||||||
assert_equal 'Hello world!', @response.body
|
assert_equal 'Hello world!', @response.body
|
||||||
|
@ -842,6 +866,11 @@ class RenderTest < ActionController::TestCase
|
||||||
assert_equal "The secret is in the sauce\n", @response.body
|
assert_equal "The secret is in the sauce\n", @response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_render_file_using_pathname
|
||||||
|
get :render_file_using_pathname
|
||||||
|
assert_equal "The secret is in the sauce\n", @response.body
|
||||||
|
end
|
||||||
|
|
||||||
def test_render_file_with_locals
|
def test_render_file_with_locals
|
||||||
get :render_file_with_locals
|
get :render_file_with_locals
|
||||||
assert_equal "The secret is in the sauce\n", @response.body
|
assert_equal "The secret is in the sauce\n", @response.body
|
||||||
|
@ -918,11 +947,11 @@ class RenderTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_attempt_to_access_object_method
|
def test_attempt_to_access_object_method
|
||||||
assert_raises(ActionController::UnknownAction, "No action responded to [clone]") { get :clone }
|
assert_raise(ActionController::UnknownAction, "No action responded to [clone]") { get :clone }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_private_methods
|
def test_private_methods
|
||||||
assert_raises(ActionController::UnknownAction, "No action responded to [determine_layout]") { get :determine_layout }
|
assert_raise(ActionController::UnknownAction, "No action responded to [determine_layout]") { get :determine_layout }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_access_to_request_in_view
|
def test_access_to_request_in_view
|
||||||
|
@ -1056,6 +1085,11 @@ class RenderTest < ActionController::TestCase
|
||||||
assert_equal "XHR!\nHello HTML!", @response.body
|
assert_equal "XHR!\nHello HTML!", @response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_should_render_explicit_html_template_with_html_layout
|
||||||
|
xhr :get, :render_html_explicit_template_and_layout
|
||||||
|
assert_equal "<html>Hello HTML!</html>\n", @response.body
|
||||||
|
end
|
||||||
|
|
||||||
def test_should_implicitly_render_js_template_without_layout
|
def test_should_implicitly_render_js_template_without_layout
|
||||||
get :render_implicit_js_template_without_layout, :format => :js
|
get :render_implicit_js_template_without_layout, :format => :js
|
||||||
assert_no_match /<html>/, @response.body
|
assert_no_match /<html>/, @response.body
|
||||||
|
@ -1149,7 +1183,7 @@ class RenderTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_bad_render_to_string_still_throws_exception
|
def test_bad_render_to_string_still_throws_exception
|
||||||
assert_raises(ActionView::MissingTemplate) { get :render_to_string_with_exception }
|
assert_raise(ActionView::MissingTemplate) { get :render_to_string_with_exception }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_render_to_string_that_throws_caught_exception_doesnt_break_assigns
|
def test_render_to_string_that_throws_caught_exception_doesnt_break_assigns
|
||||||
|
@ -1174,15 +1208,15 @@ class RenderTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_double_render
|
def test_double_render
|
||||||
assert_raises(ActionController::DoubleRenderError) { get :double_render }
|
assert_raise(ActionController::DoubleRenderError) { get :double_render }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_double_redirect
|
def test_double_redirect
|
||||||
assert_raises(ActionController::DoubleRenderError) { get :double_redirect }
|
assert_raise(ActionController::DoubleRenderError) { get :double_redirect }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_render_and_redirect
|
def test_render_and_redirect
|
||||||
assert_raises(ActionController::DoubleRenderError) { get :render_and_redirect }
|
assert_raise(ActionController::DoubleRenderError) { get :render_and_redirect }
|
||||||
end
|
end
|
||||||
|
|
||||||
# specify the one exception to double render rule - render_to_string followed by render
|
# specify the one exception to double render rule - render_to_string followed by render
|
||||||
|
@ -1463,6 +1497,16 @@ class RenderTest < ActionController::TestCase
|
||||||
assert_equal "Sam\nmaS\n", @response.body
|
assert_equal "Sam\nmaS\n", @response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_partial_with_nested_object
|
||||||
|
get :partial_with_nested_object
|
||||||
|
assert_equal "first", @response.body
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_partial_with_nested_object_shorthand
|
||||||
|
get :partial_with_nested_object_shorthand
|
||||||
|
assert_equal "first", @response.body
|
||||||
|
end
|
||||||
|
|
||||||
def test_hash_partial_collection
|
def test_hash_partial_collection
|
||||||
get :partial_hash_collection
|
get :partial_hash_collection
|
||||||
assert_equal "Pratik\nkitarP\nAmy\nymA\n", @response.body
|
assert_equal "Pratik\nkitarP\nAmy\nymA\n", @response.body
|
||||||
|
@ -1481,7 +1525,7 @@ class RenderTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_render_missing_partial_template
|
def test_render_missing_partial_template
|
||||||
assert_raises(ActionView::MissingTemplate) do
|
assert_raise(ActionView::MissingTemplate) do
|
||||||
get :missing_partial
|
get :missing_partial
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1509,7 +1553,7 @@ class ExpiresInRenderTest < ActionController::TestCase
|
||||||
assert_equal "max-age=60, private", @response.headers["Cache-Control"]
|
assert_equal "max-age=60, private", @response.headers["Cache-Control"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_expires_in_header
|
def test_expires_in_header_with_public
|
||||||
get :conditional_hello_with_expires_in_with_public
|
get :conditional_hello_with_expires_in_with_public
|
||||||
assert_equal "max-age=60, public", @response.headers["Cache-Control"]
|
assert_equal "max-age=60, public", @response.headers["Cache-Control"]
|
||||||
end
|
end
|
||||||
|
|
|
@ -103,7 +103,7 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest
|
||||||
|
|
||||||
test "does not create tempfile if no file has been selected" do
|
test "does not create tempfile if no file has been selected" do
|
||||||
params = parse_multipart('none')
|
params = parse_multipart('none')
|
||||||
assert_equal %w(files submit-name), params.keys.sort
|
assert_equal %w(submit-name), params.keys.sort
|
||||||
assert_equal 'Larry', params['submit-name']
|
assert_equal 'Larry', params['submit-name']
|
||||||
assert_equal nil, params['files']
|
assert_equal nil, params['files']
|
||||||
end
|
end
|
||||||
|
|
|
@ -79,17 +79,17 @@ module RequestForgeryProtectionTests
|
||||||
|
|
||||||
def test_should_not_allow_html_post_without_token
|
def test_should_not_allow_html_post_without_token
|
||||||
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
|
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
|
||||||
assert_raises(ActionController::InvalidAuthenticityToken) { post :index, :format => :html }
|
assert_raise(ActionController::InvalidAuthenticityToken) { post :index, :format => :html }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_not_allow_html_put_without_token
|
def test_should_not_allow_html_put_without_token
|
||||||
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
|
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
|
||||||
assert_raises(ActionController::InvalidAuthenticityToken) { put :index, :format => :html }
|
assert_raise(ActionController::InvalidAuthenticityToken) { put :index, :format => :html }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_not_allow_html_delete_without_token
|
def test_should_not_allow_html_delete_without_token
|
||||||
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
|
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
|
||||||
assert_raises(ActionController::InvalidAuthenticityToken) { delete :index, :format => :html }
|
assert_raise(ActionController::InvalidAuthenticityToken) { delete :index, :format => :html }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_allow_api_formatted_post_without_token
|
def test_should_allow_api_formatted_post_without_token
|
||||||
|
@ -111,42 +111,42 @@ module RequestForgeryProtectionTests
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_not_allow_api_formatted_post_sent_as_url_encoded_form_without_token
|
def test_should_not_allow_api_formatted_post_sent_as_url_encoded_form_without_token
|
||||||
assert_raises(ActionController::InvalidAuthenticityToken) do
|
assert_raise(ActionController::InvalidAuthenticityToken) do
|
||||||
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
|
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
|
||||||
post :index, :format => 'xml'
|
post :index, :format => 'xml'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_not_allow_api_formatted_put_sent_as_url_encoded_form_without_token
|
def test_should_not_allow_api_formatted_put_sent_as_url_encoded_form_without_token
|
||||||
assert_raises(ActionController::InvalidAuthenticityToken) do
|
assert_raise(ActionController::InvalidAuthenticityToken) do
|
||||||
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
|
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
|
||||||
put :index, :format => 'xml'
|
put :index, :format => 'xml'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_not_allow_api_formatted_delete_sent_as_url_encoded_form_without_token
|
def test_should_not_allow_api_formatted_delete_sent_as_url_encoded_form_without_token
|
||||||
assert_raises(ActionController::InvalidAuthenticityToken) do
|
assert_raise(ActionController::InvalidAuthenticityToken) do
|
||||||
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
|
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
|
||||||
delete :index, :format => 'xml'
|
delete :index, :format => 'xml'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_not_allow_api_formatted_post_sent_as_multipart_form_without_token
|
def test_should_not_allow_api_formatted_post_sent_as_multipart_form_without_token
|
||||||
assert_raises(ActionController::InvalidAuthenticityToken) do
|
assert_raise(ActionController::InvalidAuthenticityToken) do
|
||||||
@request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
|
@request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
|
||||||
post :index, :format => 'xml'
|
post :index, :format => 'xml'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_not_allow_api_formatted_put_sent_as_multipart_form_without_token
|
def test_should_not_allow_api_formatted_put_sent_as_multipart_form_without_token
|
||||||
assert_raises(ActionController::InvalidAuthenticityToken) do
|
assert_raise(ActionController::InvalidAuthenticityToken) do
|
||||||
@request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
|
@request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
|
||||||
put :index, :format => 'xml'
|
put :index, :format => 'xml'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_not_allow_api_formatted_delete_sent_as_multipart_form_without_token
|
def test_should_not_allow_api_formatted_delete_sent_as_multipart_form_without_token
|
||||||
assert_raises(ActionController::InvalidAuthenticityToken) do
|
assert_raise(ActionController::InvalidAuthenticityToken) do
|
||||||
@request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
|
@request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
|
||||||
delete :index, :format => 'xml'
|
delete :index, :format => 'xml'
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,7 +59,7 @@ class RequestTest < ActiveSupport::TestCase
|
||||||
assert_equal '3.4.5.6', @request.remote_ip
|
assert_equal '3.4.5.6', @request.remote_ip
|
||||||
|
|
||||||
@request.env['HTTP_CLIENT_IP'] = '8.8.8.8'
|
@request.env['HTTP_CLIENT_IP'] = '8.8.8.8'
|
||||||
e = assert_raises(ActionController::ActionControllerError) {
|
e = assert_raise(ActionController::ActionControllerError) {
|
||||||
@request.remote_ip
|
@request.remote_ip
|
||||||
}
|
}
|
||||||
assert_match /IP spoofing attack/, e.message
|
assert_match /IP spoofing attack/, e.message
|
||||||
|
@ -297,7 +297,7 @@ class RequestTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_invalid_http_method_raises_exception
|
def test_invalid_http_method_raises_exception
|
||||||
assert_raises(ActionController::UnknownHttpMethod) do
|
assert_raise(ActionController::UnknownHttpMethod) do
|
||||||
self.request_method = :random_method
|
self.request_method = :random_method
|
||||||
@request.request_method
|
@request.request_method
|
||||||
end
|
end
|
||||||
|
@ -311,7 +311,7 @@ class RequestTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_invalid_method_hacking_on_post_raises_exception
|
def test_invalid_method_hacking_on_post_raises_exception
|
||||||
assert_raises(ActionController::UnknownHttpMethod) do
|
assert_raise(ActionController::UnknownHttpMethod) do
|
||||||
self.request_method = :_random_method
|
self.request_method = :_random_method
|
||||||
@request.request_method
|
@request.request_method
|
||||||
end
|
end
|
||||||
|
|
|
@ -99,7 +99,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
expected_options = {:controller => 'messages', :action => 'show', :id => '1.1.1'}
|
expected_options = {:controller => 'messages', :action => 'show', :id => '1.1.1'}
|
||||||
|
|
||||||
with_restful_routing :messages do
|
with_restful_routing :messages do
|
||||||
assert_raises(ActionController::RoutingError) do
|
assert_raise(ActionController::RoutingError) do
|
||||||
assert_recognizes(expected_options, :path => 'messages/1.1.1', :method => :get)
|
assert_recognizes(expected_options, :path => 'messages/1.1.1', :method => :get)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -175,6 +175,24 @@ class ResourcesTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_with_collection_actions_and_name_prefix_and_member_action_with_same_name
|
||||||
|
actions = { 'a' => :get }
|
||||||
|
|
||||||
|
with_restful_routing :messages, :path_prefix => '/threads/:thread_id', :name_prefix => "thread_", :collection => actions, :member => actions do
|
||||||
|
assert_restful_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options|
|
||||||
|
actions.each do |action, method|
|
||||||
|
assert_recognizes(options.merge(:action => action), :path => "/threads/1/messages/#{action}", :method => method)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options|
|
||||||
|
actions.keys.each do |action|
|
||||||
|
assert_named_route "/threads/1/messages/#{action}", "#{action}_thread_messages_path", :action => action
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_with_collection_action_and_name_prefix_and_formatted
|
def test_with_collection_action_and_name_prefix_and_formatted
|
||||||
actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete }
|
actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete }
|
||||||
|
|
||||||
|
@ -209,6 +227,14 @@ class ResourcesTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_with_member_action_and_requirement
|
||||||
|
expected_options = {:controller => 'messages', :action => 'mark', :id => '1.1.1'}
|
||||||
|
|
||||||
|
with_restful_routing(:messages, :requirements => {:id => /[0-9]\.[0-9]\.[0-9]/}, :member => { :mark => :get }) do
|
||||||
|
assert_recognizes(expected_options, :path => 'messages/1.1.1/mark', :method => :get)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_member_when_override_paths_for_default_restful_actions_with
|
def test_member_when_override_paths_for_default_restful_actions_with
|
||||||
[:put, :post].each do |method|
|
[:put, :post].each do |method|
|
||||||
with_restful_routing :messages, :member => { :mark => method }, :path_names => {:new => 'nuevo'} do
|
with_restful_routing :messages, :member => { :mark => method }, :path_names => {:new => 'nuevo'} do
|
||||||
|
@ -325,7 +351,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
with_restful_routing :messages do
|
with_restful_routing :messages do
|
||||||
assert_restful_routes_for :messages do |options|
|
assert_restful_routes_for :messages do |options|
|
||||||
assert_recognizes(options.merge(:action => "new"), :path => "/messages/new", :method => :get)
|
assert_recognizes(options.merge(:action => "new"), :path => "/messages/new", :method => :get)
|
||||||
assert_raises(ActionController::MethodNotAllowed) do
|
assert_raise(ActionController::MethodNotAllowed) do
|
||||||
ActionController::Routing::Routes.recognize_path("/messages/new", :method => :post)
|
ActionController::Routing::Routes.recognize_path("/messages/new", :method => :post)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -406,6 +432,34 @@ class ResourcesTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_shallow_nested_restful_routes_with_namespaces
|
||||||
|
with_routing do |set|
|
||||||
|
set.draw do |map|
|
||||||
|
map.namespace :backoffice do |map|
|
||||||
|
map.namespace :admin do |map|
|
||||||
|
map.resources :products, :shallow => true do |map|
|
||||||
|
map.resources :images
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_simply_restful_for :products,
|
||||||
|
:controller => 'backoffice/admin/products',
|
||||||
|
:namespace => 'backoffice/admin/',
|
||||||
|
:name_prefix => 'backoffice_admin_',
|
||||||
|
:path_prefix => 'backoffice/admin/',
|
||||||
|
:shallow => true
|
||||||
|
assert_simply_restful_for :images,
|
||||||
|
:controller => 'backoffice/admin/images',
|
||||||
|
:namespace => 'backoffice/admin/',
|
||||||
|
:name_prefix => 'backoffice_admin_product_',
|
||||||
|
:path_prefix => 'backoffice/admin/products/1/',
|
||||||
|
:shallow => true,
|
||||||
|
:options => { :product_id => '1' }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_restful_routes_dont_generate_duplicates
|
def test_restful_routes_dont_generate_duplicates
|
||||||
with_restful_routing :messages do
|
with_restful_routing :messages do
|
||||||
routes = ActionController::Routing::Routes.routes
|
routes = ActionController::Routing::Routes.routes
|
||||||
|
@ -583,11 +637,11 @@ class ResourcesTest < ActionController::TestCase
|
||||||
options = { :controller => controller_name.to_s }
|
options = { :controller => controller_name.to_s }
|
||||||
collection_path = "/#{controller_name}"
|
collection_path = "/#{controller_name}"
|
||||||
|
|
||||||
assert_raises(ActionController::MethodNotAllowed) do
|
assert_raise(ActionController::MethodNotAllowed) do
|
||||||
assert_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :put)
|
assert_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :put)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_raises(ActionController::MethodNotAllowed) do
|
assert_raise(ActionController::MethodNotAllowed) do
|
||||||
assert_recognizes(options.merge(:action => 'destroy'), :path => collection_path, :method => :delete)
|
assert_recognizes(options.merge(:action => 'destroy'), :path => collection_path, :method => :delete)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -596,7 +650,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
def test_should_not_allow_invalid_head_method_for_member_routes
|
def test_should_not_allow_invalid_head_method_for_member_routes
|
||||||
with_routing do |set|
|
with_routing do |set|
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
assert_raises(ArgumentError) do
|
assert_raise(ArgumentError) do
|
||||||
map.resources :messages, :member => {:something => :head}
|
map.resources :messages, :member => {:something => :head}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -606,7 +660,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
def test_should_not_allow_invalid_http_methods_for_member_routes
|
def test_should_not_allow_invalid_http_methods_for_member_routes
|
||||||
with_routing do |set|
|
with_routing do |set|
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
assert_raises(ArgumentError) do
|
assert_raise(ArgumentError) do
|
||||||
map.resources :messages, :member => {:something => :invalid}
|
map.resources :messages, :member => {:something => :invalid}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1074,7 +1128,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
|
|
||||||
path = "#{options[:as] || controller_name}"
|
path = "#{options[:as] || controller_name}"
|
||||||
collection_path = "/#{options[:path_prefix]}#{path}"
|
collection_path = "/#{options[:path_prefix]}#{path}"
|
||||||
shallow_path = "/#{options[:path_prefix] unless options[:shallow]}#{path}"
|
shallow_path = "/#{options[:shallow] ? options[:namespace] : options[:path_prefix]}#{path}"
|
||||||
member_path = "#{shallow_path}/1"
|
member_path = "#{shallow_path}/1"
|
||||||
new_path = "#{collection_path}/#{new_action}"
|
new_path = "#{collection_path}/#{new_action}"
|
||||||
edit_member_path = "#{member_path}/#{edit_action}"
|
edit_member_path = "#{member_path}/#{edit_action}"
|
||||||
|
@ -1138,10 +1192,10 @@ class ResourcesTest < ActionController::TestCase
|
||||||
options[:options].delete :action
|
options[:options].delete :action
|
||||||
|
|
||||||
path = "#{options[:as] || controller_name}"
|
path = "#{options[:as] || controller_name}"
|
||||||
shallow_path = "/#{options[:path_prefix] unless options[:shallow]}#{path}"
|
shallow_path = "/#{options[:shallow] ? options[:namespace] : options[:path_prefix]}#{path}"
|
||||||
full_path = "/#{options[:path_prefix]}#{path}"
|
full_path = "/#{options[:path_prefix]}#{path}"
|
||||||
name_prefix = options[:name_prefix]
|
name_prefix = options[:name_prefix]
|
||||||
shallow_prefix = "#{options[:name_prefix] unless options[:shallow]}"
|
shallow_prefix = options[:shallow] ? options[:namespace].try(:gsub, /\//, '_') : options[:name_prefix]
|
||||||
|
|
||||||
new_action = "new"
|
new_action = "new"
|
||||||
edit_action = "edit"
|
edit_action = "edit"
|
||||||
|
|
|
@ -219,7 +219,7 @@ class DynamicSegmentTest < Test::Unit::TestCase
|
||||||
a_value = nil
|
a_value = nil
|
||||||
|
|
||||||
# Local jump because of return inside eval.
|
# Local jump because of return inside eval.
|
||||||
assert_raises(LocalJumpError) { eval(segment.extraction_code) }
|
assert_raise(LocalJumpError) { eval(segment.extraction_code) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_extraction_code_should_return_on_mismatch
|
def test_extraction_code_should_return_on_mismatch
|
||||||
|
@ -229,7 +229,7 @@ class DynamicSegmentTest < Test::Unit::TestCase
|
||||||
a_value = nil
|
a_value = nil
|
||||||
|
|
||||||
# Local jump because of return inside eval.
|
# Local jump because of return inside eval.
|
||||||
assert_raises(LocalJumpError) { eval(segment.extraction_code) }
|
assert_raise(LocalJumpError) { eval(segment.extraction_code) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_extraction_code_should_accept_value_and_set_local
|
def test_extraction_code_should_accept_value_and_set_local
|
||||||
|
@ -494,7 +494,7 @@ class RouteBuilderTest < Test::Unit::TestCase
|
||||||
defaults = {:action => 'buy', :person => nil, :car => nil}
|
defaults = {:action => 'buy', :person => nil, :car => nil}
|
||||||
requirements = {:person => /\w+/, :car => /^\w+$/}
|
requirements = {:person => /\w+/, :car => /^\w+$/}
|
||||||
|
|
||||||
assert_raises ArgumentError do
|
assert_raise ArgumentError do
|
||||||
route_requirements = builder.assign_route_options(segments, defaults, requirements)
|
route_requirements = builder.assign_route_options(segments, defaults, requirements)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -882,7 +882,7 @@ class LegacyRouteSetTests < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
assert_equal({:controller => "admin/accounts", :action => "index"}, rs.recognize_path("/admin/accounts"))
|
assert_equal({:controller => "admin/accounts", :action => "index"}, rs.recognize_path("/admin/accounts"))
|
||||||
assert_equal({:controller => "admin/users", :action => "index"}, rs.recognize_path("/admin/users"))
|
assert_equal({:controller => "admin/users", :action => "index"}, rs.recognize_path("/admin/users"))
|
||||||
assert_raises(ActionController::RoutingError) { rs.recognize_path("/admin/products") }
|
assert_raise(ActionController::RoutingError) { rs.recognize_path("/admin/products") }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_route_with_regexp_and_dot
|
def test_route_with_regexp_and_dot
|
||||||
|
@ -955,6 +955,13 @@ class LegacyRouteSetTests < Test::Unit::TestCase
|
||||||
x.send(:page_url))
|
x.send(:page_url))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_named_route_with_blank_path_prefix
|
||||||
|
rs.add_named_route :page, 'page', :controller => 'content', :action => 'show_page', :path_prefix => ''
|
||||||
|
x = setup_for_named_route
|
||||||
|
assert_equal("http://test.host/page",
|
||||||
|
x.send(:page_url))
|
||||||
|
end
|
||||||
|
|
||||||
def test_named_route_with_nested_controller
|
def test_named_route_with_nested_controller
|
||||||
rs.add_named_route :users, 'admin/user', :controller => 'admin/user', :action => 'index'
|
rs.add_named_route :users, 'admin/user', :controller => 'admin/user', :action => 'index'
|
||||||
x = setup_for_named_route
|
x = setup_for_named_route
|
||||||
|
@ -1060,11 +1067,11 @@ class LegacyRouteSetTests < Test::Unit::TestCase
|
||||||
rs.draw do |map|
|
rs.draw do |map|
|
||||||
map.connect ':controller/:action/:id'
|
map.connect ':controller/:action/:id'
|
||||||
end
|
end
|
||||||
assert_raises(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") }
|
assert_raise(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_paths_do_not_accept_defaults
|
def test_paths_do_not_accept_defaults
|
||||||
assert_raises(ActionController::RoutingError) do
|
assert_raise(ActionController::RoutingError) do
|
||||||
rs.draw do |map|
|
rs.draw do |map|
|
||||||
map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => %w(fake default)
|
map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => %w(fake default)
|
||||||
map.connect ':controller/:action/:id'
|
map.connect ':controller/:action/:id'
|
||||||
|
@ -1197,7 +1204,7 @@ class LegacyRouteSetTests < Test::Unit::TestCase
|
||||||
|
|
||||||
assert_equal '/post/10', rs.generate(:controller => 'post', :action => 'show', :id => 10)
|
assert_equal '/post/10', rs.generate(:controller => 'post', :action => 'show', :id => 10)
|
||||||
|
|
||||||
assert_raises ActionController::RoutingError do
|
assert_raise ActionController::RoutingError do
|
||||||
rs.generate(:controller => 'post', :action => 'show')
|
rs.generate(:controller => 'post', :action => 'show')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1407,7 +1414,7 @@ class LegacyRouteSetTests < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
x = setup_for_named_route
|
x = setup_for_named_route
|
||||||
assert_raises(ActionController::RoutingError) do
|
assert_raise(ActionController::RoutingError) do
|
||||||
x.send(:foo_with_requirement_url, "I am Against the requirements")
|
x.send(:foo_with_requirement_url, "I am Against the requirements")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1539,7 +1546,7 @@ class RouteTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_builder_complains_without_controller
|
def test_builder_complains_without_controller
|
||||||
assert_raises(ArgumentError) do
|
assert_raise(ArgumentError) do
|
||||||
ROUTING::RouteBuilder.new.build '/contact', :contoller => "contact", :action => "index"
|
ROUTING::RouteBuilder.new.build '/contact', :contoller => "contact", :action => "index"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1822,27 +1829,27 @@ class RouteSetTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_route_requirements_with_anchor_chars_are_invalid
|
def test_route_requirements_with_anchor_chars_are_invalid
|
||||||
assert_raises ArgumentError do
|
assert_raise ArgumentError do
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /^\d+/
|
map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /^\d+/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
assert_raises ArgumentError do
|
assert_raise ArgumentError do
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\A\d+/
|
map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\A\d+/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
assert_raises ArgumentError do
|
assert_raise ArgumentError do
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+$/
|
map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+$/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
assert_raises ArgumentError do
|
assert_raise ArgumentError do
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\Z/
|
map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\Z/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
assert_raises ArgumentError do
|
assert_raise ArgumentError do
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\z/
|
map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\z/
|
||||||
end
|
end
|
||||||
|
@ -1851,22 +1858,30 @@ class RouteSetTest < Test::Unit::TestCase
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/, :name => /^(david|jamis)/
|
map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/, :name => /^(david|jamis)/
|
||||||
end
|
end
|
||||||
assert_raises ActionController::RoutingError do
|
assert_raise ActionController::RoutingError do
|
||||||
set.generate :controller => 'pages', :action => 'show', :id => 10
|
set.generate :controller => 'pages', :action => 'show', :id => 10
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_route_requirements_with_invalid_http_method_is_invalid
|
def test_route_requirements_with_invalid_http_method_is_invalid
|
||||||
assert_raises ArgumentError do
|
assert_raise ArgumentError do
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
map.connect 'valid/route', :controller => 'pages', :action => 'show', :conditions => {:method => :invalid}
|
map.connect 'valid/route', :controller => 'pages', :action => 'show', :conditions => {:method => :invalid}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_route_requirements_with_options_method_condition_is_valid
|
||||||
|
assert_nothing_raised do
|
||||||
|
set.draw do |map|
|
||||||
|
map.connect 'valid/route', :controller => 'pages', :action => 'show', :conditions => {:method => :options}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_route_requirements_with_head_method_condition_is_invalid
|
def test_route_requirements_with_head_method_condition_is_invalid
|
||||||
assert_raises ArgumentError do
|
assert_raise ArgumentError do
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
map.connect 'valid/route', :controller => 'pages', :action => 'show', :conditions => {:method => :head}
|
map.connect 'valid/route', :controller => 'pages', :action => 'show', :conditions => {:method => :head}
|
||||||
end
|
end
|
||||||
|
@ -1878,10 +1893,10 @@ class RouteSetTest < Test::Unit::TestCase
|
||||||
map.connect 'page/37s', :controller => 'pages', :action => 'show', :name => /(jamis|david)/
|
map.connect 'page/37s', :controller => 'pages', :action => 'show', :name => /(jamis|david)/
|
||||||
end
|
end
|
||||||
assert_equal '/page/37s', set.generate(:controller => 'pages', :action => 'show', :name => 'jamis')
|
assert_equal '/page/37s', set.generate(:controller => 'pages', :action => 'show', :name => 'jamis')
|
||||||
assert_raises ActionController::RoutingError do
|
assert_raise ActionController::RoutingError do
|
||||||
set.generate(:controller => 'pages', :action => 'show', :name => 'not_jamis')
|
set.generate(:controller => 'pages', :action => 'show', :name => 'not_jamis')
|
||||||
end
|
end
|
||||||
assert_raises ActionController::RoutingError do
|
assert_raise ActionController::RoutingError do
|
||||||
set.generate(:controller => 'pages', :action => 'show', :name => 'nor_jamis_and_david')
|
set.generate(:controller => 'pages', :action => 'show', :name => 'nor_jamis_and_david')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1924,7 +1939,7 @@ class RouteSetTest < Test::Unit::TestCase
|
||||||
assert_equal("update", request.path_parameters[:action])
|
assert_equal("update", request.path_parameters[:action])
|
||||||
request.recycle!
|
request.recycle!
|
||||||
|
|
||||||
assert_raises(ActionController::UnknownHttpMethod) {
|
assert_raise(ActionController::UnknownHttpMethod) {
|
||||||
request.env["REQUEST_METHOD"] = "BACON"
|
request.env["REQUEST_METHOD"] = "BACON"
|
||||||
set.recognize(request)
|
set.recognize(request)
|
||||||
}
|
}
|
||||||
|
@ -2122,11 +2137,9 @@ class RouteSetTest < Test::Unit::TestCase
|
||||||
Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
|
Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
|
||||||
|
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
|
|
||||||
map.namespace 'api', :path_prefix => 'prefix' do |api|
|
map.namespace 'api', :path_prefix => 'prefix' do |api|
|
||||||
api.route 'inventory', :controller => "products", :action => 'inventory'
|
api.route 'inventory', :controller => "products", :action => 'inventory'
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
request.path = "/prefix/inventory"
|
request.path = "/prefix/inventory"
|
||||||
|
@ -2138,6 +2151,24 @@ class RouteSetTest < Test::Unit::TestCase
|
||||||
Object.send(:remove_const, :Api)
|
Object.send(:remove_const, :Api)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_namespace_with_blank_path_prefix
|
||||||
|
Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
|
||||||
|
|
||||||
|
set.draw do |map|
|
||||||
|
map.namespace 'api', :path_prefix => '' do |api|
|
||||||
|
api.route 'inventory', :controller => "products", :action => 'inventory'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
request.path = "/inventory"
|
||||||
|
request.env["REQUEST_METHOD"] = "GET"
|
||||||
|
assert_nothing_raised { set.recognize(request) }
|
||||||
|
assert_equal("api/products", request.path_parameters[:controller])
|
||||||
|
assert_equal("inventory", request.path_parameters[:action])
|
||||||
|
ensure
|
||||||
|
Object.send(:remove_const, :Api)
|
||||||
|
end
|
||||||
|
|
||||||
def test_generate_finds_best_fit
|
def test_generate_finds_best_fit
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
map.connect "/people", :controller => "people", :action => "index"
|
map.connect "/people", :controller => "people", :action => "index"
|
||||||
|
@ -2202,6 +2233,13 @@ class RouteSetTest < Test::Unit::TestCase
|
||||||
assert_equal "/my/foo/bar/7?x=y", set.generate(args)
|
assert_equal "/my/foo/bar/7?x=y", set.generate(args)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_generate_with_blank_path_prefix
|
||||||
|
set.draw { |map| map.connect ':controller/:action/:id', :path_prefix => '' }
|
||||||
|
|
||||||
|
args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
|
||||||
|
assert_equal "/foo/bar/7?x=y", set.generate(args)
|
||||||
|
end
|
||||||
|
|
||||||
def test_named_routes_are_never_relative_to_modules
|
def test_named_routes_are_never_relative_to_modules
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
map.connect "/connection/manage/:action", :controller => 'connection/manage'
|
map.connect "/connection/manage/:action", :controller => 'connection/manage'
|
||||||
|
@ -2309,7 +2347,7 @@ class RouteSetTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_route_requirements_with_unsupported_regexp_options_must_error
|
def test_route_requirements_with_unsupported_regexp_options_must_error
|
||||||
assert_raises ArgumentError do
|
assert_raise ArgumentError do
|
||||||
set.draw do |map|
|
set.draw do |map|
|
||||||
map.connect 'page/:name', :controller => 'pages',
|
map.connect 'page/:name', :controller => 'pages',
|
||||||
:action => 'show',
|
:action => 'show',
|
||||||
|
@ -2347,7 +2385,7 @@ class RouteSetTest < Test::Unit::TestCase
|
||||||
:requirements => {:name => /(david|jamis)/i}
|
:requirements => {:name => /(david|jamis)/i}
|
||||||
end
|
end
|
||||||
assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
|
assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
|
||||||
assert_raises ActionController::RoutingError do
|
assert_raise ActionController::RoutingError do
|
||||||
set.recognize_path('/page/davidjamis')
|
set.recognize_path('/page/davidjamis')
|
||||||
end
|
end
|
||||||
assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID'))
|
assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID'))
|
||||||
|
@ -2361,7 +2399,7 @@ class RouteSetTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
|
url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
|
||||||
assert_equal "/page/david", url
|
assert_equal "/page/david", url
|
||||||
assert_raises ActionController::RoutingError do
|
assert_raise ActionController::RoutingError do
|
||||||
url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
|
url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
|
||||||
end
|
end
|
||||||
url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
|
url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
|
||||||
|
@ -2381,10 +2419,10 @@ class RouteSetTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
|
assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
|
||||||
assert_equal({:controller => 'pages', :action => 'show', :name => 'david'}, set.recognize_path('/page/david'))
|
assert_equal({:controller => 'pages', :action => 'show', :name => 'david'}, set.recognize_path('/page/david'))
|
||||||
assert_raises ActionController::RoutingError do
|
assert_raise ActionController::RoutingError do
|
||||||
set.recognize_path('/page/david #The Creator')
|
set.recognize_path('/page/david #The Creator')
|
||||||
end
|
end
|
||||||
assert_raises ActionController::RoutingError do
|
assert_raise ActionController::RoutingError do
|
||||||
set.recognize_path('/page/David')
|
set.recognize_path('/page/David')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2402,10 +2440,10 @@ class RouteSetTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
|
url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
|
||||||
assert_equal "/page/david", url
|
assert_equal "/page/david", url
|
||||||
assert_raises ActionController::RoutingError do
|
assert_raise ActionController::RoutingError do
|
||||||
url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
|
url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
|
||||||
end
|
end
|
||||||
assert_raises ActionController::RoutingError do
|
assert_raise ActionController::RoutingError do
|
||||||
url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
|
url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -303,7 +303,7 @@ class SelectorTest < Test::Unit::TestCase
|
||||||
assert_equal 1, @matches.size
|
assert_equal 1, @matches.size
|
||||||
assert_equal "2", @matches[0].attributes["id"]
|
assert_equal "2", @matches[0].attributes["id"]
|
||||||
# Before first and past last returns nothing.:
|
# Before first and past last returns nothing.:
|
||||||
assert_raises(ArgumentError) { select("tr:nth-child(-1)") }
|
assert_raise(ArgumentError) { select("tr:nth-child(-1)") }
|
||||||
select("tr:nth-child(0)")
|
select("tr:nth-child(0)")
|
||||||
assert_equal 0, @matches.size
|
assert_equal 0, @matches.size
|
||||||
select("tr:nth-child(5)")
|
select("tr:nth-child(5)")
|
||||||
|
@ -597,8 +597,8 @@ class SelectorTest < Test::Unit::TestCase
|
||||||
|
|
||||||
def test_negation_details
|
def test_negation_details
|
||||||
parse(%Q{<p id="1"></p><p id="2"></p><p id="3"></p>})
|
parse(%Q{<p id="1"></p><p id="2"></p><p id="3"></p>})
|
||||||
assert_raises(ArgumentError) { select(":not(") }
|
assert_raise(ArgumentError) { select(":not(") }
|
||||||
assert_raises(ArgumentError) { select(":not(:not())") }
|
assert_raise(ArgumentError) { select(":not(:not())") }
|
||||||
select("p:not(#1):not(#3)")
|
select("p:not(#1):not(#3)")
|
||||||
assert_equal 1, @matches.size
|
assert_equal 1, @matches.size
|
||||||
assert_equal "2", @matches[0].attributes["id"]
|
assert_equal "2", @matches[0].attributes["id"]
|
||||||
|
|
|
@ -142,7 +142,7 @@ class SendFileTest < ActionController::TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
@controller.headers = {}
|
@controller.headers = {}
|
||||||
assert_raises(ArgumentError){ @controller.send(:send_file_headers!, options) }
|
assert_raise(ArgumentError){ @controller.send(:send_file_headers!, options) }
|
||||||
end
|
end
|
||||||
|
|
||||||
%w(file data).each do |method|
|
%w(file data).each do |method|
|
||||||
|
|
|
@ -199,29 +199,18 @@ class CookieStoreTest < ActionController::IntegrationTest
|
||||||
|
|
||||||
with_test_route_set do
|
with_test_route_set do
|
||||||
# First request accesses the session
|
# First request accesses the session
|
||||||
time = Time.local(2008, 4, 24)
|
|
||||||
Time.stubs(:now).returns(time)
|
|
||||||
expected_expiry = (time + 5.hours).gmtime.strftime("%a, %d-%b-%Y %H:%M:%S GMT")
|
|
||||||
|
|
||||||
cookies[SessionKey] = SignedBar
|
cookies[SessionKey] = SignedBar
|
||||||
|
|
||||||
get '/set_session_value'
|
get '/set_session_value'
|
||||||
assert_response :success
|
assert_response :success
|
||||||
|
cookie = headers['Set-Cookie']
|
||||||
|
|
||||||
cookie_body = response.body
|
# Second request does not access the session so the
|
||||||
assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly",
|
# expires header should not be changed
|
||||||
headers['Set-Cookie']
|
|
||||||
|
|
||||||
# Second request does not access the session
|
|
||||||
time = Time.local(2008, 4, 25)
|
|
||||||
Time.stubs(:now).returns(time)
|
|
||||||
expected_expiry = (time + 5.hours).gmtime.strftime("%a, %d-%b-%Y %H:%M:%S GMT")
|
|
||||||
|
|
||||||
get '/no_session_access'
|
get '/no_session_access'
|
||||||
assert_response :success
|
assert_response :success
|
||||||
|
assert_equal cookie, headers['Set-Cookie'],
|
||||||
assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly",
|
"#{unmarshal_session(cookie).inspect} expected but was #{unmarshal_session(headers['Set-Cookie']).inspect}"
|
||||||
headers['Set-Cookie']
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -236,4 +225,13 @@ class CookieStoreTest < ActionController::IntegrationTest
|
||||||
yield
|
yield
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unmarshal_session(cookie_string)
|
||||||
|
session = Rack::Utils.parse_query(cookie_string, ';,').inject({}) {|h,(k,v)|
|
||||||
|
h[k] = Array === v ? v.first : v
|
||||||
|
h
|
||||||
|
}[SessionKey]
|
||||||
|
verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1')
|
||||||
|
verifier.verify(session)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,11 +17,14 @@ class MemCacheStoreTest < ActionController::IntegrationTest
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_session_id
|
def get_session_id
|
||||||
render :text => "foo: #{session[:foo].inspect}; id: #{request.session_options[:id]}"
|
session[:foo]
|
||||||
|
render :text => "#{request.session_options[:id]}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def call_reset_session
|
def call_reset_session
|
||||||
|
session[:bar]
|
||||||
reset_session
|
reset_session
|
||||||
|
session[:bar] = "baz"
|
||||||
head :ok
|
head :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -58,6 +61,27 @@ class MemCacheStoreTest < ActionController::IntegrationTest
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_setting_session_value_after_session_reset
|
||||||
|
with_test_route_set do
|
||||||
|
get '/set_session_value'
|
||||||
|
assert_response :success
|
||||||
|
assert cookies['_session_id']
|
||||||
|
session_id = cookies['_session_id']
|
||||||
|
|
||||||
|
get '/call_reset_session'
|
||||||
|
assert_response :success
|
||||||
|
assert_not_equal [], headers['Set-Cookie']
|
||||||
|
|
||||||
|
get '/get_session_value'
|
||||||
|
assert_response :success
|
||||||
|
assert_equal 'foo: nil', response.body
|
||||||
|
|
||||||
|
get '/get_session_id'
|
||||||
|
assert_response :success
|
||||||
|
assert_not_equal session_id, response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_getting_session_id
|
def test_getting_session_id
|
||||||
with_test_route_set do
|
with_test_route_set do
|
||||||
get '/set_session_value'
|
get '/set_session_value'
|
||||||
|
@ -67,7 +91,7 @@ class MemCacheStoreTest < ActionController::IntegrationTest
|
||||||
|
|
||||||
get '/get_session_id'
|
get '/get_session_id'
|
||||||
assert_response :success
|
assert_response :success
|
||||||
assert_equal "foo: \"bar\"; id: #{session_id}", response.body
|
assert_equal session_id, response.body
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -85,22 +109,6 @@ class MemCacheStoreTest < ActionController::IntegrationTest
|
||||||
assert_equal nil, cookies['_session_id']
|
assert_equal nil, cookies['_session_id']
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_setting_session_value_after_session_reset
|
|
||||||
with_test_route_set do
|
|
||||||
get '/set_session_value'
|
|
||||||
assert_response :success
|
|
||||||
assert cookies['_session_id']
|
|
||||||
|
|
||||||
get '/call_reset_session'
|
|
||||||
assert_response :success
|
|
||||||
assert_not_equal [], headers['Set-Cookie']
|
|
||||||
|
|
||||||
get '/get_session_value'
|
|
||||||
assert_response :success
|
|
||||||
assert_equal 'foo: nil', response.body
|
|
||||||
end
|
|
||||||
end
|
|
||||||
rescue LoadError, RuntimeError
|
rescue LoadError, RuntimeError
|
||||||
$stderr.puts "Skipping MemCacheStoreTest tests. Start memcached and try again."
|
$stderr.puts "Skipping MemCacheStoreTest tests. Start memcached and try again."
|
||||||
end
|
end
|
||||||
|
|
|
@ -99,7 +99,7 @@ class UrlWriterTests < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_exception_is_thrown_without_host
|
def test_exception_is_thrown_without_host
|
||||||
assert_raises RuntimeError do
|
assert_raise RuntimeError do
|
||||||
W.new.url_for :controller => 'c', :action => 'a', :id => 'i'
|
W.new.url_for :controller => 'c', :action => 'a', :id => 'i'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
1
vendor/rails/actionpack/test/fixtures/layouts/default_html.html.erb
vendored
Normal file
1
vendor/rails/actionpack/test/fixtures/layouts/default_html.html.erb
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<html><%= @content_for_layout %></html>
|
1
vendor/rails/actionpack/test/fixtures/quiz/questions/_question.html.erb
vendored
Normal file
1
vendor/rails/actionpack/test/fixtures/quiz/questions/_question.html.erb
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<%= question.name %>
|
|
@ -19,6 +19,30 @@ class ActiveRecordHelperTest < ActionView::TestCase
|
||||||
Column = Struct.new("Column", :type, :name, :human_name)
|
Column = Struct.new("Column", :type, :name, :human_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class DirtyPost
|
||||||
|
class Errors
|
||||||
|
def empty?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def count
|
||||||
|
1
|
||||||
|
end
|
||||||
|
|
||||||
|
def full_messages
|
||||||
|
["Author name can't be <em>empty</em>"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def on(field)
|
||||||
|
"can't be <em>empty</em>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def errors
|
||||||
|
Errors.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def setup_post
|
def setup_post
|
||||||
@post = Post.new
|
@post = Post.new
|
||||||
def @post.errors
|
def @post.errors
|
||||||
|
@ -195,10 +219,20 @@ class ActiveRecordHelperTest < ActionView::TestCase
|
||||||
assert_equal %(<div class="errorDeathByClass"><h1>1 error prohibited this post from being saved</h1><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>), error_messages_for("post", :class => "errorDeathByClass", :id => nil, :header_tag => "h1")
|
assert_equal %(<div class="errorDeathByClass"><h1>1 error prohibited this post from being saved</h1><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>), error_messages_for("post", :class => "errorDeathByClass", :id => nil, :header_tag => "h1")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_error_messages_for_escapes_html
|
||||||
|
@dirty_post = DirtyPost.new
|
||||||
|
assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this dirty post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be <em>empty</em></li></ul></div>), error_messages_for("dirty_post")
|
||||||
|
end
|
||||||
|
|
||||||
def test_error_messages_for_handles_nil
|
def test_error_messages_for_handles_nil
|
||||||
assert_equal "", error_messages_for("notthere")
|
assert_equal "", error_messages_for("notthere")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_error_message_on_escapes_html
|
||||||
|
@dirty_post = DirtyPost.new
|
||||||
|
assert_dom_equal "<div class=\"formError\">can't be <em>empty</em></div>", error_message_on(:dirty_post, :author_name)
|
||||||
|
end
|
||||||
|
|
||||||
def test_error_message_on_handles_nil
|
def test_error_message_on_handles_nil
|
||||||
assert_equal "", error_message_on("notthere", "notthere")
|
assert_equal "", error_message_on("notthere", "notthere")
|
||||||
end
|
end
|
||||||
|
|
|
@ -266,11 +266,18 @@ class FormTagHelperTest < ActionView::TestCase
|
||||||
|
|
||||||
def test_submit_tag_with_confirmation
|
def test_submit_tag_with_confirmation
|
||||||
assert_dom_equal(
|
assert_dom_equal(
|
||||||
%(<input name='commit' type='submit' value='Save' onclick="return confirm('Are you sure?');"/>),
|
%(<input name='commit' type='submit' value='Save' onclick="if (!confirm('Are you sure?')) return false; return true;"/>),
|
||||||
submit_tag("Save", :confirm => "Are you sure?")
|
submit_tag("Save", :confirm => "Are you sure?")
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_submit_tag_with_confirmation_and_with_disable_with
|
||||||
|
assert_dom_equal(
|
||||||
|
%(<input name="commit" type="submit" value="Save" onclick="if (!confirm('Are you sure?')) return false; if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = this.cloneNode(false);hiddenCommit.setAttribute('type', 'hidden');this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" />),
|
||||||
|
submit_tag("Save", :disable_with => "Saving...", :confirm => "Are you sure?")
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def test_image_submit_tag_with_confirmation
|
def test_image_submit_tag_with_confirmation
|
||||||
assert_dom_equal(
|
assert_dom_equal(
|
||||||
%(<input type="image" src="/images/save.gif" onclick="return confirm('Are you sure?');"/>),
|
%(<input type="image" src="/images/save.gif" onclick="return confirm('Are you sure?');"/>),
|
||||||
|
|
|
@ -45,11 +45,6 @@ class JavaScriptHelperTest < ActionView::TestCase
|
||||||
link_to_function("Greeting", "alert('Hello world!')", :href => 'http://example.com/')
|
link_to_function("Greeting", "alert('Hello world!')", :href => 'http://example.com/')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_link_to_function_with_href
|
|
||||||
assert_dom_equal %(<a href="http://example.com/" onclick="alert('Hello world!'); return false;">Greeting</a>),
|
|
||||||
link_to_function("Greeting", "alert('Hello world!')", :href => 'http://example.com/')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_button_to_function
|
def test_button_to_function
|
||||||
assert_dom_equal %(<input type="button" onclick="alert('Hello world!');" value="Greeting" />),
|
assert_dom_equal %(<input type="button" onclick="alert('Hello world!');" value="Greeting" />),
|
||||||
button_to_function("Greeting", "alert('Hello world!')")
|
button_to_function("Greeting", "alert('Hello world!')")
|
||||||
|
|
|
@ -4,6 +4,7 @@ class NumberHelperTest < ActionView::TestCase
|
||||||
tests ActionView::Helpers::NumberHelper
|
tests ActionView::Helpers::NumberHelper
|
||||||
|
|
||||||
def test_number_to_phone
|
def test_number_to_phone
|
||||||
|
assert_equal("555-1234", number_to_phone(5551234))
|
||||||
assert_equal("800-555-1212", number_to_phone(8005551212))
|
assert_equal("800-555-1212", number_to_phone(8005551212))
|
||||||
assert_equal("(800) 555-1212", number_to_phone(8005551212, {:area_code => true}))
|
assert_equal("(800) 555-1212", number_to_phone(8005551212, {:area_code => true}))
|
||||||
assert_equal("800 555 1212", number_to_phone(8005551212, {:delimiter => " "}))
|
assert_equal("800 555 1212", number_to_phone(8005551212, {:delimiter => " "}))
|
||||||
|
|
|
@ -145,6 +145,10 @@ module RenderTestCases
|
||||||
assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name
|
assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_render_object
|
||||||
|
assert_equal "Hello: david", @view.render(:partial => "test/customer", :object => Customer.new("david"))
|
||||||
|
end
|
||||||
|
|
||||||
def test_render_partial_collection
|
def test_render_partial_collection
|
||||||
assert_equal "Hello: davidHello: mary", @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), Customer.new("mary") ])
|
assert_equal "Hello: davidHello: mary", @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), Customer.new("mary") ])
|
||||||
end
|
end
|
||||||
|
|
|
@ -375,6 +375,12 @@ class TextHelperTest < ActionView::TestCase
|
||||||
assert_equal "{link: #{link3_result}}", auto_link("{link: #{link3_raw}}")
|
assert_equal "{link: #{link3_result}}", auto_link("{link: #{link3_raw}}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_auto_link_in_tags
|
||||||
|
link_raw = 'http://www.rubyonrails.org/images/rails.png'
|
||||||
|
link_result = %Q(<img src="#{link_raw}" />)
|
||||||
|
assert_equal link_result, auto_link(link_result)
|
||||||
|
end
|
||||||
|
|
||||||
def test_auto_link_at_eol
|
def test_auto_link_at_eol
|
||||||
url1 = "http://api.rubyonrails.com/Foo.html"
|
url1 = "http://api.rubyonrails.com/Foo.html"
|
||||||
url2 = "http://www.ruby-doc.org/core/Bar.html"
|
url2 = "http://www.ruby-doc.org/core/Bar.html"
|
||||||
|
|
|
@ -220,7 +220,7 @@ class UrlHelperTest < ActionView::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_link_tag_using_post_javascript_and_popup
|
def test_link_tag_using_post_javascript_and_popup
|
||||||
assert_raises(ActionView::ActionViewError) { link_to("Hello", "http://www.example.com", :popup => true, :method => :post, :confirm => "Are you serious?") }
|
assert_raise(ActionView::ActionViewError) { link_to("Hello", "http://www.example.com", :popup => true, :method => :post, :confirm => "Are you serious?") }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_link_tag_using_block_in_erb
|
def test_link_tag_using_block_in_erb
|
||||||
|
|
|
@ -4,7 +4,7 @@ module ActiveModel
|
||||||
# Validates whether the value of the specified attribute is available in a particular enumerable object.
|
# Validates whether the value of the specified attribute is available in a particular enumerable object.
|
||||||
#
|
#
|
||||||
# class Person < ActiveRecord::Base
|
# class Person < ActiveRecord::Base
|
||||||
# validates_inclusion_of :gender, :in => %w( m f ), :message => "woah! what are you then!??!!"
|
# validates_inclusion_of :gender, :in => %w( m f )
|
||||||
# validates_inclusion_of :age, :in => 0..99
|
# validates_inclusion_of :age, :in => 0..99
|
||||||
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %s is not included in the list"
|
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %s is not included in the list"
|
||||||
# end
|
# end
|
||||||
|
|
|
@ -31,7 +31,7 @@ class EventBeingFiredTest < ActiveModel::TestCase
|
||||||
test 'should raise an AASM::InvalidTransition error if the transitions are empty' do
|
test 'should raise an AASM::InvalidTransition error if the transitions are empty' do
|
||||||
event = ActiveModel::StateMachine::Event.new(nil, :event)
|
event = ActiveModel::StateMachine::Event.new(nil, :event)
|
||||||
|
|
||||||
assert_raises ActiveModel::StateMachine::InvalidTransition do
|
assert_raise ActiveModel::StateMachine::InvalidTransition do
|
||||||
event.fire(nil)
|
event.fire(nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
7
vendor/rails/activerecord/CHANGELOG
vendored
7
vendor/rails/activerecord/CHANGELOG
vendored
|
@ -1,12 +1,9 @@
|
||||||
*2.3.1 [RC2] (March 5, 2009)*
|
*2.3.2 [Final] (March 15, 2009)*
|
||||||
|
|
||||||
* Added ActiveRecord::Base.each and ActiveRecord::Base.find_in_batches for batch processing [DHH/Jamis Buck]
|
* Added ActiveRecord::Base.find_each and ActiveRecord::Base.find_in_batches for batch processing [DHH/Jamis Buck]
|
||||||
|
|
||||||
* Added that ActiveRecord::Base.exists? can be called with no arguments #1817 [Scott Taylor]
|
* Added that ActiveRecord::Base.exists? can be called with no arguments #1817 [Scott Taylor]
|
||||||
|
|
||||||
|
|
||||||
*2.3.0 [RC1] (February 1st, 2009)*
|
|
||||||
|
|
||||||
* Add Support for updating deeply nested models from a single form. #1202 [Eloy Duran]
|
* Add Support for updating deeply nested models from a single form. #1202 [Eloy Duran]
|
||||||
|
|
||||||
class Book < ActiveRecord::Base
|
class Book < ActiveRecord::Base
|
||||||
|
|
2
vendor/rails/activerecord/Rakefile
vendored
2
vendor/rails/activerecord/Rakefile
vendored
|
@ -177,7 +177,7 @@ spec = Gem::Specification.new do |s|
|
||||||
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
||||||
end
|
end
|
||||||
|
|
||||||
s.add_dependency('activesupport', '= 2.3.1' + PKG_BUILD)
|
s.add_dependency('activesupport', '= 2.3.2' + PKG_BUILD)
|
||||||
|
|
||||||
s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite"
|
s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite"
|
||||||
s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite"
|
s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite"
|
||||||
|
|
|
@ -51,6 +51,12 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class HasAndBelongsToManyAssociationForeignKeyNeeded < ActiveRecordError #:nodoc:
|
||||||
|
def initialize(reflection)
|
||||||
|
super("Cannot create self referential has_and_belongs_to_many association on '#{reflection.class_name rescue nil}##{reflection.name rescue nil}'. :association_foreign_key cannot be the same as the :foreign_key.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class EagerLoadPolymorphicError < ActiveRecordError #:nodoc:
|
class EagerLoadPolymorphicError < ActiveRecordError #:nodoc:
|
||||||
def initialize(reflection)
|
def initialize(reflection)
|
||||||
super("Can not eagerly load the polymorphic association #{reflection.name.inspect}")
|
super("Can not eagerly load the polymorphic association #{reflection.name.inspect}")
|
||||||
|
@ -65,7 +71,7 @@ module ActiveRecord
|
||||||
|
|
||||||
# See ActiveRecord::Associations::ClassMethods for documentation.
|
# See ActiveRecord::Associations::ClassMethods for documentation.
|
||||||
module Associations # :nodoc:
|
module Associations # :nodoc:
|
||||||
# These classes will be loaded when associatoins are created.
|
# These classes will be loaded when associations are created.
|
||||||
# So there is no need to eager load them.
|
# So there is no need to eager load them.
|
||||||
autoload :AssociationCollection, 'active_record/associations/association_collection'
|
autoload :AssociationCollection, 'active_record/associations/association_collection'
|
||||||
autoload :AssociationProxy, 'active_record/associations/association_proxy'
|
autoload :AssociationProxy, 'active_record/associations/association_proxy'
|
||||||
|
@ -997,9 +1003,7 @@ module ActiveRecord
|
||||||
|
|
||||||
# Create the callbacks to update counter cache
|
# Create the callbacks to update counter cache
|
||||||
if options[:counter_cache]
|
if options[:counter_cache]
|
||||||
cache_column = options[:counter_cache] == true ?
|
cache_column = reflection.counter_cache_column
|
||||||
"#{self.to_s.demodulize.underscore.pluralize}_count" :
|
|
||||||
options[:counter_cache]
|
|
||||||
|
|
||||||
method_name = "belongs_to_counter_cache_after_create_for_#{reflection.name}".to_sym
|
method_name = "belongs_to_counter_cache_after_create_for_#{reflection.name}".to_sym
|
||||||
define_method(method_name) do
|
define_method(method_name) do
|
||||||
|
@ -1526,6 +1530,10 @@ module ActiveRecord
|
||||||
options[:extend] = create_extension_modules(association_id, extension, options[:extend])
|
options[:extend] = create_extension_modules(association_id, extension, options[:extend])
|
||||||
|
|
||||||
reflection = create_reflection(:has_and_belongs_to_many, association_id, options, self)
|
reflection = create_reflection(:has_and_belongs_to_many, association_id, options, self)
|
||||||
|
|
||||||
|
if reflection.association_foreign_key == reflection.primary_key_name
|
||||||
|
raise HasAndBelongsToManyAssociationForeignKeyNeeded.new(reflection)
|
||||||
|
end
|
||||||
|
|
||||||
reflection.options[:join_table] ||= join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(reflection.class_name))
|
reflection.options[:join_table] ||= join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(reflection.class_name))
|
||||||
|
|
||||||
|
@ -1848,9 +1856,10 @@ module ActiveRecord
|
||||||
def construct(parent, associations, joins, row)
|
def construct(parent, associations, joins, row)
|
||||||
case associations
|
case associations
|
||||||
when Symbol, String
|
when Symbol, String
|
||||||
while (join = joins.shift).reflection.name.to_s != associations.to_s
|
join = joins.detect{|j| j.reflection.name.to_s == associations.to_s && j.parent_table_name == parent.class.table_name }
|
||||||
raise ConfigurationError, "Not Enough Associations" if joins.empty?
|
raise(ConfigurationError, "No such association") if join.nil?
|
||||||
end
|
|
||||||
|
joins.delete(join)
|
||||||
construct_association(parent, join, row)
|
construct_association(parent, join, row)
|
||||||
when Array
|
when Array
|
||||||
associations.each do |association|
|
associations.each do |association|
|
||||||
|
@ -1858,7 +1867,11 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
when Hash
|
when Hash
|
||||||
associations.keys.sort{|a,b|a.to_s<=>b.to_s}.each do |name|
|
associations.keys.sort{|a,b|a.to_s<=>b.to_s}.each do |name|
|
||||||
association = construct_association(parent, joins.shift, row)
|
join = joins.detect{|j| j.reflection.name.to_s == name.to_s && j.parent_table_name == parent.class.table_name }
|
||||||
|
raise(ConfigurationError, "No such association") if join.nil?
|
||||||
|
|
||||||
|
association = construct_association(parent, join, row)
|
||||||
|
joins.delete(join)
|
||||||
construct(association, associations[name], joins, row) if association
|
construct(association, associations[name], joins, row) if association
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
|
@ -60,7 +60,7 @@ module ActiveRecord
|
||||||
@reflection.klass.find(*args)
|
@reflection.klass.find(*args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Fetches the first one using SQL if possible.
|
# Fetches the first one using SQL if possible.
|
||||||
def first(*args)
|
def first(*args)
|
||||||
if fetch_first_or_last_using_find?(args)
|
if fetch_first_or_last_using_find?(args)
|
||||||
|
@ -143,6 +143,8 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
# Remove all records from this association
|
# Remove all records from this association
|
||||||
|
#
|
||||||
|
# See delete for more info.
|
||||||
def delete_all
|
def delete_all
|
||||||
load_target
|
load_target
|
||||||
delete(@target)
|
delete(@target)
|
||||||
|
@ -186,7 +188,6 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# Removes +records+ from this association calling +before_remove+ and
|
# Removes +records+ from this association calling +before_remove+ and
|
||||||
# +after_remove+ callbacks.
|
# +after_remove+ callbacks.
|
||||||
#
|
#
|
||||||
|
@ -195,22 +196,25 @@ module ActiveRecord
|
||||||
# are actually removed from the database, that depends precisely on
|
# are actually removed from the database, that depends precisely on
|
||||||
# +delete_records+. They are in any case removed from the collection.
|
# +delete_records+. They are in any case removed from the collection.
|
||||||
def delete(*records)
|
def delete(*records)
|
||||||
records = flatten_deeper(records)
|
remove_records(records) do |records, old_records|
|
||||||
records.each { |record| raise_on_type_mismatch(record) }
|
|
||||||
|
|
||||||
transaction do
|
|
||||||
records.each { |record| callback(:before_remove, record) }
|
|
||||||
|
|
||||||
old_records = records.reject {|r| r.new_record? }
|
|
||||||
delete_records(old_records) if old_records.any?
|
delete_records(old_records) if old_records.any?
|
||||||
|
records.each { |record| @target.delete(record) }
|
||||||
records.each do |record|
|
|
||||||
@target.delete(record)
|
|
||||||
callback(:after_remove, record)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Destroy +records+ and remove them from this association calling
|
||||||
|
# +before_remove+ and +after_remove+ callbacks.
|
||||||
|
#
|
||||||
|
# Note that this method will _always_ remove records from the database
|
||||||
|
# ignoring the +:dependent+ option.
|
||||||
|
def destroy(*records)
|
||||||
|
remove_records(records) do |records, old_records|
|
||||||
|
old_records.each { |record| record.destroy }
|
||||||
|
end
|
||||||
|
|
||||||
|
load_target
|
||||||
|
end
|
||||||
|
|
||||||
# Removes all records from this association. Returns +self+ so method calls may be chained.
|
# Removes all records from this association. Returns +self+ so method calls may be chained.
|
||||||
def clear
|
def clear
|
||||||
return self if length.zero? # forces load_target if it hasn't happened already
|
return self if length.zero? # forces load_target if it hasn't happened already
|
||||||
|
@ -223,15 +227,16 @@ module ActiveRecord
|
||||||
|
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy_all
|
|
||||||
transaction do
|
|
||||||
each { |record| record.destroy }
|
|
||||||
end
|
|
||||||
|
|
||||||
|
# Destory all the records from this association.
|
||||||
|
#
|
||||||
|
# See destroy for more info.
|
||||||
|
def destroy_all
|
||||||
|
load_target
|
||||||
|
destroy(@target)
|
||||||
reset_target!
|
reset_target!
|
||||||
end
|
end
|
||||||
|
|
||||||
def create(attrs = {})
|
def create(attrs = {})
|
||||||
if attrs.is_a?(Array)
|
if attrs.is_a?(Array)
|
||||||
attrs.collect { |attr| create(attr) }
|
attrs.collect { |attr| create(attr) }
|
||||||
|
@ -431,6 +436,18 @@ module ActiveRecord
|
||||||
record
|
record
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remove_records(*records)
|
||||||
|
records = flatten_deeper(records)
|
||||||
|
records.each { |record| raise_on_type_mismatch(record) }
|
||||||
|
|
||||||
|
transaction do
|
||||||
|
records.each { |record| callback(:before_remove, record) }
|
||||||
|
old_records = records.reject { |r| r.new_record? }
|
||||||
|
yield(records, old_records)
|
||||||
|
records.each { |record| callback(:after_remove, record) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def callback(method, record)
|
def callback(method, record)
|
||||||
callbacks_for(method).each do |callback|
|
callbacks_for(method).each do |callback|
|
||||||
ActiveSupport::Callbacks::Callback.new(method, callback, record).call(@owner, record)
|
ActiveSupport::Callbacks::Callback.new(method, callback, record).call(@owner, record)
|
||||||
|
|
|
@ -23,8 +23,8 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been loaded and
|
# Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been loaded and
|
||||||
# calling collection.size if it has. If it's more likely than not that the collection does have a size larger than zero
|
# calling collection.size if it has. If it's more likely than not that the collection does have a size larger than zero,
|
||||||
# and you need to fetch that collection afterwards, it'll take one less SELECT query if you use length.
|
# and you need to fetch that collection afterwards, it'll take one fewer SELECT query if you use #length.
|
||||||
def size
|
def size
|
||||||
return @owner.send(:read_attribute, cached_counter_attribute_name) if has_cached_counter?
|
return @owner.send(:read_attribute, cached_counter_attribute_name) if has_cached_counter?
|
||||||
return @target.size if loaded?
|
return @target.size if loaded?
|
||||||
|
@ -150,7 +150,7 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
reflection_primary_key = @reflection.source_reflection.primary_key_name
|
reflection_primary_key = @reflection.source_reflection.primary_key_name
|
||||||
source_primary_key = @reflection.klass.primary_key
|
source_primary_key = @reflection.through_reflection.klass.primary_key
|
||||||
if @reflection.source_reflection.options[:as]
|
if @reflection.source_reflection.options[:as]
|
||||||
polymorphic_join = "AND %s.%s = %s" % [
|
polymorphic_join = "AND %s.%s = %s" % [
|
||||||
@reflection.quoted_table_name, "#{@reflection.source_reflection.options[:as]}_type",
|
@reflection.quoted_table_name, "#{@reflection.source_reflection.options[:as]}_type",
|
||||||
|
|
|
@ -29,8 +29,17 @@ module ActiveRecord
|
||||||
|
|
||||||
unless @target.nil? || @target == obj
|
unless @target.nil? || @target == obj
|
||||||
if dependent? && !dont_save
|
if dependent? && !dont_save
|
||||||
@target.destroy unless @target.new_record?
|
case @reflection.options[:dependent]
|
||||||
@owner.clear_association_cache
|
when :delete
|
||||||
|
@target.delete unless @target.new_record?
|
||||||
|
@owner.clear_association_cache
|
||||||
|
when :destroy
|
||||||
|
@target.destroy unless @target.new_record?
|
||||||
|
@owner.clear_association_cache
|
||||||
|
when :nullify
|
||||||
|
@target[@reflection.primary_key_name] = nil
|
||||||
|
@target.save unless @owner.new_record? || @target.new_record?
|
||||||
|
end
|
||||||
else
|
else
|
||||||
@target[@reflection.primary_key_name] = nil
|
@target[@reflection.primary_key_name] = nil
|
||||||
@target.save unless @owner.new_record? || @target.new_record?
|
@target.save unless @owner.new_record? || @target.new_record?
|
||||||
|
|
|
@ -283,7 +283,7 @@ module ActiveRecord
|
||||||
if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
|
if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
|
||||||
records.each do |record|
|
records.each do |record|
|
||||||
if autosave && record.marked_for_destruction?
|
if autosave && record.marked_for_destruction?
|
||||||
record.destroy
|
association.destroy(record)
|
||||||
elsif @new_record_before_save || record.new_record?
|
elsif @new_record_before_save || record.new_record?
|
||||||
if autosave
|
if autosave
|
||||||
association.send(:insert_record, record, false, false)
|
association.send(:insert_record, record, false, false)
|
||||||
|
@ -310,7 +310,7 @@ module ActiveRecord
|
||||||
# This all happens inside a transaction, _if_ the Transactions module is included into
|
# This all happens inside a transaction, _if_ the Transactions module is included into
|
||||||
# ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
|
# ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
|
||||||
def save_has_one_association(reflection)
|
def save_has_one_association(reflection)
|
||||||
if association = association_instance_get(reflection.name)
|
if (association = association_instance_get(reflection.name)) && !association.target.nil?
|
||||||
if reflection.options[:autosave] && association.marked_for_destruction?
|
if reflection.options[:autosave] && association.marked_for_destruction?
|
||||||
association.destroy
|
association.destroy
|
||||||
elsif new_record? || association.new_record? || association[reflection.primary_key_name] != id || reflection.options[:autosave]
|
elsif new_record? || association.new_record? || association[reflection.primary_key_name] != id || reflection.options[:autosave]
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue