aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md128
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb35
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb7
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb26
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/debug_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb6
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb2
-rw-r--r--actionpack/test/controller/parameters/parameters_permit_test.rb3
-rw-r--r--actionpack/test/dispatch/routing_test.rb27
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb2
-rw-r--r--actionpack/test/template/date_helper_test.rb36
-rw-r--r--actionpack/test/template/form_options_helper_test.rb16
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb2
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb10
-rw-r--r--activerecord/test/cases/migration/columns_test.rb (renamed from activerecord/test/cases/migration/rename_column_test.rb)30
-rw-r--r--activerecord/test/models/speedometer.rb2
-rw-r--r--activesupport/CHANGELOG.md28
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/calculations.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb15
-rw-r--r--activesupport/lib/active_support/number_helper.rb2
-rw-r--r--activesupport/test/core_ext/date_time_ext_test.rb8
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb8
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb14
-rw-r--r--activesupport/test/number_helper_test.rb7
-rw-r--r--railties/lib/rails/app_rails_loader.rb24
-rw-r--r--railties/lib/rails/application/configuration.rb6
-rw-r--r--railties/lib/rails/cli.rb3
-rw-r--r--railties/lib/rails/tasks/documentation.rake2
-rw-r--r--railties/test/app_rails_loader_test.rb65
31 files changed, 346 insertions, 190 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 1a0060c911..528fa291c5 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,17 +1,27 @@
## Rails 4.0.0 (unreleased) ##
-* Remove support for parsing XML parameters from request. If you still want to parse XML
- parameters, please install `actionpack-xml_parser' gem.
+* New applications use an encrypted session store by default.
- *Prem Sichanugrist*
+ *Santiago Pastorino*
+
+* Determine the controller#action from only the matched path when using the
+ shorthand syntax. Previously the complete path was used, which led
+ to problems with nesting (scopes and namespaces).
+ Fixes #7554.
+
+ Example:
-* Fix `time_zone_options_for_select` to call `dup` on the returned TimeZone array.
+ # This will route to questions#new.
+ scope ':locale' do
+ get 'questions/new'
+ end
- Previously if you supplied :priority_zones options to `time_zone_options_for_select`
- the memoized ActiveSupport::TimeZone.all array would be mutated. Calling
- `dup` prevents mutation of the main TimeZones array.
+ *Yves Senn*
+
+* Remove support for parsing XML parameters from request. If you still want to parse XML
+ parameters, please install `actionpack-xml_parser' gem.
- *Brian McManus*
+ *Prem Sichanugrist*
* Remove support for parsing YAML parameters from request.
@@ -19,7 +29,7 @@
* Add a message when you have no routes defined to both `rake routes` and
GET "/rails/info/routes" that lets you know you have none defined and links
- to the Rails Guide on the topic.
+ to the Rails guide on the topic.
*Steve Klabnik*
@@ -33,31 +43,30 @@
screen readers by converting both hyphens and underscores to spaces.
Before:
+
image_tag('underscored_file_name.png')
# => <img alt="Underscored_file_name" src="/assets/underscored_file_name.png" />
After:
+
image_tag('underscored_file_name.png')
# => <img alt="Underscored file name" src="/assets/underscored_file_name.png" />
*Nick Cox*
-* We don't support the `:controller` option for route definitions
- with the ruby constant notation. This will now result in an
- `ArgumentError`.
+* We don't support Ruby constant notation in the `:controller` option for route
+ definitions. So, this raises an `ArgumentError` now:
- Example:
- # This raises an ArgumentError:
- resources :posts, :controller => "Admin::Posts"
+ resources :posts, controller: "Admin::Posts" # WRONG
- # Use directory notation instead:
- resources :posts, :controller => "admin/posts"
+ Use path notation instead:
+
+ resources :posts, controller: "admin/posts" # RIGHT
*Yves Senn*
* `assert_template` can be used to verify the locals of partials,
which live inside a directory.
- Fixes #8516.
# Prefixed partials inside directories worked and still work.
assert_template partial: 'directory/_partial', locals: {name: 'John'}
@@ -65,23 +74,25 @@
# This did not work but does now.
assert_template partial: 'directory/partial', locals: {name: 'John'}
+ Fixes #8516.
+
*Yves Senn*
-* Fix `content_tag_for` with array html option.
+* Fix `content_tag_for` with array HTML option.
It would embed array as string instead of joining it like `content_tag` does:
content_tag(:td, class: ["foo", "bar"]){}
- #=> '<td class="foo bar"></td>'
+ # => <td class="foo bar"></td>
Before:
content_tag_for(:td, item, class: ["foo", "bar"])
- #=> '<td class="item [&quot;foo&quot;, &quot;bar&quot;]" id="item_1"></td>'
+ # => <td class="item [&quot;foo&quot;, &quot;bar&quot;]" id="item_1"></td>
After:
content_tag_for(:td, item, class: ["foo", "bar"])
- #=> '<td class="item foo bar" id="item_1"></td>'
+ # => <td class="item foo bar" id="item_1"></td>
*Semyon Perepelitsa*
@@ -101,35 +112,18 @@
*Piotr Sarnacki*
-* Add javascript based routing path matcher to `/rails/info/routes`.
+* Add JavaScript based routing path matcher to `/rails/info/routes`.
Routes can now be filtered by whether or not they match a path.
*Richard Schneeman*
-* Given
-
- params.permit(:name)
-
- `:name` passes if it is a key of `params` whose value is a permitted scalar.
-
- Similarly, given
-
- params.permit(tags: [])
-
- `:tags` passes if it is a key of `params` whose value is an array of
- permitted scalars.
-
- Permitted scalars filtering happens at any level of nesting.
-
- *Xavier Noria*
-
* Change the behavior of route defaults so that explicit defaults are no longer
required where the key is not part of the path. For example:
resources :posts, bucket_type: 'posts'
will be required whenever constructing the url from a hash such as a functional
- test or using url_for directly. However using the explicit form alters the
+ test or using `url_for` directly. However using the explicit form alters the
behavior so it's not required:
resources :projects, defaults: { bucket_type: 'projects' }
@@ -163,7 +157,7 @@
*Colin Burn-Murdoch*
-* Fixed json params parsing regression for non-object JSON content.
+* Fixed JSON params parsing regression for non-object JSON content.
*Dylan Smith*
@@ -201,12 +195,13 @@
* Do not append second slash to `root_url` when using `trailing_slash: true`
Fix #8700
- Example:
- # before
- root_url # => http://test.host//
+ Before:
- # after
- root_url # => http://test.host/
+ root_url(trailing_slash: true) # => http://test.host//
+
+ After:
+
+ root_url(trailing_slash: true) # => http://test.host/
*Yves Senn*
@@ -230,8 +225,8 @@
*Yves Senn*
-* Added `Mime::NullType` class. This allows to use html?, xml?, json?..etc when
- the `format` of `request` is unknown, without raise an exception.
+* Added `Mime::NullType` class. This allows to use `html?`, `xml?`, `json?`, etc.
+ when the format of the request is unknown, without raising an exception.
*Angelo Capilleri*
@@ -256,7 +251,7 @@
*Matt Venables*
-* Prevent raising EOFError on multipart GET request (IE issue). *Adam Stankiewicz*
+* Prevent raising `EOFError` on multipart GET request (IE issue). *Adam Stankiewicz*
* Rename all action callbacks from *_filter to *_action to avoid the misconception that these
callbacks are only suited for transforming or halting the response. With the new style,
@@ -302,7 +297,7 @@
*Stephen Ausman + Fabrizio Regini + Angelo Capilleri*
-* Add filter capability to ActionController logs for redirect locations:
+* Add logging filter capability for redirect URLs:
config.filter_redirect << 'http://please.hide.it/'
@@ -401,23 +396,17 @@
Before:
check_box("post", "comment_ids", { multiple: true, index: "foo" }, 1)
- #=> <input name=\"post[foo][comment_ids]\" type=\"hidden\" value=\"0\" /><input id=\"post_foo_comment_ids_1\" name=\"post[foo][comment_ids]\" type=\"checkbox\" value=\"1\" />
+ # => <input name=\"post[foo][comment_ids]\" type=\"hidden\" value=\"0\" /><input id=\"post_foo_comment_ids_1\" name=\"post[foo][comment_ids]\" type=\"checkbox\" value=\"1\" />
After:
check_box("post", "comment_ids", { multiple: true, index: "foo" }, 1)
- #=> <input name=\"post[foo][comment_ids][]\" type=\"hidden\" value=\"0\" /><input id=\"post_foo_comment_ids_1\" name=\"post[foo][comment_ids][]\" type=\"checkbox\" value=\"1\" />
+ # => <input name=\"post[foo][comment_ids][]\" type=\"hidden\" value=\"0\" /><input id=\"post_foo_comment_ids_1\" name=\"post[foo][comment_ids][]\" type=\"checkbox\" value=\"1\" />
Fix #8108.
*Daniel Fox, Grant Hutchins & Trace Wax*
-* `BestStandardsSupport` middleware now appends it's `X-UA-Compatible` value to app's
- returned value if any.
- Fix #8086.
-
- *Nikita Afanasenko*
-
* `date_select` helper accepts `with_css_classes: true` to add css classes similar with type
of generated select tags.
@@ -470,10 +459,6 @@
* Failsafe exception returns `text/plain`. *Steve Klabnik*
-* Remove `rack-cache` dependency from Action Pack and declare it on Gemfile
-
- *Guillermo Iguaran*
-
* Rename internal variables on `ActionController::TemplateAssertions` to prevent
naming collisions. `@partials`, `@templates` and `@layouts` are now prefixed with an underscore.
Fix #7459.
@@ -559,9 +544,7 @@
*Guillermo Iguaran*
* `ActionDispatch::Session::MemCacheStore` now uses `dalli` instead of the deprecated
- `memcache-client` gem. As side effect the autoloading of unloaded classes objects
- saved as values in session isn't supported anymore when mem_cache session store is
- used, this can have an impact in apps only when config.cache_classes is false.
+ `memcache-client` gem.
*Arun Agrawal + Guillermo Iguaran*
@@ -835,9 +818,9 @@
* `assert_generates`, `assert_recognizes`, and `assert_routing` all raise
`Assertion` instead of `RoutingError` *David Chelimsky*
-* URL path parameters with invalid encoding now raise ActionController::BadRequest. *Andrew White*
+* URL path parameters with invalid encoding now raise `ActionController::BadRequest`. *Andrew White*
-* Malformed query and request parameter hashes now raise ActionController::BadRequest. *Andrew White*
+* Malformed query and request parameter hashes now raise `ActionController::BadRequest`. *Andrew White*
* Add `divider` option to `grouped_options_for_select` to generate a separator
`optgroup` automatically, and deprecate `prompt` as third argument, in favor
@@ -864,7 +847,7 @@
*Andrew White*
-* `respond_to` and `respond_with` now raise ActionController::UnknownFormat instead
+* `respond_to` and `respond_with` now raise `ActionController::UnknownFormat` instead
of directly returning head 406. The exception is rescued and converted to 406
in the exception handling middleware. *Steven Soroka*
@@ -894,7 +877,7 @@
* Remove the leading \n added by textarea on `assert_select`. *Santiago Pastorino*
* Changed default value for `config.action_view.embed_authenticity_token_in_remote_forms`
- to `false`. This change breaks remote forms that need to work also without javascript,
+ to `false`. This change breaks remote forms that need to work also without JavaScript,
so if you need such behavior, you can either set it to `true` or explicitly pass
`authenticity_token: true` in form options.
@@ -989,9 +972,6 @@
* `check_box` with `:form` html5 attribute will now replicate the `:form`
attribute to the hidden field as well. *Carlos Antonio da Silva*
-* Turn off verbose mode of rack-cache, we still have X-Rack-Cache to
- check that info. Closes #5245. *Santiago Pastorino*
-
* `label` form helper accepts `for: nil` to not generate the attribute. *Carlos Antonio da Silva*
* Add `:format` option to `number_to_percentage`. *Rodrigo Flores*
@@ -1019,6 +999,8 @@
not submitted with the form. This is a behavior change, previously the hidden
tag had a value of the disabled checkbox. *Tadas Tamosauskas*
+* `favicon_link_tag` helper will now use the favicon in app/assets by default. *Lucas Caton*
+
* `ActionView::Helpers::TextHelper#highlight` now defaults to the
HTML5 `mark` element. *Brian Cardarella*
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 17379cf7ac..d275a854fd 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -50,6 +50,10 @@ module ActionController #:nodoc:
config_accessor :request_forgery_protection_token
self.request_forgery_protection_token ||= :authenticity_token
+ # Holds the class which implements the request forgery protection.
+ config_accessor :forgery_protection_strategy
+ self.forgery_protection_strategy = nil
+
# Controls whether request forgery protection is turned on or not. Turned off by default only in test mode.
config_accessor :allow_forgery_protection
self.allow_forgery_protection = true if allow_forgery_protection.nil?
@@ -82,14 +86,14 @@ module ActionController #:nodoc:
# * <tt>:reset_session</tt> - Resets the session.
# * <tt>:null_session</tt> - Provides an empty session during request but doesn't reset it completely. Used as default if <tt>:with</tt> option is not specified.
def protect_from_forgery(options = {})
- include protection_method_module(options[:with] || :null_session)
+ self.forgery_protection_strategy = protection_method_class(options[:with] || :null_session)
self.request_forgery_protection_token ||= :authenticity_token
prepend_before_action :verify_authenticity_token, options
end
private
- def protection_method_module(name)
+ def protection_method_class(name)
ActionController::RequestForgeryProtection::ProtectionMethods.const_get(name.to_s.classify)
rescue NameError
raise ArgumentError, 'Invalid request forgery protection method, use :null_session, :exception, or :reset_session'
@@ -97,17 +101,22 @@ module ActionController #:nodoc:
end
module ProtectionMethods
- module NullSession
- protected
+ class NullSession
+ def initialize(controller)
+ @controller = controller
+ end
# This is the method that defines the application behavior when a request is found to be unverified.
def handle_unverified_request
+ request = @controller.request
request.session = NullSessionHash.new(request.env)
request.env['action_dispatch.request.flash_hash'] = nil
request.env['rack.session.options'] = { skip: true }
request.env['action_dispatch.cookies'] = NullCookieJar.build(request)
end
+ protected
+
class NullSessionHash < Rack::Session::Abstract::SessionHash #:nodoc:
def initialize(env)
super(nil, env)
@@ -135,16 +144,20 @@ module ActionController #:nodoc:
end
end
- module ResetSession
- protected
+ class ResetSession
+ def initialize(controller)
+ @controller = controller
+ end
def handle_unverified_request
- reset_session
+ @controller.reset_session
end
end
- module Exception
- protected
+ class Exception
+ def initialize(controller)
+ @controller = controller
+ end
def handle_unverified_request
raise ActionController::InvalidAuthenticityToken
@@ -153,6 +166,10 @@ module ActionController #:nodoc:
end
protected
+ def handle_unverified_request
+ forgery_protection_strategy.new(self).handle_unverified_request
+ end
+
# The actual before_action that is used. Modify this to change how you handle unverified requests.
def verify_authenticity_token
unless verified_request?
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 7e720ca6f5..e4dcd3213f 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -191,9 +191,9 @@ module ActionController
#
# +:name+ passes it is a key of +params+ whose associated value is of type
# +String+, +Symbol+, +NilClass+, +Numeric+, +TrueClass+, +FalseClass+,
- # +Date+, +Time+, +DateTime+, +StringIO+, +IO+, or
- # +ActionDispatch::Http::UploadedFile+. Otherwise, the key +:name+ is
- # filtered out.
+ # +Date+, +Time+, +DateTime+, +StringIO+, +IO+,
+ # +ActionDispatch::Http::UploadedFile+ or +Rack::Test::UploadedFile+.
+ # Otherwise, the key +:name+ is filtered out.
#
# You may declare that the parameter should be an array of permitted scalars
# by mapping it to an empty array:
@@ -374,6 +374,7 @@ module ActionController
StringIO,
IO,
ActionDispatch::Http::UploadedFile,
+ Rack::Test::UploadedFile,
]
def permitted_scalar?(value)
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 0a41ed0fcf..a8e225d61c 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -50,7 +50,6 @@ module ActionDispatch
class Mapping #:nodoc:
IGNORE_OPTIONS = [:to, :as, :via, :on, :constraints, :defaults, :only, :except, :anchor, :shallow, :shallow_path, :shallow_prefix, :format]
ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
- SHORTHAND_REGEX = %r{/[\w/]+$}
WILDCARD_PATH = %r{\*([^/\)]+)\)?$}
attr_reader :scope, :path, :options, :requirements, :conditions, :defaults
@@ -111,17 +110,7 @@ module ActionDispatch
@options[:controller] ||= /.+?/
end
- if using_match_shorthand?(path_without_format, @options)
- to_shorthand = @options[:to].blank?
- @options[:to] ||= path_without_format.gsub(/\(.*\)/, "")[1..-1].sub(%r{/([^/]*)$}, '#\1')
- end
-
- @options.merge!(default_controller_and_action(to_shorthand))
- end
-
- # match "account/overview"
- def using_match_shorthand?(path, options)
- path && (options[:to] || options[:action]).nil? && path =~ SHORTHAND_REGEX
+ @options.merge!(default_controller_and_action)
end
def normalize_format!
@@ -214,7 +203,7 @@ module ActionDispatch
Constraints.new(endpoint, blocks, @set.request_class)
end
- def default_controller_and_action(to_shorthand=nil)
+ def default_controller_and_action
if to.respond_to?(:call)
{ }
else
@@ -227,7 +216,7 @@ module ActionDispatch
controller ||= default_controller
action ||= default_action
- unless controller.is_a?(Regexp) || to_shorthand
+ unless controller.is_a?(Regexp)
controller = [@scope[:module], controller].compact.join("/").presence
end
@@ -1383,6 +1372,11 @@ module ActionDispatch
paths = [path] + rest
end
+ path_without_format = path.to_s.sub(/\(\.:format\)$/, '')
+ if using_match_shorthand?(path_without_format, options)
+ options[:to] ||= path_without_format.gsub(%r{^/}, "").sub(%r{/([^/]*)$}, '#\1')
+ end
+
options[:anchor] = true unless options.key?(:anchor)
if options[:on] && !VALID_ON_OPTIONS.include?(options[:on])
@@ -1393,6 +1387,10 @@ module ActionDispatch
self
end
+ def using_match_shorthand?(path, options)
+ path && (options[:to] || options[:action]).nil? && path =~ %r{/[\w/]+$}
+ end
+
def decomposed_match(path, options) # :nodoc:
if on = options.delete(:on)
send(on) { decomposed_match(path, options) }
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index bf78c00e4d..31e37893c6 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -152,7 +152,7 @@ module ActionView
# * <tt>:type</tt> - Override the auto-generated mime type, defaults to 'image/vnd.microsoft.icon'
#
# favicon_link_tag '/myicon.ico'
- # # => <link href="/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />
+ # # => <link href="/assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />
#
# Mobile Safari looks for a different <link> tag, pointing to an image that
# will be used if you add the page to the home screen of an iPod Touch, iPhone, or iPad.
@@ -161,7 +161,7 @@ module ActionView
# favicon_link_tag '/mb-icon.png', rel: 'apple-touch-icon', type: 'image/png'
# # => <link href="/assets/mb-icon.png" rel="apple-touch-icon" type="image/png" />
#
- def favicon_link_tag(source='/favicon.ico', options={})
+ def favicon_link_tag(source='favicon.ico', options={})
tag('link', {
:rel => 'shortcut icon',
:type => 'image/vnd.microsoft.icon',
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index a989966613..d3953c26b7 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -642,6 +642,8 @@ module ActionView
# <time datetime="2010-11-03">Yesterday</time>
# time_tag Date.today, pubdate: true # =>
# <time datetime="2010-11-04" pubdate="pubdate">November 04, 2010</time>
+ # time_tag Date.today, datetime: Date.today.strftime('%G-W%V') # =>
+ # <time datetime="2010-W44">November 04, 2010</time>
#
# <%= time_tag Time.now do %>
# <span>Right now</span>
@@ -651,7 +653,7 @@ module ActionView
options = args.extract_options!
format = options.delete(:format) || :long
content = args.first || I18n.l(date_or_time, :format => format)
- datetime = date_or_time.acts_like?(:time) ? date_or_time.xmlschema : date_or_time.rfc3339
+ datetime = date_or_time.acts_like?(:time) ? date_or_time.xmlschema : date_or_time.iso8601
content_tag(:time, content, options.reverse_merge(:datetime => datetime), &block)
end
diff --git a/actionpack/lib/action_view/helpers/debug_helper.rb b/actionpack/lib/action_view/helpers/debug_helper.rb
index 34fc23ac1a..c29c1b1eea 100644
--- a/actionpack/lib/action_view/helpers/debug_helper.rb
+++ b/actionpack/lib/action_view/helpers/debug_helper.rb
@@ -32,7 +32,7 @@ module ActionView
content_tag(:pre, object, :class => "debug_dump")
rescue Exception # errors from Marshal or YAML
# Object couldn't be dumped, perhaps because of singleton methods -- this is the fallback
- content_tag(:code, object.to_yaml, :class => "debug_dump")
+ content_tag(:code, object.inspect, :class => "debug_dump")
end
end
end
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 49473dd129..377819a80c 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -560,19 +560,19 @@ module ActionView
def time_zone_options_for_select(selected = nil, priority_zones = nil, model = ::ActiveSupport::TimeZone)
zone_options = "".html_safe
- zones = model.all.dup
+ zones = model.all
convert_zones = lambda { |list| list.map { |z| [ z.to_s, z.name ] } }
if priority_zones
if priority_zones.is_a?(Regexp)
- priority_zones = zones.select { |z| z =~ priority_zones }
+ priority_zones = zones.grep(priority_zones)
end
zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected)
zone_options.safe_concat content_tag(:option, '-------------', :value => '', :disabled => 'disabled')
zone_options.safe_concat "\n"
- zones.reject! { |z| priority_zones.include?(z) }
+ zones = zones - priority_zones
end
zone_options.safe_concat options_for_select(convert_zones[zones], selected)
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 86d9f94067..1adc8225f1 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -33,7 +33,7 @@ module ActionView
# (by passing <tt>false</tt>). Remote forms may omit the embedded authenticity token
# by setting <tt>config.action_view.embed_authenticity_token_in_remote_forms = false</tt>.
# This is helpful when you're fragment-caching the form. Remote forms get the
- # authenticity from the <tt>meta</tt> tag, so embedding is unnecessary unless you
+ # authenticity token from the <tt>meta</tt> tag, so embedding is unnecessary unless you
# support browsers without JavaScript.
# * A list of parameters to feed to the URL the form will be posted to.
# * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index aadb142660..437da43d9b 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -32,7 +32,8 @@ class ParametersPermitTest < ActiveSupport::TestCase
values += [0, 1.0, 2**128, BigDecimal.new(1)]
values += [true, false]
values += [Date.today, Time.now, DateTime.now]
- values += [STDOUT, StringIO.new, ActionDispatch::Http::UploadedFile.new(tempfile: __FILE__)]
+ values += [STDOUT, StringIO.new, ActionDispatch::Http::UploadedFile.new(tempfile: __FILE__),
+ Rack::Test::UploadedFile.new(__FILE__)]
values.each do |value|
params = ActionController::Parameters.new(id: value)
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 143733254b..37ad9ddb6b 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -1146,6 +1146,33 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal 'api/products#list', @response.body
end
+ def test_match_shorthand_inside_scope_with_variables_with_controller
+ draw do
+ scope ':locale' do
+ match 'questions/new', via: [:get]
+ end
+ end
+
+ get '/de/questions/new'
+ assert_equal 'questions#new', @response.body
+ assert_equal 'de', @request.params[:locale]
+ end
+
+ def test_match_shorthand_inside_nested_namespaces_and_scopes_with_controller
+ draw do
+ namespace :api do
+ namespace :v3 do
+ scope ':locale' do
+ get "products/list"
+ end
+ end
+ end
+ end
+
+ get '/api/v3/en/products/list'
+ assert_equal 'api/v3/products#list', @response.body
+ end
+
def test_dynamically_generated_helpers_on_collection_do_not_clobber_resources_url_helper
draw do
resources :replies do
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index 185f742c7f..11614a45dc 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -200,7 +200,7 @@ class AssetTagHelperTest < ActionView::TestCase
}
FaviconLinkToTag = {
- %(favicon_link_tag) => %(<link href="/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />),
+ %(favicon_link_tag) => %(<link href="/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />),
%(favicon_link_tag 'favicon.ico') => %(<link href="/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />),
%(favicon_link_tag 'favicon.ico', :rel => 'foo') => %(<link href="/images/favicon.ico" rel="foo" type="image/vnd.microsoft.icon" />),
%(favicon_link_tag 'favicon.ico', :rel => 'foo', :type => 'bar') => %(<link href="/images/favicon.ico" rel="foo" type="bar" />),
diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb
index f11adefad8..242b56a1fd 100644
--- a/actionpack/test/template/date_helper_test.rb
+++ b/actionpack/test/template/date_helper_test.rb
@@ -1510,42 +1510,42 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, date_select("post", "written_on")
end
-
+
def test_date_select_with_selected
@post = Post.new
@post.written_on = Date.new(2004, 6, 15)
-
+
expected = %{<select id="post_written_on_1i" name="post[written_on(1i)]">\n}
expected << %{<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option selected="selected" value="2004">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n}
expected << "</select>\n"
-
+
expected << %{<select id="post_written_on_2i" name="post[written_on(2i)]">\n}
expected << %{<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7" selected="selected">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n}
expected << "</select>\n"
-
+
expected << %{<select id="post_written_on_3i" name="post[written_on(3i)]">\n}
expected << %{<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10" selected="selected">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n}
-
+
expected << "</select>\n"
-
+
assert_dom_equal expected, date_select("post", "written_on", :selected => Date.new(2004, 07, 10))
end
def test_date_select_with_selected_nil
@post = Post.new
@post.written_on = Date.new(2004, 6, 15)
-
+
expected = '<input id="post_written_on_1i" name="post[written_on(1i)]" type="hidden" value="1"/>' + "\n"
-
+
expected << %{<select id="post_written_on_2i" name="post[written_on(2i)]">\n}
expected << %{<option value=""></option>\n<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n}
expected << "</select>\n"
-
+
expected << %{<select id="post_written_on_3i" name="post[written_on(3i)]">\n}
expected << %{<option value=""></option>\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n}
-
+
expected << "</select>\n"
-
+
assert_dom_equal expected, date_select("post", "written_on", include_blank: true, discard_year: true, selected: nil)
end
@@ -2296,7 +2296,7 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, datetime_select("post", "updated_at", discard_year: true, selected: nil)
end
-
+
def test_datetime_select_defaults_to_time_zone_now_when_config_time_zone_is_set
# The love zone is UTC+0
mytz = Class.new(ActiveSupport::TimeZone) {
@@ -3160,14 +3160,14 @@ class DateHelperTest < ActionView::TestCase
end
def test_time_tag_with_date
- date = Date.today
- expected = "<time datetime=\"#{date.rfc3339}\">#{I18n.l(date, :format => :long)}</time>"
+ date = Date.new(2013, 2, 20)
+ expected = '<time datetime="2013-02-20">February 20, 2013</time>'
assert_equal expected, time_tag(date)
end
def test_time_tag_with_time
- time = Time.now
- expected = "<time datetime=\"#{time.xmlschema}\">#{I18n.l(time, :format => :long)}</time>"
+ time = Time.new(2013, 2, 20, 0, 0, 0, '+00:00')
+ expected = '<time datetime="2013-02-20T00:00:00+00:00">February 20, 2013 00:00</time>'
assert_equal expected, time_tag(time)
end
@@ -3184,8 +3184,8 @@ class DateHelperTest < ActionView::TestCase
end
def test_time_tag_with_different_format
- time = Time.now
- expected = "<time datetime=\"#{time.xmlschema}\">#{I18n.l(time, :format => :short)}</time>"
+ time = Time.new(2013, 2, 20, 0, 0, 0, '+00:00')
+ expected = '<time datetime="2013-02-20T00:00:00+00:00">20 Feb 00:00</time>'
assert_equal expected, time_tag(time, :format => :short)
end
diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb
index 757b05dbc1..04cdd068c8 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -21,10 +21,10 @@ class FormOptionsHelperTest < ActionView::TestCase
end
def setup
- @fake_timezones = %w(A B C D E).inject([]) do |zones, id|
+ @fake_timezones = %w(A B C D E).map do |id|
tz = TZInfo::Timezone.loaded_zones[id] = stub(:name => id, :to_s => id)
ActiveSupport::TimeZone.stubs(:[]).with(id).returns(tz)
- zones << tz
+ tz
end
ActiveSupport::TimeZone.stubs(:all).returns(@fake_timezones)
end
@@ -351,7 +351,7 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
- def test_time_zone_options_no_parms
+ def test_time_zone_options_no_params
opts = time_zone_options_for_select
assert_dom_equal "<option value=\"A\">A</option>\n" +
"<option value=\"B\">B</option>\n" +
@@ -416,11 +416,11 @@ class FormOptionsHelperTest < ActionView::TestCase
"<option value=\"D\">D</option>",
opts
end
-
+
def test_time_zone_options_with_priority_zones_does_not_mutate_time_zones
original_zones = ActiveSupport::TimeZone.all.dup
zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ]
- opts = time_zone_options_for_select( nil, zones )
+ time_zone_options_for_select(nil, zones)
assert_equal original_zones, ActiveSupport::TimeZone.all
end
@@ -1086,11 +1086,13 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_time_zone_select_with_priority_zones_as_regexp
@firm = Firm.new("D")
+
+ priority_zones = /A|D/
@fake_timezones.each_with_index do |tz, i|
- tz.stubs(:=~).returns(i.zero? || i == 3)
+ priority_zones.stubs(:===).with(tz).returns(i.zero? || i == 3)
end
- html = time_zone_select("firm", "time_zone", /A|D/)
+ html = time_zone_select("firm", "time_zone", priority_zones)
assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
"<option value=\"A\">A</option>\n" +
"<option value=\"D\" selected=\"selected\">D</option>" +
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 7ddaea1bb0..14520381c9 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -58,7 +58,7 @@ module ActiveRecord
# order. The order will depend on the database implementation.
# If an order is supplied it will be respected.
#
- # Person.take # returns an object fetched by SELECT * FROM people
+ # Person.take # returns an object fetched by SELECT * FROM people LIMIT 1
# Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
# Person.where(["name LIKE '%?'", name]).take
def take(limit = nil)
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index fd6d531645..d0add42e1e 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -20,6 +20,8 @@ require 'models/car'
require 'models/bulb'
require 'models/engine'
require 'models/categorization'
+require 'models/minivan'
+require 'models/speedometer'
class HasManyAssociationsTestForCountWithFinderSql < ActiveRecord::TestCase
class Invoice < ActiveRecord::Base
@@ -1747,4 +1749,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
david.posts_with_special_categorizations = []
assert_equal [], david.posts_with_special_categorizations
end
+
+ test "does not duplicate associations when used with natural primary keys" do
+ speedometer = Speedometer.create!(id: '4')
+ minivan = speedometer.minivans.create!(minivan_id: 'a-van-red' ,name: 'a van', color: 'red')
+
+ assert_equal 1, speedometer.minivans.to_a.size, "Only one association should be present:\n#{speedometer.minivans.to_a}"
+ assert_equal 1, speedometer.reload.minivans.to_a.size
+ end
end
diff --git a/activerecord/test/cases/migration/rename_column_test.rb b/activerecord/test/cases/migration/columns_test.rb
index 88bea2211d..e52809f0f8 100644
--- a/activerecord/test/cases/migration/rename_column_test.rb
+++ b/activerecord/test/cases/migration/columns_test.rb
@@ -2,7 +2,7 @@ require "cases/migration/helper"
module ActiveRecord
class Migration
- class RenameColumnTest < ActiveRecord::TestCase
+ class ColumnsTest < ActiveRecord::TestCase
include ActiveRecord::Migration::TestHelper
self.use_transactional_fixtures = false
@@ -96,10 +96,18 @@ module ActiveRecord
add_index "test_models", ["hat_style", "hat_size"], unique: true
rename_column "test_models", "hat_size", 'size'
- assert_equal ['index_test_models_on_hat_style_and_size'], connection.indexes('test_models').map(&:name)
+ if current_adapter? :OracleAdapter
+ assert_equal ['i_test_models_hat_style_size'], connection.indexes('test_models').map(&:name)
+ else
+ assert_equal ['index_test_models_on_hat_style_and_size'], connection.indexes('test_models').map(&:name)
+ end
rename_column "test_models", "hat_style", 'style'
- assert_equal ['index_test_models_on_style_and_size'], connection.indexes('test_models').map(&:name)
+ if current_adapter? :OracleAdapter
+ assert_equal ['i_test_models_style_size'], connection.indexes('test_models').map(&:name)
+ else
+ assert_equal ['index_test_models_on_style_and_size'], connection.indexes('test_models').map(&:name)
+ end
end
def test_rename_column_does_not_rename_custom_named_index
@@ -128,7 +136,7 @@ module ActiveRecord
assert_equal 1, connection.indexes('test_models').size
remove_column("test_models", "hat_size")
- # Every database and/or database adapter has their own behavior
+ # Every database and/or database adapter has their own behavior
# if it drops the multi-column index when any of the indexed columns dropped by remove_column.
if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
assert_equal [], connection.indexes('test_models').map(&:name)
@@ -245,6 +253,20 @@ module ActiveRecord
def test_remove_column_no_second_parameter_raises_exception
assert_raise(ArgumentError) { connection.remove_column("funny") }
end
+
+ def test_removing_and_renaming_column_preserves_custom_primary_key
+ connection.create_table "my_table", primary_key: "my_table_id", force: true do |t|
+ t.integer "col_one"
+ t.string "col_two", limit: 128, null: false
+ end
+
+ remove_column("my_table", "col_two")
+ rename_column("my_table", "col_one", "col_three")
+
+ assert_equal 'my_table_id', connection.primary_key('my_table')
+ ensure
+ connection.drop_table(:my_table) rescue nil
+ end
end
end
end
diff --git a/activerecord/test/models/speedometer.rb b/activerecord/test/models/speedometer.rb
index 0a7d38d8ec..497c3aba9a 100644
--- a/activerecord/test/models/speedometer.rb
+++ b/activerecord/test/models/speedometer.rb
@@ -1,4 +1,6 @@
class Speedometer < ActiveRecord::Base
self.primary_key = :speedometer_id
belongs_to :dashboard
+
+ has_many :minivans
end
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index daa283e397..4d3dafbb59 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,10 +1,26 @@
## Rails 4.0.0 (unreleased) ##
+* `ActiveSupport::NumberHelper#number_to_human` returns the number unaltered when
+ the given units hash does not contain the needed key, e.g. when the number provided
+ is less than the largest key provided.
+ Fixes #9269.
+
+ Examples:
+
+ number_to_human(123, units: {}) # => 123
+ number_to_human(123, units: { thousand: 'k' }) # => 123
+
+ *Michael Hoffman*
+
+* Added `beginning_of_minute` support to core ext calculations for `Time` and `DateTime`.
+
+ *Gagan Awhad*
+
* Add `:nsec` date format.
*Jamie Gaskins*
-* ActiveSupport::Gzip.compress allows two optional arguments for compression
+* `ActiveSupport::Gzip.compress` allows two optional arguments for compression
level and strategy.
*Beyond*
@@ -106,8 +122,9 @@
*Francesco Rodriguez*
-* Patched Marshal#load to work with constant autoloading.
- Fixes autoloading with cache stores that relay on Marshal(MemCacheStore and FileStore). [fixes #8167]
+* Patched `Marshal#load` to work with constant autoloading. Fixes autoloading
+ with cache stores that rely on `Marshal` (`MemCacheStore` and `FileStore`).
+ Fixes #8167.
*Uriel Katz*
@@ -139,12 +156,11 @@
*Nikita Afanasenko*
-* Dependencies no longer trigger Kernel#autoload in remove_constant [fixes #8213]. *Xavier Noria*
+* Dependencies no longer trigger `Kernel#autoload` in `remove_constant`. Fixes #8213. *Xavier Noria*
* Simplify mocha integration and remove monkey-patches, bumping mocha to 0.13.0. *James Mead*
-* `#as_json` isolates options when encoding a hash.
- Fix #8182
+* `#as_json` isolates options when encoding a hash. Fixes #8182.
*Yves Senn*
diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
index 1d3682eaf2..97aad008f5 100644
--- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -124,6 +124,18 @@ class DateTime
end
alias :at_end_of_hour :end_of_hour
+ # Returns a new DateTime representing the start of the minute (hh:mm:00).
+ def beginning_of_minute
+ change(:sec => 0)
+ end
+ alias :at_beginning_of_minute :beginning_of_minute
+
+ # Returns a new DateTime representing the end of the minute (hh:mm:59).
+ def end_of_minute
+ change(:sec => 59)
+ end
+ alias :at_end_of_minute :end_of_minute
+
# Adjusts DateTime to UTC by adding its offset value; offset is set to 0.
#
# DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index 1f95f62229..a3ce7dbe3f 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -188,6 +188,21 @@ class Time
end
alias :at_end_of_hour :end_of_hour
+ # Returns a new Time representing the start of the minute (x:xx:00)
+ def beginning_of_minute
+ change(:sec => 0)
+ end
+ alias :at_beginning_of_minute :beginning_of_minute
+
+ # Returns a new Time representing the end of the minute, x:xx:59.999999 (.999999999 in ruby1.9)
+ def end_of_minute
+ change(
+ :sec => 59,
+ :usec => Rational(999999999, 1000)
+ )
+ end
+ alias :at_end_of_minute :end_of_minute
+
# Returns a Range representing the whole day of the current time.
def all_day
beginning_of_day..end_of_day
diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb
index 2191471daa..cc935e6cb9 100644
--- a/activesupport/lib/active_support/number_helper.rb
+++ b/activesupport/lib/active_support/number_helper.rb
@@ -580,7 +580,7 @@ module ActiveSupport
unit = case units
when Hash
- units[DECIMAL_UNITS[display_exponent]]
+ units[DECIMAL_UNITS[display_exponent]] || ''
when String, Symbol
I18n.translate(:"#{units}.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
else
diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb
index 24e62cc2b9..59ca2a4059 100644
--- a/activesupport/test/core_ext/date_time_ext_test.rb
+++ b/activesupport/test/core_ext/date_time_ext_test.rb
@@ -88,6 +88,14 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal DateTime.civil(2005,2,4,19,59,59), DateTime.civil(2005,2,4,19,30,10).end_of_hour
end
+ def test_beginning_of_minute
+ assert_equal DateTime.civil(2005,2,4,19,30,0), DateTime.civil(2005,2,4,19,30,10).beginning_of_minute
+ end
+
+ def test_end_of_minute
+ assert_equal DateTime.civil(2005,2,4,19,30,59), DateTime.civil(2005,2,4,19,30,10).end_of_minute
+ end
+
def test_end_of_month
assert_equal DateTime.civil(2005,3,31,23,59,59), DateTime.civil(2005,3,20,10,10,10).end_of_month
assert_equal DateTime.civil(2005,2,28,23,59,59), DateTime.civil(2005,2,20,10,10,10).end_of_month
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index 43c92003dc..2864d7a57f 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -121,6 +121,10 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2005,2,4,19,0,0), Time.local(2005,2,4,19,30,10).beginning_of_hour
end
+ def test_beginning_of_minute
+ assert_equal Time.local(2005,2,4,19,30,0), Time.local(2005,2,4,19,30,10).beginning_of_minute
+ end
+
def test_end_of_day
assert_equal Time.local(2007,8,12,23,59,59,Rational(999999999, 1000)), Time.local(2007,8,12,10,10,10).end_of_day
with_env_tz 'US/Eastern' do
@@ -137,6 +141,10 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2005,2,4,19,59,59,Rational(999999999, 1000)), Time.local(2005,2,4,19,30,10).end_of_hour
end
+ def test_end_of_minute
+ assert_equal Time.local(2005,2,4,19,30,59,Rational(999999999, 1000)), Time.local(2005,2,4,19,30,10).end_of_minute
+ end
+
def test_last_year
assert_equal Time.local(2004,6,5,10), Time.local(2005,6,5,10,0,0).last_year
end
diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb
index c2b3676aac..21fef88d79 100644
--- a/activesupport/test/core_ext/time_with_zone_test.rb
+++ b/activesupport/test/core_ext/time_with_zone_test.rb
@@ -539,6 +539,20 @@ class TimeWithZoneTest < ActiveSupport::TestCase
assert_equal "Fri, 31 Dec 1999 19:59:59 EST -05:00", twz.end_of_hour.inspect
end
+ def test_beginning_of_minute
+ utc = Time.utc(2000, 1, 1, 0, 30, 10)
+ twz = ActiveSupport::TimeWithZone.new(utc, @time_zone)
+ assert_equal "Fri, 31 Dec 1999 19:30:10 EST -05:00", twz.inspect
+ assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", twz.beginning_of_hour.inspect
+ end
+
+ def test_end_of_minute
+ utc = Time.utc(2000, 1, 1, 0, 30, 10)
+ twz = ActiveSupport::TimeWithZone.new(utc, @time_zone)
+ assert_equal "Fri, 31 Dec 1999 19:30:10 EST -05:00", twz.inspect
+ assert_equal "Fri, 31 Dec 1999 19:30:59 EST -05:00", twz.end_of_minute.inspect
+ end
+
def test_since
assert_equal "Fri, 31 Dec 1999 19:00:01 EST -05:00", @twz.since(1).inspect
end
diff --git a/activesupport/test/number_helper_test.rb b/activesupport/test/number_helper_test.rb
index 5f54587f93..1fadef3637 100644
--- a/activesupport/test/number_helper_test.rb
+++ b/activesupport/test/number_helper_test.rb
@@ -301,6 +301,13 @@ module ActiveSupport
end
end
+ def test_number_to_human_with_custom_units_that_are_missing_the_needed_key
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal '123', number_helper.number_to_human(123, units: { thousand: 'k'})
+ assert_equal '123', number_helper.number_to_human(123, units: {})
+ end
+ end
+
def test_number_to_human_with_custom_format
[@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
assert_equal '123 times Thousand', number_helper.number_to_human(123456, :format => "%n times %u")
diff --git a/railties/lib/rails/app_rails_loader.rb b/railties/lib/rails/app_rails_loader.rb
index 8937e10db3..44f4d3dabc 100644
--- a/railties/lib/rails/app_rails_loader.rb
+++ b/railties/lib/rails/app_rails_loader.rb
@@ -3,12 +3,16 @@ require 'pathname'
module Rails
module AppRailsLoader
RUBY = File.join(*RbConfig::CONFIG.values_at("bindir", "ruby_install_name")) + RbConfig::CONFIG["EXEEXT"]
- EXECUTABLE = 'bin/rails'
+ EXECUTABLES = ['bin/rails', 'script/rails']
def self.exec_app_rails
- cwd = Dir.pwd
- return unless in_rails_application_or_engine? || in_rails_application_or_engine_subdirectory?
- exec RUBY, EXECUTABLE, *ARGV if in_rails_application_or_engine?
+ cwd = Dir.pwd
+
+ exe = find_executable
+ exe ||= find_executable_in_parent_path
+ return unless exe
+
+ exec RUBY, exe, *ARGV if find_executable
Dir.chdir("..") do
# Recurse in a chdir block: if the search fails we want to be sure
# the application is generated in the original working directory.
@@ -18,12 +22,16 @@ module Rails
# could not chdir, no problem just return
end
- def self.in_rails_application_or_engine?
- File.exists?(EXECUTABLE) && File.read(EXECUTABLE) =~ /(APP|ENGINE)_PATH/
+ def self.find_executable
+ EXECUTABLES.find do |exe|
+ File.exists?(exe) && File.read(exe) =~ /(APP|ENGINE)_PATH/
+ end
end
- def self.in_rails_application_or_engine_subdirectory?(path = Pathname.new(Dir.pwd))
- File.exists?(File.join(path, EXECUTABLE)) || !path.root? && in_rails_application_or_engine_subdirectory?(path.parent)
+ def self.find_executable_in_parent_path(path = Pathname.new(Dir.pwd))
+ EXECUTABLES.find do |exe|
+ File.exists?(File.join(path, exe)) || !path.root? && find_executable_in_parent_path(path.parent)
+ end
end
end
end
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 1b88b834c7..17763b39c5 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -97,9 +97,9 @@ module Rails
self
end
- # Loads and returns the contents of the #database_configuration_file. The
- # contents of the file are processed via ERB before being sent through
- # YAML::load.
+ # Loads and returns the configuration of the database.
+ # First, looks at If ENV['DATABASE_URL'] if it's not present it uses the #paths["config/database"]
+ # The contents of the file are processed via ERB before being sent through YAML::load.
def database_configuration
if ENV['DATABASE_URL']
{Rails.env => ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.connection_url_to_hash(ENV['DATABASE_URL']).stringify_keys}
diff --git a/railties/lib/rails/cli.rb b/railties/lib/rails/cli.rb
index b717b026de..e5341ac436 100644
--- a/railties/lib/rails/cli.rb
+++ b/railties/lib/rails/cli.rb
@@ -3,9 +3,6 @@ require 'rails/app_rails_loader'
# If we are inside a Rails application this method performs an exec and thus
# the rest of this script is not run.
-#
-# TODO: when we hit this, advise adding ./bin to $PATH instead. Then the
-# app's `rails` executable is run immediately.
Rails::AppRailsLoader.exec_app_rails
require 'rails/ruby_version_check'
diff --git a/railties/lib/rails/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake
index ea6c074bdc..0057b0f887 100644
--- a/railties/lib/rails/tasks/documentation.rake
+++ b/railties/lib/rails/tasks/documentation.rake
@@ -102,7 +102,7 @@ namespace :doc do
# desc "Generate Rails Guides"
task :guides do
# FIXME: Reaching outside lib directory is a bad idea
- require File.expand_path('../../../../guides/rails_guides', __FILE__)
+ require File.expand_path('../../../../../guides/rails_guides', __FILE__)
RailsGuides::Generator.new(Rails.root.join("doc/guides")).generate
end
end
diff --git a/railties/test/app_rails_loader_test.rb b/railties/test/app_rails_loader_test.rb
index 87e0ad7bd7..63ed9eaef0 100644
--- a/railties/test/app_rails_loader_test.rb
+++ b/railties/test/app_rails_loader_test.rb
@@ -2,40 +2,47 @@ require 'abstract_unit'
require 'rails/app_rails_loader'
class AppRailsLoaderTest < ActiveSupport::TestCase
- test "is in a rails application if bin/rails exists and contains APP_PATH" do
- File.stubs(:exists?).returns(true)
- File.stubs(:read).with('bin/rails').returns('APP_PATH')
- assert Rails::AppRailsLoader.in_rails_application_or_engine?
- end
- test "is not in a rails application if bin/rails exists but doesn't contain APP_PATH" do
- File.stubs(:exists?).returns(true)
- File.stubs(:read).with('bin/rails').returns('railties bin/rails')
- assert !Rails::AppRailsLoader.in_rails_application_or_engine?
+ setup do
+ File.stubs(:exists?).returns(false)
end
- test "is in a rails application if parent directory has bin/rails containing APP_PATH" do
- File.stubs(:exists?).with("/foo/bar/bin/rails").returns(false)
- File.stubs(:exists?).with("/foo/bin/rails").returns(true)
- File.stubs(:read).with('/foo/bin/rails').returns('APP_PATH')
- assert Rails::AppRailsLoader.in_rails_application_or_engine_subdirectory?(Pathname.new("/foo/bar"))
- end
+ ['bin/rails', 'script/rails'].each do |exe|
+ test "is in a rails application if #{exe} exists and contains APP_PATH" do
+ File.stubs(:exists?).with(exe).returns(true)
+ File.stubs(:read).with(exe).returns('APP_PATH')
+ assert Rails::AppRailsLoader.find_executable
+ end
- test "is not in a rails application if at the root directory and doesn't have bin/rails" do
- Pathname.any_instance.stubs(:root?).returns true
- assert !Rails::AppRailsLoader.in_rails_application_or_engine?
- end
+ test "is not in a rails application if #{exe} exists but doesn't contain APP_PATH" do
+ File.stubs(:exists?).with(exe).returns(true)
+ File.stubs(:read).with(exe).returns("railties #{exe}")
+ assert !Rails::AppRailsLoader.find_executable
+ end
- test "is in a rails engine if parent directory has bin/rails containing ENGINE_PATH" do
- File.stubs(:exists?).with("/foo/bar/bin/rails").returns(false)
- File.stubs(:exists?).with("/foo/bin/rails").returns(true)
- File.stubs(:read).with('/foo/bin/rails').returns('ENGINE_PATH')
- assert Rails::AppRailsLoader.in_rails_application_or_engine_subdirectory?(Pathname.new("/foo/bar"))
- end
+ test "is in a rails application if parent directory has #{exe} containing APP_PATH" do
+ File.stubs(:exists?).with("/foo/bar/#{exe}").returns(false)
+ File.stubs(:exists?).with("/foo/#{exe}").returns(true)
+ File.stubs(:read).with("/foo/#{exe}").returns('APP_PATH')
+ assert Rails::AppRailsLoader.find_executable_in_parent_path(Pathname.new("/foo/bar"))
+ end
+
+ test "is not in a rails application if at the root directory and doesn't have #{exe}" do
+ Pathname.any_instance.stubs(:root?).returns true
+ assert !Rails::AppRailsLoader.find_executable
+ end
+
+ test "is in a rails engine if parent directory has #{exe} containing ENGINE_PATH" do
+ File.stubs(:exists?).with("/foo/bar/#{exe}").returns(false)
+ File.stubs(:exists?).with("/foo/#{exe}").returns(true)
+ File.stubs(:read).with("/foo/#{exe}").returns('ENGINE_PATH')
+ assert Rails::AppRailsLoader.find_executable_in_parent_path(Pathname.new("/foo/bar"))
+ end
- test "is in a rails engine if bin/rails exists containing ENGINE_PATH" do
- File.stubs(:exists?).returns(true)
- File.stubs(:read).with('bin/rails').returns('ENGINE_PATH')
- assert Rails::AppRailsLoader.in_rails_application_or_engine?
+ test "is in a rails engine if #{exe} exists containing ENGINE_PATH" do
+ File.stubs(:exists?).with(exe).returns(true)
+ File.stubs(:read).with(exe).returns('ENGINE_PATH')
+ assert Rails::AppRailsLoader.find_executable
+ end
end
end