Commit 844a188c authored by Ondrej Sury's avatar Ondrej Sury

New upstream version 4.0.0

parent 1e11155c
......@@ -60,11 +60,6 @@ platforms :jruby do
gem 'json'
gem 'activerecord-jdbcsqlite3-adapter', '>= 1.2.7'
# This is needed by now to let tests work on JRuby
# TODO: When the JRuby guys merge jruby-openssl in
# jruby this will be removed
gem 'jruby-openssl'
group :db do
gem 'activerecord-jdbcmysql-adapter', '>= 1.2.7'
gem 'activerecord-jdbcpostgresql-adapter', '>= 1.2.7'
......
## Rails 4.0.0 (unreleased) ##
## Rails 4.0.0.beta1 (February 25, 2013) ##
## Rails 4.0.0 (June 25, 2013) ##
* Allow passing interpolations to `#default_i18n_subject`, e.g.:
......
......@@ -67,12 +67,12 @@ simply call the method and optionally call +deliver+ on the return value.
Calling the method returns a Mail Message object:
message = Notifier.welcome # => Returns a Mail::Message object
message = Notifier.welcome("david@loudthinking.com") # => Returns a Mail::Message object
message.deliver # => delivers the email
Or you can just chain the methods together like:
Notifier.welcome.deliver # Creates the email and sends it immediately
Notifier.welcome("david@loudthinking.com").deliver # Creates the email and sends it immediately
== Setting defaults
......@@ -119,8 +119,7 @@ trivial case like this:
rails runner 'Mailman.receive(STDIN.read)'
However, invoking Rails in the runner for each mail to be received is very resource intensive. A single
instance of Rails should be run within a daemon, if it is going to be utilized to process more than just
a limited number of email.
instance of Rails should be run within a daemon, if it is going to process more than just a limited amount of email.
== Configuration
......
......@@ -334,8 +334,8 @@ module ActionMailer
# and starts to use it.
# * <tt>:openssl_verify_mode</tt> - When using TLS, you can set how OpenSSL checks the certificate. This is
# really useful if you need to validate a self-signed and/or a wildcard certificate. You can use the name
# of an OpenSSL verify constant ('none', 'peer', 'client_once','fail_if_no_peer_cert') or directly the
# constant (OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER,...).
# of an OpenSSL verify constant ('none', 'peer', 'client_once', 'fail_if_no_peer_cert') or directly the
# constant (OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER, ...).
#
# * <tt>sendmail_settings</tt> - Allows you to override options for the <tt>:sendmail</tt> delivery method.
# * <tt>:location</tt> - The location of the sendmail executable. Defaults to <tt>/usr/sbin/sendmail</tt>.
......@@ -596,7 +596,7 @@ def attachments
# class method:
#
# class Notifier < ActionMailer::Base
# self.default from: 'no-reply@test.lindsaar.net',
# default from: 'no-reply@test.lindsaar.net',
# bcc: 'email_logger@test.lindsaar.net',
# reply_to: 'bounces@test.lindsaar.net'
# end
......
module ActionMailer
# Returns the version of the currently loaded ActionMailer as a Gem::Version
def self.version
Gem::Version.new "4.0.0.rc1"
Gem::Version.new "4.0.0"
end
module VERSION #:nodoc:
......
<html>
<body>
HTML formatted message to <strong><%= @recipient %></strong>.
</body>
</html>
<html>
<body>
HTML formatted message to <strong><%= @recipient %></strong>.
</body>
</html>
Ignored when searching for implicitly multipart parts.
......@@ -38,7 +38,7 @@ def attachment_with_content(hash = {})
end
def attachment_with_hash
attachments['invoice.jpg'] = { data: "\312\213\254\232)b",
attachments['invoice.jpg'] = { data: ::Base64.encode64("\312\213\254\232)b"),
mime_type: "image/x-jpg",
transfer_encoding: "base64" }
mail
......
## Rails 4.0.0 (unreleased) ##
## Rails 4.0.0 (June 25, 2013) ##
* Merge `:action` from routing scope and assign endpoint if both `:controller`
and `:action` are present. The endpoint assignment only occurs if there is
no `:to` present in the options hash so should only affect routes using the
shorthand syntax (i.e. endpoint is inferred from the the path).
Fixes #9856
*Yves Senn*, *Andrew White*
* Use a case insensitive URI Regexp for #asset_path.
This fix a problem where the same asset path using different case are generating
different URIs.
Before:
image_tag("HTTP://google.com")
# => "<img alt=\"Google\" src=\"/assets/HTTP://google.com\" />"
image_tag("http://google.com")
# => "<img alt=\"Google\" src=\"http://google.com\" />"
After:
image_tag("HTTP://google.com")
# => "<img alt=\"Google\" src=\"HTTP://google.com\" />"
image_tag("http://google.com")
# => "<img alt=\"Google\" src=\"http://google.com\" />"
*David Celis*
* Fix an issue where partials with a number in the filename weren't being digested for cache dependencies.
*Bryan Ricker*
* Add support for passing custom url options other than `:host` and custom
status and flash options to `force_ssl`.
......@@ -181,9 +215,6 @@
*Thierry Zires*
## Rails 4.0.0.beta1 (February 25, 2013) ##
* Fix `respond_to` not using formats that have no block if all is present. *Michael Grosser*
* New applications use an encrypted session store by default.
......@@ -1058,6 +1089,14 @@
*Andrew White*
* In the routes DSL the `:via` option of `match` is now mandatory.
For routes that respond to one single verb it is recommended to use the more specific
macros `get`, `post`, etc. instead. You can still map all HTTP verbs to one action
with `match`, but it has to be explictly configured using `:via => :all`.
*José Valim and Yehuda Katz*
* Add `index` method to FormBuilder class. *Jorge Bejar*
* Remove the leading \n added by textarea on `assert_select`. *Santiago Pastorino*
......@@ -1106,8 +1145,6 @@
*dlee*
* Integration tests support the `OPTIONS` method. *Jeremy Kemper*
* `expires_in` accepts a `must_revalidate` flag. If true, "must-revalidate"
is added to the Cache-Control header. *fxn*
......
......@@ -32,7 +32,8 @@ def url_options
if (same_origin = _routes.equal?(env["action_dispatch.routes"])) ||
(script_name = env["ROUTES_#{_routes.object_id}_SCRIPT_NAME"]) ||
(original_script_name = env['SCRIPT_NAME'])
(original_script_name = env['ORIGINAL_SCRIPT_NAME'])
@_url_options.dup.tap do |options|
if original_script_name
options[:original_script_name] = original_script_name
......
......@@ -499,12 +499,6 @@ def head(action, *args)
process(action, "HEAD", *args)
end
# Simulate a OPTIONS request with the given parameters and set/volley the response.
# See +get+ for more details.
def options(action, *args)
process(action, "OPTIONS", *args)
end
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
@request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
......
......@@ -65,7 +65,7 @@ def normalize_encode_params(params)
new_hash = {}
params.each do |k, v|
new_key = k.is_a?(String) ? k.dup.force_encoding("UTF-8").encode! : k
new_key = k.is_a?(String) ? k.dup.force_encoding(Encoding::UTF_8).encode! : k
new_hash[new_key] =
case v
when Hash
......
......@@ -77,7 +77,7 @@ def cookie_jar
# domain and subdomains.
#
# * <tt>:expires</tt> - The time at which this cookie expires, as a \Time object.
# * <tt>:secure</tt> - Whether this cookie is a only transmitted to HTTPS servers.
# * <tt>:secure</tt> - Whether this cookie is only transmitted to HTTPS servers.
# Default is +false+.
# * <tt>:httponly</tt> - Whether this cookie is accessible via scripting or
# only HTTP. Defaults to +false+.
......
......@@ -13,6 +13,7 @@ class ExceptionWrapper
'ActionController::NotImplemented' => :not_implemented,
'ActionController::UnknownFormat' => :not_acceptable,
'ActionController::InvalidAuthenticityToken' => :unprocessable_entity,
'ActionDispatch::ParamsParser::ParseError' => :bad_request,
'ActionController::BadRequest' => :bad_request,
'ActionController::ParameterMissing' => :bad_request
)
......
......@@ -7,11 +7,10 @@ def initialize(public_path)
end
def call(env)
exception = env["action_dispatch.exception"]
status = env["PATH_INFO"][1..-1]
request = ActionDispatch::Request.new(env)
content_type = request.formats.first
body = { :status => status, :error => exception.message }
body = { :status => status, :error => Rack::Utils::HTTP_STATUS_CODES.fetch(status.to_i, Rack::Utils::HTTP_STATUS_CODES[500]) }
render(status, content_type, body)
end
......@@ -19,7 +18,7 @@ def call(env)
private
def render(status, content_type, body)
format = content_type && "to_#{content_type.to_sym}"
format = "to_#{content_type.to_sym}" if content_type
if format && body.respond_to?(format)
render_format(status, content_type, body.public_send(format))
else
......
......@@ -34,6 +34,12 @@
padding: 0.5em 1.5em;
}
h1 {
margin: 0.2em 0;
line-height: 1.1em;
font-size: 2em;
}
h2 {
color: #C52F24;
line-height: 25px;
......
......@@ -69,7 +69,7 @@ def action
end
def internal?
controller =~ %r{\Arails/(info|welcome)} || path =~ %r{\A#{Rails.application.config.assets.prefix}}
controller.to_s =~ %r{\Arails/(info|welcome)} || path =~ %r{\A#{Rails.application.config.assets.prefix}}
end
def engine?
......
......@@ -11,8 +11,8 @@ module Routing
class Mapper
URL_OPTIONS = [:protocol, :subdomain, :domain, :host, :port]
SCOPE_OPTIONS = [:path, :shallow_path, :as, :shallow_prefix, :module,
:controller, :path_names, :constraints, :defaults,
:shallow, :blocks, :options]
:controller, :action, :path_names, :constraints,
:shallow, :blocks, :defaults, :options]
class Constraints #:nodoc:
def self.new(app, constraints, request = Rack::Request)
......@@ -299,7 +299,7 @@ def default_action
end
end
# Invokes Rack::Mount::Utils.normalize path and ensure that
# Invokes Journey::Router::Utils.normalize_path and ensure that
# (:locale) becomes (/:locale) instead of /(:locale). Except
# for root cases, where the latter is the correct one.
def self.normalize_path(path)
......@@ -869,6 +869,10 @@ def merge_controller_scope(parent, child) #:nodoc:
child
end
def merge_action_scope(parent, child) #:nodoc:
child
end
def merge_path_names_scope(parent, child) #:nodoc:
merge_options_scope(parent, child)
end
......@@ -1378,6 +1382,10 @@ def match(path, *rest)
raise ArgumentError, "Unknown scope #{on.inspect} given to :on"
end
if @scope[:controller] && @scope[:action]
options[:to] ||= "#{@scope[:controller]}##{@scope[:action]}"
end
paths.each do |_path|
route_options = options.dup
route_options[:path] ||= _path if _path.is_a?(String)
......
......@@ -218,6 +218,7 @@ def handle_positional_args(t, args, options, keys)
keys -= t.url_options.keys if t.respond_to?(:url_options)
keys -= options.keys
end
keys -= inner_options.keys
result.merge!(Hash[keys.zip(args)])
end
......
......@@ -62,12 +62,6 @@ def head(path, parameters = nil, headers_or_env = nil)
process :head, path, parameters, headers_or_env
end
# Performs a OPTIONS request with the given parameters. See +#get+ for
# more details.
def options(path, parameters = nil, headers_or_env = nil)
process :options, path, parameters, headers_or_env
end
# Performs an XMLHttpRequest request with the given parameters, mirroring
# a request from the Prototype library.
#
......@@ -342,7 +336,7 @@ def reset!
@integration_session = Integration::Session.new(app)
end
%w(get post patch put head delete options cookies assigns
%w(get post patch put head delete cookies assigns
xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
define_method(method) do |*args|
reset! unless integration_session
......
module ActionPack
# Returns the version of the currently loaded ActionPack as a Gem::Version
def self.version
Gem::Version.new "4.0.0.rc1"
Gem::Version.new "4.0.0"
end
module VERSION #:nodoc:
......
......@@ -39,7 +39,7 @@ class ERBTracker
render\s* # render, followed by optional whitespace
\(? # start an optional parenthesis for the render call
(partial:|:partial\s+=>)?\s* # naming the partial, used with collection -- 1st capture
([@a-z"'][@a-z_\/\."']+) # the template name itself -- 2nd capture
([@a-z"'][@\w\/\."']+) # the template name itself -- 2nd capture
/x
def self.call(name, template)
......
......@@ -105,7 +105,7 @@ module Helpers
# )
#
module AssetUrlHelper
URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}
URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}i
# Computes the path to asset in public directory. If :type
# options is set, a file extension will be appended and scoped
......@@ -193,7 +193,6 @@ def compute_asset_host(source = "", options = {})
request = self.request if respond_to?(:request)
host = config.asset_host if defined? config.asset_host
host ||= request.base_url if request && options[:protocol] == :request
return unless host
if host.respond_to?(:call)
arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity
......@@ -204,6 +203,8 @@ def compute_asset_host(source = "", options = {})
host = host % (Zlib.crc32(source) % 4)
end
return unless host
if host =~ URI_REGEXP
host
else
......
......@@ -81,7 +81,7 @@ def form_tag(url_for_options = {}, options = {}, &block)
# ==== Options
# * <tt>:multiple</tt> - If set to true the selection will allow multiple choices.
# * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
# * <tt>:include_blank</tt> - If set to true, an empty option will be create
# * <tt>:include_blank</tt> - If set to true, an empty option will be created.
# * <tt>:prompt</tt> - Create a prompt option with blank value and the text asking user to select something
# * Any other key creates standard HTML attributes for the tag.
#
......
require 'thread_safe'
require 'active_support/core_ext/module/remove_method'
require 'active_support/core_ext/module/attribute_accessors'
module ActionView
# = Action View Lookup Context
......
......@@ -117,12 +117,6 @@ def test_head
@session.head(path,params,headers)
end
def test_options
path = "/index"; params = "blah"; headers = {:location => 'blah'}
@session.expects(:process).with(:options,path,params,headers)
@session.options(path,params,headers)
end
def test_xml_http_request_get
path = "/index"; params = "blah"; headers = {:location => 'blah'}
headers_after_xhr = headers.merge(
......@@ -183,16 +177,6 @@ def test_xml_http_request_head
@session.xml_http_request(:head,path,params,headers)
end
def test_xml_http_request_options
path = "/index"; params = "blah"; headers = {:location => 'blah'}
headers_after_xhr = headers.merge(
"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
"HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*"
)
@session.expects(:process).with(:options,path,params,headers_after_xhr)
@session.xml_http_request(:options,path,params,headers)
end
def test_xml_http_request_override_accept
path = "/index"; params = "blah"; headers = {:location => 'blah', "HTTP_ACCEPT" => "application/xml"}
headers_after_xhr = headers.merge(
......@@ -250,7 +234,7 @@ def test_integration_methods_called
@integration_session.stubs(:generic_url_rewriter)
@integration_session.stubs(:process)
%w( get post head patch put delete options ).each do |verb|
%w( get post head patch put delete ).each do |verb|
assert_nothing_raised("'#{verb}' should use integration test methods") { __send__(verb, '/') }
end
end
......
......@@ -75,7 +75,7 @@ def test_render_json_exception
get "/", {}, 'HTTP_ACCEPT' => 'application/json'
assert_response :internal_server_error
assert_equal 'application/json', response.content_type.to_s
assert_equal({ :status => '500', :error => 'boom!' }.to_json, response.body)
assert_equal({ :status => '500', :error => 'Internal Server Error' }.to_json, response.body)
end
def test_render_xml_exception
......@@ -83,7 +83,7 @@ def test_render_xml_exception
get "/", {}, 'HTTP_ACCEPT' => 'application/xml'
assert_response :internal_server_error
assert_equal 'application/xml', response.content_type.to_s
assert_equal({ :status => '500', :error => 'boom!' }.to_xml, response.body)
assert_equal({ :status => '500', :error => 'Internal Server Error' }.to_xml, response.body)
end
def test_render_fallback_exception
......
......@@ -201,11 +201,6 @@ def test_head_params_as_sting
assert_raise(NoMethodError) { head :test_params, "document body", :id => 10 }
end
def test_options
options :test_params
assert_equal 200, @response.status
end
def test_process_without_flash
process :set_flash
assert_equal '><', flash['test']
......
......@@ -50,7 +50,7 @@ def teardown
output = StringIO.new
json = "[\"person]\": {\"name\": \"David\"}}"
post "/parse", json, {'CONTENT_TYPE' => 'application/json', 'action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => ActiveSupport::Logger.new(output)}
assert_response :error
assert_response :bad_request
output.rewind && err = output.read
assert err =~ /Error occurred while parsing request parameters/
end
......
......@@ -234,6 +234,15 @@ def test_routes_can_be_filtered
" PUT /posts/:id(.:format) posts#update",
" DELETE /posts/:id(.:format) posts#destroy"], output
end
def test_regression_route_with_controller_regexp
output = draw do
get ':controller(/:action)', controller: /api\/[^\/]+/, format: false
end
assert_equal ["Prefix Verb URI Pattern Controller#Action",
" GET /:controller(/:action) (?-mix:api\\/[^\\/]+)#:action"], output
end
end
end
end
......@@ -69,6 +69,17 @@ def call(env)
end
end
test "explicit keys win over implicit keys" do
draw do
resources :foo do
resources :bar, to: SimpleApp.new('foo#show')
end
end
assert_equal '/foo/1/bar/2', url_helpers.foo_bar_path(1, 2)
assert_equal '/foo/1/bar/2', url_helpers.foo_bar_path(2, foo_id: 1)
end
private
def clear!
@set.clear!
......
......@@ -1253,6 +1253,19 @@ def test_match_shorthand_inside_nested_namespaces_and_scopes_with_controller
assert_equal 'api/v3/products#list', @response.body
end
def test_controller_option_with_nesting_and_leading_slash
draw do
scope '/job', controller: 'job' do
scope ':id', action: 'manage_applicant' do
get "/active"
end
end
end
get '/job/5/active'
assert_equal 'job#manage_applicant', @response.body
end
def test_dynamically_generated_helpers_on_collection_do_not_clobber_resources_url_helper
draw do
resources :replies do
......
......@@ -8,6 +8,8 @@ def call(env)
case req.path
when "/not_found"
raise AbstractController::ActionNotFound
when "/bad_params"
raise ActionDispatch::ParamsParser::ParseError.new("", StandardError.new)
when "/method_not_allowed"
raise ActionController::MethodNotAllowed
when "/unknown_http_method"
......@@ -36,6 +38,10 @@ def call(env)
assert_response 500
assert_equal "500 error fixture\n", body
get "/bad_params", {}, {'action_dispatch.show_exceptions' => true}
assert_response 400
assert_equal "400 error fixture\n", body
get "/not_found", {}, {'action_dispatch.show_exceptions' => true}
assert_response 404
assert_equal "404 error fixture\n", body
......
......@@ -7,6 +7,7 @@
<%= render @message.history.events %>
<%# render "something_missing" %>
<%# render "something_missing_1" %>
<%
# Template Dependency: messages/form
......
Don't pick me!
\ No newline at end of file
Don't render me!
\ No newline at end of file
Don't render me!
\ No newline at end of file
Don't render me!
\ No newline at end of file
......@@ -48,6 +48,9 @@ def url_for(*args)
%(asset_path("style.min")) => %(/style.min),
%(asset_path("style.min.css")) => %(/style.min.css),
%(asset_path("http://www.outside.com/image.jpg")) => %(http://www.outside.com/image.jpg),
%(asset_path("HTTP://www.outside.com/image.jpg")) => %(HTTP://www.outside.com/image.jpg),
%(asset_path("style", type: :stylesheet)) => %(/stylesheets/style.css),
%(asset_path("xmlhr", type: :javascript)) => %(/javascripts/xmlhr.js),
%(asset_path("xml.png", type: :image)) => %(/images/xml.png)
......@@ -530,6 +533,17 @@ def test_should_not_modify_source_string
assert_equal copy, source
end
def test_image_path_with_asset_host_proc_returning_nil
@controller.config.asset_host = Proc.new do |source|
unless source.end_with?("tiff")
"cdn.example.com"
end
end
assert_equal "/images/file.tiff", image_path("file.tiff")
assert_equal "http://cdn.example.com/images/file.png", image_path("file.png")
end
def test_caching_image_path_with_caching_and_proc_asset_host_using_request
@controller.config.asset_host = Proc.new do |source, request|
if request.ssl?
......
......@@ -83,6 +83,12 @@ def test_logging_of_missing_template
end
end
def test_logging_of_missing_template_ending_with_number
assert_logged "Couldn't find template for digesting: messages/something_missing_1.html" do
digest("messages/show")
end
end
def test_nested_template_directory
assert_digest_difference("messages/show") do
change_template("messages/actions/_move")
......
## Rails 4.0.0 (unreleased) ##
## Rails 4.0.0 (June 25, 2013) ##
* Fix regression in has_secure_password. When a password is set, but a
confirmation is an empty string, it would incorrectly save.
*Steve Klabnik* and *Phillip Calvin*
* Add `ActiveModel::Errors#full_messages_for`, to return all the error messages
for a given attribute.
......@@ -68,8 +73,6 @@
*Yves Senn*