diff options
64 files changed, 381 insertions, 329 deletions
@@ -79,7 +79,7 @@ group :test do end platforms :ruby do - gem 'nokogiri', '>= 1.4.5' + gem 'nokogiri', '>= 1.6.7.rc3' # Needed for compiling the ActionDispatch::Journey parser gem 'racc', '>=1.4.6', require: false @@ -127,3 +127,4 @@ end # A gem necessary for ActiveRecord tests with IBM DB gem 'ibm_db' if ENV['IBM_DB'] +gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] diff --git a/Gemfile.lock b/Gemfile.lock index 44fedddc04..da4614db2b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -29,7 +29,7 @@ GIT GIT remote: git://github.com/rack/rack.git - revision: 4224c028c71c4ccca7cdb3e5a10c51af797a4d4d + revision: c28f271d0c91f45e13bfa8f07bed445ef91f41de branch: master specs: rack (2.0.0.alpha) @@ -37,14 +37,14 @@ GIT GIT remote: git://github.com/rails/arel.git - revision: d5432b4616ff43fbb14540d351eed351e21bb20e + revision: 77ec13b46af2926bfcfc3073685711c874b0d272 branch: master specs: arel (7.0.0.alpha) GIT remote: git://github.com/rails/globalid.git - revision: 8178ff2dc898a8f49dd71f6eb46f2a09712462de + revision: 1d8fca667740570d204fd955a0bd39ac539bac7f branch: master specs: globalid (0.3.6) @@ -52,7 +52,7 @@ GIT GIT remote: git://github.com/rails/jquery-rails.git - revision: 01cb69b17083c8eb8daba13a8daba4907b1c3813 + revision: 04fcfa29b859eef9479f89b6a799d00212902385 branch: master specs: jquery-rails (4.0.5) @@ -62,18 +62,18 @@ GIT GIT remote: git://github.com/rails/sass-rails.git - revision: 805cb17722b8a13ff00dffe20283a6ba2c9a45dc + revision: a3b25261a3d31ed9ff5dd6e841b777790fc86c55 branch: master specs: sass-rails (6.0.0) railties (>= 4.0.0, < 5.0) - sass (~> 3.3) + sass (~> 3.4) sprockets (>= 4.0) sprockets-rails (< 4.0) GIT remote: git://github.com/rails/sprockets-rails.git - revision: e65e088575be4f6b994823b80a277affb0a57a5e + revision: 600f981fe79ff2d4179baf84bd18fac5acb58b5e branch: master specs: sprockets-rails (3.0.0.beta2) @@ -83,11 +83,11 @@ GIT GIT remote: git://github.com/rails/sprockets.git - revision: 408e4ad79df056f6f2199e495782363c22a95c04 + revision: edae5cdfa241b0fb0fcb756b25cd561c3d8b7f29 branch: master specs: sprockets (4.0.0) - rack (~> 2.x) + rack (> 1, < 3) PATH remote: . @@ -151,7 +151,7 @@ GEM remote: https://rubygems.org/ specs: amq-protocol (2.0.0) - backburner (1.0.0) + backburner (1.1.0) beaneater (~> 1.0) dante (> 0.1.5) bcrypt (3.1.10) @@ -160,8 +160,8 @@ GEM beaneater (1.0.0) benchmark-ips (2.3.0) builder (3.2.2) - bunny (2.0.0) - amq-protocol (>= 1.9.2) + bunny (2.2.0) + amq-protocol (>= 2.0.0) byebug (6.0.2) celluloid (0.16.0) timers (~> 4.0.0) @@ -183,8 +183,8 @@ GEM delayed_job (>= 3.0, < 4.1) erubis (2.7.0) execjs (2.6.0) - hitimes (1.2.2) - hitimes (1.2.2-x86-mingw32) + hitimes (1.2.3) + hitimes (1.2.3-x86-mingw32) i18n (0.7.0) json (1.8.3) kindlerb (0.1.1) @@ -194,8 +194,8 @@ GEM nokogiri (>= 1.5.9) metaclass (0.0.4) method_source (0.8.2) - mime-types (2.6.1) - mini_portile (0.6.2) + mime-types (2.6.2) + mini_portile (0.7.0.rc4) minitest (5.3.3) mocha (0.14.0) metaclass (~> 0.0.1) @@ -204,15 +204,15 @@ GEM mustache (1.0.2) mysql (2.9.1) mysql2 (0.4.0) - nokogiri (1.6.6.2) - mini_portile (~> 0.6.0) - nokogiri (1.6.6.2-x64-mingw32) - mini_portile (~> 0.6.0) - nokogiri (1.6.6.2-x86-mingw32) - mini_portile (~> 0.6.0) - pg (0.18.2) + nokogiri (1.6.7.rc3) + mini_portile (~> 0.7.0.rc4) + nokogiri (1.6.7.rc3-x64-mingw32) + mini_portile (~> 0.7.0.rc4) + nokogiri (1.6.7.rc3-x86-mingw32) + mini_portile (~> 0.7.0.rc4) + pg (0.18.3) psych (2.0.15) - que (0.10.0) + que (0.11.2) racc (1.4.12) rack-cache (1.2) rack (>= 0.4) @@ -243,12 +243,12 @@ GEM redis (~> 3.0) resque (~> 1.25) rufus-scheduler (~> 3.0) - rufus-scheduler (3.1.3) - sass (3.4.17) + rufus-scheduler (3.1.4) + sass (3.4.18) sdoc (0.4.1) json (~> 1.7, >= 1.7.7) rdoc (~> 4.0) - sequel (4.25.0) + sequel (4.26.0) serverengine (1.5.10) sigdump (~> 0.2.2) sidekiq (3.4.2) @@ -260,8 +260,8 @@ GEM sigdump (0.2.3) sinatra (1.0) rack (>= 1.0) - sneakers (1.1.1) - bunny (>= 1.7.0, <= 2.0.0) + sneakers (2.2.0) + bunny (~> 2.2.0) serverengine (~> 1.5.5) thor thread (~> 0.1.7) @@ -272,13 +272,15 @@ GEM thor (0.19.1) thread (0.1.7) thread_safe (0.3.5) - timers (4.0.1) + timers (4.0.4) hitimes turbolinks (2.5.3) coffee-rails tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (2.7.1) + tzinfo-data (1.2015.6) + tzinfo (>= 1.0.0) + uglifier (2.7.2) execjs (>= 0.3.0) json (>= 1.8.0) vegas (0.1.11) @@ -314,7 +316,7 @@ DEPENDENCIES mocha (~> 0.14) mysql (>= 2.9.0) mysql2 (>= 0.4.0) - nokogiri (>= 1.4.5) + nokogiri (>= 1.6.7.rc3) pg (>= 0.18.0) psych (~> 2.0) qu-rails! @@ -341,6 +343,7 @@ DEPENDENCIES stackprof sucker_punch turbolinks + tzinfo-data uglifier (>= 1.3.0) w3c_validators diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 0727bb8369..04e5922ce8 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -248,6 +248,7 @@ module ActionController MODULES.each do |mod| include mod end + setup_renderer! # Define some internal variables that should not be propagated to the view. PROTECTED_IVARS = AbstractController::Rendering::DEFAULT_PROTECTED_INSTANCE_VARIABLES + [ diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 030a1f3478..0384740fef 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -140,13 +140,6 @@ module ActionController end end - def self.build_with_env(env = {}) #:nodoc: - new.tap { |c| - c.set_request! ActionDispatch::Request.new(env) - c.set_response! make_response!(c.request) - } - end - # Delegates to the class' <tt>controller_name</tt> def controller_name self.class.controller_name diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index 4214399b6f..00b551af94 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -11,10 +11,17 @@ module ActionController # Documentation at ActionController::Renderer#render delegate :render, to: :renderer - # Returns a renderer class (inherited from ActionController::Renderer) + # Returns a renderer instance (inherited from ActionController::Renderer) # for the controller. - def renderer - @renderer ||= Renderer.for(self) + attr_reader :renderer + + def setup_renderer! # :nodoc: + @renderer = Renderer.for(self) + end + + def inherited(klass) + klass.setup_renderer! + super end end diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index e5f3cb8e8d..5674eef67b 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -137,8 +137,8 @@ module ActionController #:nodoc: def handle_unverified_request request = @controller.request request.session = NullSessionHash.new(request) - request.env['action_dispatch.request.flash_hash'] = nil - request.env['rack.session.options'] = { skip: true } + request.flash = nil + request.session_options = { skip: true } request.cookie_jar = NullCookieJar.build(request, {}) end diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index bf5c7003ff..903dba3eb4 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -97,9 +97,8 @@ module ActionController # environment they should only be set once at boot-time and never mutated at # runtime. # - # <tt>ActionController::Parameters</tt> inherits from - # <tt>ActiveSupport::HashWithIndifferentAccess</tt>, this means - # that you can fetch values using either <tt>:key</tt> or <tt>"key"</tt>. + # You can fetch values of <tt>ActionController::Parameters</tt> using either + # <tt>:key</tt> or <tt>"key"</tt>. # # params = ActionController::Parameters.new(key: 'value') # params[:key] # => "value" diff --git a/actionpack/lib/action_controller/renderer.rb b/actionpack/lib/action_controller/renderer.rb index e8b29c5b5e..e4d19e9dba 100644 --- a/actionpack/lib/action_controller/renderer.rb +++ b/actionpack/lib/action_controller/renderer.rb @@ -34,67 +34,78 @@ module ActionController # ApplicationController.renderer.new(method: 'post', https: true) # class Renderer - class_attribute :controller, :defaults - # Rack environment to render templates in. - attr_reader :env + attr_reader :defaults, :controller - class << self - delegate :render, to: :new + DEFAULTS = { + http_host: 'example.org', + https: false, + method: 'get', + script_name: '', + input: '' + }.freeze - # Create a new renderer class for a specific controller class. - def for(controller) - Class.new self do - self.controller = controller - self.defaults = { - http_host: 'example.org', - https: false, - method: 'get', - script_name: '', - 'rack.input' => '' - } - end - end + # Create a new renderer instance for a specific controller class. + def self.for(controller, env = {}, defaults = DEFAULTS) + new(controller, env, defaults) + end + + # Create a new renderer for the same controller but with a new env. + def new(env = {}) + self.class.new controller, env, defaults + end + + # Create a new renderer for the same controller but with new defaults. + def with_defaults(defaults) + self.class.new controller, env, self.defaults.merge(defaults) end # Accepts a custom Rack environment to render templates in. # It will be merged with ActionController::Renderer.defaults - def initialize(env = {}) - @env = normalize_keys(defaults).merge normalize_keys(env) - @env['action_dispatch.routes'] = controller._routes + def initialize(controller, env, defaults) + @controller = controller + @defaults = defaults + @env = normalize_keys defaults.merge(env) end # Render templates with any options from ActionController::Base#render_to_string. def render(*args) - raise 'missing controller' unless controller? + raise 'missing controller' unless controller - instance = controller.build_with_env(env) + request = ActionDispatch::Request.new @env + request.routes = controller._routes + + instance = controller.new + instance.set_request! request + instance.set_response! controller.make_response!(request) instance.render_to_string(*args) end private def normalize_keys(env) - http_header_format(env).tap do |new_env| - handle_method_key! new_env - handle_https_key! new_env - end + new_env = {} + env.each_pair { |k,v| new_env[rack_key_for(k)] = rack_value_for(k, v) } + new_env end - def http_header_format(env) - env.transform_keys do |key| - key.is_a?(Symbol) ? key.to_s.upcase : key - end - end + RACK_KEY_TRANSLATION = { + http_host: 'HTTP_HOST', + https: 'HTTPS', + method: 'REQUEST_METHOD', + script_name: 'SCRIPT_NAME', + input: 'rack.input' + } - def handle_method_key!(env) - if method = env.delete('METHOD') - env['REQUEST_METHOD'] = method.upcase - end - end + IDENTITY = ->(_) { _ } + + RACK_VALUE_TRANSLATION = { + https: ->(v) { v ? 'on' : 'off' }, + method: ->(v) { v.upcase }, + } + + def rack_key_for(key); RACK_KEY_TRANSLATION[key]; end - def handle_https_key!(env) - if env.has_key? 'HTTPS' - env['HTTPS'] = env['HTTPS'] ? 'on' : 'off' - end + def rack_value_for(key, value) + RACK_VALUE_TRANSLATION.fetch(key, IDENTITY).call value end end end diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 472bb74add..fbbaa1a887 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -78,7 +78,9 @@ module ActionController # params parser middleware, and we should remove this roundtripping # when we switch to caling `call` on the controller - case content_mime_type.ref + case content_mime_type.to_sym + when nil + raise "Unknown Content-Type: #{content_type}" when :json data = ActiveSupport::JSON.encode(non_path_parameters) params = ActiveSupport::JSON.decode(data).with_indifferent_access @@ -90,7 +92,8 @@ module ActionController when :url_encoded_form data = non_path_parameters.to_query else - raise "Unknown Content-Type: #{content_type}" + data = non_path_parameters.to_query + self.request_parameters = non_path_parameters end end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 18504eba6d..b2566c4820 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -324,7 +324,7 @@ module ActionDispatch else self.session = {} end - set_header('action_dispatch.request.flash_hash', nil) + self.flash = nil end def session=(session) #:nodoc: diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index d1e1f1fcf6..45ffacd6f5 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -402,7 +402,7 @@ module ActionDispatch # :nodoc: end def rack_response(status, header) - if NO_CONTENT_CODES.include?(@status) + if NO_CONTENT_CODES.include?(status) header.delete CONTENT_TYPE header.delete 'Content-Length' [status, header, []] diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index 3f7011d100..02b6cfe727 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -53,7 +53,7 @@ module ActionDispatch # # Note that changing the secret key will invalidate all existing sessions! # - # Because CookieStore extends Rack::Session::Abstract::ID, many of the + # Because CookieStore extends Rack::Session::Abstract::Persisted, many of the # options described there can be used to customize the session cookie that # is generated. For example: # diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb index b72953f1d1..47f475559a 100644 --- a/actionpack/lib/action_dispatch/middleware/ssl.rb +++ b/actionpack/lib/action_dispatch/middleware/ssl.rb @@ -15,7 +15,8 @@ module ActionDispatch # # Configure HSTS with `hsts: { … }`: # * `expires`: How long, in seconds, these settings will stick. Defaults to - # `18.weeks`, the minimum required to qualify for browser preload lists. + # `180.days` (recommended). The minimum required to qualify for browser + # preload lists is `18.weeks`. # * `subdomains`: Set to `true` to tell the browser to apply these settings # to all subdomains. This protects your cookies from interception by a # vulnerable site on a subdomain. Defaults to `false`. diff --git a/actionpack/test/controller/renderer_test.rb b/actionpack/test/controller/renderer_test.rb index b55a25430b..16d24fa82a 100644 --- a/actionpack/test/controller/renderer_test.rb +++ b/actionpack/test/controller/renderer_test.rb @@ -1,6 +1,10 @@ require 'abstract_unit' class RendererTest < ActiveSupport::TestCase + test 'action controller base has a renderer' do + assert ActionController::Base.renderer + end + test 'creating with a controller' do controller = CommentsController renderer = ActionController::Renderer.for controller @@ -57,8 +61,7 @@ class RendererTest < ActiveSupport::TestCase end test 'rendering with defaults' do - renderer = ApplicationController.renderer - renderer.defaults[:https] = true + renderer = ApplicationController.renderer.new https: true content = renderer.render inline: '<%= request.ssl? %>' assert_equal 'true', content @@ -67,8 +70,8 @@ class RendererTest < ActiveSupport::TestCase test 'same defaults from the same controller' do renderer_defaults = ->(controller) { controller.renderer.defaults } - assert renderer_defaults[AccountsController].equal? renderer_defaults[AccountsController] - assert_not renderer_defaults[AccountsController].equal? renderer_defaults[CommentsController] + assert_equal renderer_defaults[AccountsController], renderer_defaults[AccountsController] + assert_equal renderer_defaults[AccountsController], renderer_defaults[CommentsController] end test 'rendering with different formats' do @@ -83,18 +86,6 @@ class RendererTest < ActiveSupport::TestCase test 'rendering with helpers' do assert_equal "<p>1\n<br />2</p>", render[inline: '<%= simple_format "1\n2" %>'] end - - test 'rendering from inherited renderer' do - inherited = Class.new ApplicationController.renderer do - defaults[:script_name] = 'script' - def render(options) - super options.merge(locals: { param: :value }) - end - end - - template = '<%= url_for controller: :foo, action: :bar, param: param %>' - assert_equal 'script/foo/bar?param=value', inherited.render(inline: template) - end private def render diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb index b3c3979c84..06bf9dec74 100644 --- a/actionpack/test/controller/test_case_test.rb +++ b/actionpack/test/controller/test_case_test.rb @@ -627,6 +627,31 @@ XML assert_equal "application/json", parsed_env["CONTENT_TYPE"] end + def test_mutating_content_type_headers_for_plain_text_files_sets_the_header + @request.headers['Content-Type'] = 'text/plain' + post :render_body, params: { name: 'foo.txt' } + + assert_equal 'text/plain', @request.headers['Content-type'] + assert_equal 'foo.txt', @request.request_parameters[:name] + assert_equal 'render_body', @request.path_parameters[:action] + end + + def test_mutating_content_type_headers_for_html_files_sets_the_header + @request.headers['Content-Type'] = 'text/html' + post :render_body, params: { name: 'foo.html' } + + assert_equal 'text/html', @request.headers['Content-type'] + assert_equal 'foo.html', @request.request_parameters[:name] + assert_equal 'render_body', @request.path_parameters[:action] + end + + def test_mutating_content_type_headers_for_non_registered_mime_type_raises_an_error + assert_raises(RuntimeError) do + @request.headers['Content-Type'] = 'type/fake' + post :render_body, params: { name: 'foo.fake' } + end + end + def test_id_converted_to_string get :test_params, params: { id: 20, foo: Object.new diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb index 3a9acafaa2..ebf5ea5b77 100644 --- a/actionview/lib/action_view/helpers/form_helper.rb +++ b/actionview/lib/action_view/helpers/form_helper.rb @@ -1880,7 +1880,7 @@ module ActionView # create: "Add %{model}" # # ==== Examples - # button("Create a post") + # button("Create post") # # => <button name='button' type='submit'>Create post</button> # # button do diff --git a/actionview/lib/action_view/record_identifier.rb b/actionview/lib/action_view/record_identifier.rb index 6c6e69101b..4b44eb5520 100644 --- a/actionview/lib/action_view/record_identifier.rb +++ b/actionview/lib/action_view/record_identifier.rb @@ -11,7 +11,7 @@ module ActionView # <%= post.body %> # <% end %> # - # When +post+ is a new, unsaved ActiveRecord::Base intance, the resulting HTML + # When +post+ is a new, unsaved ActiveRecord::Base instance, the resulting HTML # is: # # <div id="new_post" class="post"> diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 554bec17d6..918097449b 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,8 @@ +* Lookup the attribute name for `restrict_with_error` messages on the + model class that defines the association. + + *kuboon*, *Ronak Jangir* + * Correct query for PostgreSQL 8.2 compatibility. *Ben Murphy*, *Matthew Draper* diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index f8211ef9fb..38bda0d2a5 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -15,7 +15,7 @@ module ActiveRecord when :restrict_with_error unless empty? - record = klass.human_attribute_name(reflection.name).downcase + record = owner.class.human_attribute_name(reflection.name).downcase message = owner.errors.generate_message(:base, :'restrict_dependent_destroy.many', record: record, raise: true) rescue nil if message ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index 1829453d73..b1e05c32b5 100644 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -11,7 +11,7 @@ module ActiveRecord when :restrict_with_error if load_target - record = klass.human_attribute_name(reflection.name).downcase + record = owner.class.human_attribute_name(reflection.name).downcase message = owner.errors.generate_message(:base, :'restrict_dependent_destroy.one', record: record, raise: true) rescue nil if message ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb index e85777c335..0c730d313f 100644 --- a/activerecord/lib/active_record/attribute_set/builder.rb +++ b/activerecord/lib/active_record/attribute_set/builder.rb @@ -1,3 +1,5 @@ +require 'active_record/attribute' + module ActiveRecord class AttributeSet # :nodoc: class Builder # :nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 282af220fb..6544b64f52 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -364,7 +364,7 @@ module ActiveRecord # Is there an open connection that is being used for the current thread? # - # This method only works for connections that have been abtained through + # This method only works for connections that have been obtained through # #connection or #with_connection methods, connections obtained through # #checkout will not be detected by #active_connection? def active_connection? @@ -427,7 +427,7 @@ module ActiveRecord # The pool first tries to gain ownership of all connections, if unable to # do so within a timeout interval (default duration is # +spec.config[:checkout_timeout] * 2+ seconds), the pool is forcefully - # disconneted wihout any regard for other connection owning threads. + # disconnected without any regard for other connection owning threads. def disconnect! disconnect(false) end @@ -587,7 +587,7 @@ module ActiveRecord end #-- - # From the discussion on Github: + # From the discussion on GitHub: # https://github.com/rails/rails/pull/14938#commitcomment-6601951 # This hook-in method allows for easier monkey-patching fixes needed by # JRuby users that use Fibers. diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 1e13b24867..107806cd93 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -137,7 +137,7 @@ module ActiveRecord # # In order to get around this problem, #transaction will emulate the effect # of nested transactions, by using savepoints: - # http://dev.mysql.com/doc/refman/5.6/en/savepoint.html + # http://dev.mysql.com/doc/refman/5.7/en/savepoint.html # Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8' # supports savepoints. # @@ -190,7 +190,7 @@ module ActiveRecord # semantics of these different levels: # # * http://www.postgresql.org/docs/current/static/transaction-iso.html - # * https://dev.mysql.com/doc/refman/5.6/en/set-transaction.html + # * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html # # An <tt>ActiveRecord::TransactionIsolationError</tt> will be raised if: # diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 3115e03ea2..2c76dd1518 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -236,8 +236,8 @@ module ActiveRecord # # Available options are (none of these exists by default): # * <tt>:limit</tt> - - # Requests a maximum column length. This is number of characters for <tt>:string</tt> and - # <tt>:text</tt> columns and number of bytes for <tt>:binary</tt> and <tt>:integer</tt> columns. + # Requests a maximum column length. This is number of characters for a <tt>:string</tt> column + # and number of bytes for <tt>:text</tt>, <tt>:binary</tt> and <tt>:integer</tt> columns. # * <tt>:default</tt> - # The column's default value. Use nil for NULL. # * <tt>:null</tt> - diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 08803303cf..16aefc94ab 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -158,7 +158,7 @@ module ActiveRecord # generates: # # CREATE TABLE suppliers ( - # id int(11) DEFAULT NULL auto_increment PRIMARY KEY + # id int(11) auto_increment PRIMARY KEY # ) ENGINE=InnoDB DEFAULT CHARSET=utf8 # # ====== Rename the primary key column @@ -170,7 +170,7 @@ module ActiveRecord # generates: # # CREATE TABLE objects ( - # guid int(11) DEFAULT NULL auto_increment PRIMARY KEY, + # guid int(11) auto_increment PRIMARY KEY, # name varchar(80) # ) # diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 7b47539596..597f0d0597 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -980,14 +980,14 @@ module ActiveRecord defaults = [':default', :default].to_set # Make MySQL reject illegal values rather than truncating or blanking them, see - # http://dev.mysql.com/doc/refman/5.6/en/sql-mode.html#sqlmode_strict_all_tables + # http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_all_tables # If the user has provided another value for sql_mode, don't replace it. unless variables.has_key?('sql_mode') || defaults.include?(@config[:strict]) variables['sql_mode'] = strict_mode? ? 'STRICT_ALL_TABLES' : '' end # NAMES does not have an equals sign, see - # http://dev.mysql.com/doc/refman/5.6/en/set-statement.html#id944430 + # http://dev.mysql.com/doc/refman/5.7/en/set-statement.html#id944430 # (trailing comma because variable_assignments will always have content) if @config[:encoding] encoding = "NAMES #{@config[:encoding]}" @@ -1027,7 +1027,7 @@ module ActiveRecord when 0..0xfff; "varbinary(#{limit})" when nil; "blob" when 0x1000..0xffffffff; "blob(#{limit})" - else raise(ActiveRecordError, "No binary type has character length #{limit}") + else raise(ActiveRecordError, "No binary type has byte length #{limit}") end end @@ -1048,7 +1048,7 @@ module ActiveRecord when nil, 0x100..0xffff; 'text' when 0x10000..0xffffff; 'mediumtext' when 0x1000000..0xffffffff; 'longtext' - else raise(ActiveRecordError, "No text type has character length #{limit}") + else raise(ActiveRecordError, "No text type has byte length #{limit}") end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 0738c59ddf..e4fcff8814 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -58,9 +58,9 @@ module ActiveRecord # * <tt>:password</tt> - Defaults to nothing. # * <tt>:database</tt> - The name of the database. No default, must be provided. # * <tt>:encoding</tt> - (Optional) Sets the client encoding by executing "SET NAMES <encoding>" after connection. - # * <tt>:reconnect</tt> - Defaults to false (See MySQL documentation: http://dev.mysql.com/doc/refman/5.6/en/auto-reconnect.html). - # * <tt>:strict</tt> - Defaults to true. Enable STRICT_ALL_TABLES. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.6/en/sql-mode.html) - # * <tt>:variables</tt> - (Optional) A hash session variables to send as <tt>SET @@SESSION.key = value</tt> on each database connection. Use the value +:default+ to set a variable to its DEFAULT value. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.6/en/set-statement.html). + # * <tt>:reconnect</tt> - Defaults to false (See MySQL documentation: http://dev.mysql.com/doc/refman/5.7/en/auto-reconnect.html). + # * <tt>:strict</tt> - Defaults to true. Enable STRICT_ALL_TABLES. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html) + # * <tt>:variables</tt> - (Optional) A hash session variables to send as <tt>SET @@SESSION.key = value</tt> on each database connection. Use the value +:default+ to set a variable to its DEFAULT value. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.7/en/set-statement.html). # * <tt>:sslca</tt> - Necessary to use MySQL with an SSL connection. # * <tt>:sslkey</tt> - Necessary to use MySQL with an SSL connection. # * <tt>:sslcert</tt> - Necessary to use MySQL with an SSL connection. diff --git a/activerecord/lib/active_record/locking/pessimistic.rb b/activerecord/lib/active_record/locking/pessimistic.rb index 3d95c54ef3..8ecdf76b72 100644 --- a/activerecord/lib/active_record/locking/pessimistic.rb +++ b/activerecord/lib/active_record/locking/pessimistic.rb @@ -51,7 +51,7 @@ module ActiveRecord # end # # Database-specific information on row locking: - # MySQL: http://dev.mysql.com/doc/refman/5.6/en/innodb-locking-reads.html + # MySQL: http://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html # PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE module Pessimistic # Obtain a row lock on this record. Reloads the record to obtain the requested diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index f087a1eaa6..5bdb7213cd 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -941,10 +941,6 @@ module ActiveRecord migrations(migrations_paths).any? end - def last_version - last_migration.version - end - def last_migration #:nodoc: migrations(migrations_paths).last || NullMigration.new end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 2b648978b3..4e0fc407bc 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -66,7 +66,6 @@ module ActiveRecord # # Account.reflections # => {"balance" => AggregateReflection} # - # @api public def reflections @__reflections ||= begin ref = {} @@ -96,7 +95,6 @@ module ActiveRecord # Account.reflect_on_all_associations # returns an array of all associations # Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations # - # @api public def reflect_on_all_associations(macro = nil) association_reflections = reflections.values association_reflections.select! { |reflection| reflection.macro == macro } if macro @@ -108,24 +106,20 @@ module ActiveRecord # Account.reflect_on_association(:owner) # returns the owner AssociationReflection # Invoice.reflect_on_association(:line_items).macro # returns :has_many # - # @api public def reflect_on_association(association) reflections[association.to_s] end - # @api private def _reflect_on_association(association) #:nodoc: _reflections[association.to_s] end # Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled. - # - # @api public def reflect_on_all_autosave_associations reflections.values.select { |reflection| reflection.options[:autosave] } end - def clear_reflections_cache #:nodoc: + def clear_reflections_cache # :nodoc: @__reflections = nil end end diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index c5910fa1ad..fd48ea402a 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -247,7 +247,7 @@ HEADER end def ignored?(table_name) - ['schema_migrations', ignore_tables].flatten.any? do |ignored| + [ActiveRecord::Base.schema_migrations_table_name, ignore_tables].flatten.any? do |ignored| ignored === remove_prefix_and_suffix(table_name) end end diff --git a/activerecord/lib/active_record/schema_migration.rb b/activerecord/lib/active_record/schema_migration.rb index cb47bf23f7..b384529e75 100644 --- a/activerecord/lib/active_record/schema_migration.rb +++ b/activerecord/lib/active_record/schema_migration.rb @@ -2,7 +2,11 @@ require 'active_record/scoping/default' require 'active_record/scoping/named' module ActiveRecord - class SchemaMigration < ActiveRecord::Base + # This class is used to create a table that keeps track of which migrations + # have been applied to a given database. When a migration is run, its schema + # number is inserted in to the `SchemaMigration.table_name` so it doesn't need + # to be executed the next time. + class SchemaMigration < ActiveRecord::Base # :nodoc: class << self def primary_key nil diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb index 673386f0d9..ba5dd0a0d9 100644 --- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb @@ -23,7 +23,7 @@ module ActiveRecord end rescue error_class => error if error.respond_to?(:errno) && error.errno == ACCESS_DENIED_ERROR - $stdout.print error.error + $stdout.print error.message establish_connection root_configuration_without_database connection.create_database configuration['database'], creation_options if configuration['username'] != 'root' diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 887d7a5903..4a569fc242 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -167,7 +167,7 @@ module ActiveRecord # writing, the only database that we're aware of that supports true nested # transactions, is MS-SQL. Because of this, Active Record emulates nested # transactions by using savepoints on MySQL and PostgreSQL. See - # http://dev.mysql.com/doc/refman/5.6/en/savepoint.html + # http://dev.mysql.com/doc/refman/5.7/en/savepoint.html # for more information about savepoints. # # === Callbacks diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 7de5bc01ae..0beaf0056a 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -1482,6 +1482,25 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert firm.companies.exists?(:name => 'child') end + def test_restrict_with_error_with_locale + I18n.backend = I18n::Backend::Simple.new + I18n.backend.store_translations 'en', activerecord: {attributes: {restricted_with_error_firm: {companies: 'client companies'}}} + firm = RestrictedWithErrorFirm.create!(name: 'restrict') + firm.companies.create(name: 'child') + + assert !firm.companies.empty? + + firm.destroy + + assert !firm.errors.empty? + + assert_equal "Cannot delete record because dependent client companies exist", firm.errors[:base].first + assert RestrictedWithErrorFirm.exists?(name: 'restrict') + assert firm.companies.exists?(name: 'child') + ensure + I18n.backend.reload! + end + def test_included_in_collection assert_equal true, companies(:first_firm).clients.include?(Client.find(2)) end diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index d46e7ad235..c9d9e29f09 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -219,6 +219,24 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert firm.account.present? end + def test_restrict_with_error_with_locale + I18n.backend = I18n::Backend::Simple.new + I18n.backend.store_translations 'en', activerecord: {attributes: {restricted_with_error_firm: {account: 'firm account'}}} + firm = RestrictedWithErrorFirm.create!(name: 'restrict') + firm.create_account(credit_limit: 10) + + assert_not_nil firm.account + + firm.destroy + + assert !firm.errors.empty? + assert_equal "Cannot delete record because a dependent firm account exists", firm.errors[:base].first + assert RestrictedWithErrorFirm.exists?(name: 'restrict') + assert firm.account.present? + ensure + I18n.backend.reload! + end + def test_successful_build_association firm = Firm.new("name" => "GlobalMegaCorp") firm.save diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 0edb8a8901..5a93ea3832 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1299,9 +1299,10 @@ class BasicsTest < ActiveRecord::TestCase end def test_compute_type_no_method_error - ActiveSupport::Dependencies.stubs(:safe_constantize).raises(NoMethodError) - assert_raises NoMethodError do - ActiveRecord::Base.send :compute_type, 'InvalidModel' + ActiveSupport::Dependencies.stub(:safe_constantize, proc{ raise NoMethodError }) do + assert_raises NoMethodError do + ActiveRecord::Base.send :compute_type, 'InvalidModel' + end end end @@ -1315,18 +1316,20 @@ class BasicsTest < ActiveRecord::TestCase error = e end - ActiveSupport::Dependencies.stubs(:safe_constantize).raises(e) + ActiveSupport::Dependencies.stub(:safe_constantize, proc{ raise e }) do - exception = assert_raises NameError do - ActiveRecord::Base.send :compute_type, 'InvalidModel' + exception = assert_raises NameError do + ActiveRecord::Base.send :compute_type, 'InvalidModel' + end + assert_equal error.message, exception.message end - assert_equal error.message, exception.message end def test_compute_type_argument_error - ActiveSupport::Dependencies.stubs(:safe_constantize).raises(ArgumentError) - assert_raises ArgumentError do - ActiveRecord::Base.send :compute_type, 'InvalidModel' + ActiveSupport::Dependencies.stub(:safe_constantize, proc{ raise ArgumentError }) do + assert_raises ArgumentError do + ActiveRecord::Base.send :compute_type, 'InvalidModel' + end end end diff --git a/activerecord/test/cases/explain_test.rb b/activerecord/test/cases/explain_test.rb index f1d5511bb8..64dfd86ce2 100644 --- a/activerecord/test/cases/explain_test.rb +++ b/activerecord/test/cases/explain_test.rb @@ -39,38 +39,49 @@ if ActiveRecord::Base.connection.supports_explain? binds = [[], []] queries = sqls.zip(binds) - connection.stubs(:explain).returns('query plan foo', 'query plan bar') - expected = sqls.map {|sql| "EXPLAIN for: #{sql}\nquery plan #{sql}"}.join("\n") - assert_equal expected, base.exec_explain(queries) + stub_explain_for_query_plans do + expected = sqls.map {|sql| "EXPLAIN for: #{sql}\nquery plan #{sql}"}.join("\n") + assert_equal expected, base.exec_explain(queries) + end end def test_exec_explain_with_binds - cols = [Object.new, Object.new] - cols[0].expects(:name).returns('wadus') - cols[1].expects(:name).returns('chaflan') + object = Struct.new(:name) + cols = [object.new('wadus'), object.new('chaflan')] sqls = %w(foo bar) binds = [[[cols[0], 1]], [[cols[1], 2]]] queries = sqls.zip(binds) - connection.stubs(:explain).returns("query plan foo\n", "query plan bar\n") - expected = <<-SQL.strip_heredoc - EXPLAIN for: #{sqls[0]} [["wadus", 1]] - query plan foo + stub_explain_for_query_plans(["query plan foo\n", "query plan bar\n"]) do + expected = <<-SQL.strip_heredoc + EXPLAIN for: #{sqls[0]} [["wadus", 1]] + query plan foo - EXPLAIN for: #{sqls[1]} [["chaflan", 2]] - query plan bar - SQL - assert_equal expected, base.exec_explain(queries) + EXPLAIN for: #{sqls[1]} [["chaflan", 2]] + query plan bar + SQL + assert_equal expected, base.exec_explain(queries) + end end def test_unsupported_connection_adapter - connection.stubs(:supports_explain?).returns(false) + connection.stub(:supports_explain?, false) do + assert_not_called(base.logger, :warn) do + Car.where(:name => 'honda').to_a + end + end + end - base.logger.expects(:warn).never + private - Car.where(:name => 'honda').to_a - end + def stub_explain_for_query_plans(query_plans = ['query plan foo', 'query plan bar']) + explain_called = 0 + + connection.stub(:explain, proc{ explain_called += 1; query_plans[explain_called - 1] }) do + yield + end + end end end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 4b819a82e8..0dc884497c 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -178,8 +178,9 @@ class FinderTest < ActiveRecord::TestCase end def test_exists_does_not_instantiate_records - Developer.expects(:instantiate).never - Developer.exists? + assert_not_called(Developer, :instantiate) do + Developer.exists? + end end def test_find_by_array_of_one_id diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index 64759160dc..e3c4bd9f4a 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -408,9 +408,11 @@ class FixturesWithoutInstantiationTest < ActiveRecord::TestCase end def test_reloading_fixtures_through_accessor_methods + topic = Struct.new(:title) assert_equal "The First Topic", topics(:first).title - @loaded_fixtures['topics']['first'].expects(:find).returns(stub(:title => "Fresh Topic!")) - assert_equal "Fresh Topic!", topics(:first, true).title + assert_called(@loaded_fixtures['topics']['first'], :find, returns: topic.new("Fresh Topic!")) do + assert_equal "Fresh Topic!", topics(:first, true).title + end end end diff --git a/activerecord/test/cases/migration/command_recorder_test.rb b/activerecord/test/cases/migration/command_recorder_test.rb index 99f1dc65b0..1e3529db54 100644 --- a/activerecord/test/cases/migration/command_recorder_test.rb +++ b/activerecord/test/cases/migration/command_recorder_test.rb @@ -31,7 +31,8 @@ module ActiveRecord end def test_unknown_commands_delegate - recorder = CommandRecorder.new(stub(:foo => 'bar')) + recorder = Struct.new(:foo) + recorder = CommandRecorder.new(recorder.new('bar')) assert_equal 'bar', recorder.foo end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 128a242495..10f1c7216f 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -75,15 +75,13 @@ class MigrationTest < ActiveRecord::TestCase ActiveRecord::Migrator.up(migrations_path) assert_equal 3, ActiveRecord::Migrator.current_version - assert_equal 3, ActiveRecord::Migrator.last_version assert_equal false, ActiveRecord::Migrator.needs_migration? ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid") assert_equal 0, ActiveRecord::Migrator.current_version - assert_equal 3, ActiveRecord::Migrator.last_version assert_equal true, ActiveRecord::Migrator.needs_migration? - ActiveRecord::SchemaMigration.create!(:version => ActiveRecord::Migrator.last_version) + ActiveRecord::SchemaMigration.create!(version: 3) assert_equal true, ActiveRecord::Migrator.needs_migration? ensure ActiveRecord::Migrator.migrations_paths = old_path diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index b8a0401fe3..93cb631a04 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -273,10 +273,11 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase end def test_should_modify_an_existing_record_if_there_is_a_matching_composite_id - @ship.stubs(:id).returns('ABC1X') - @pirate.ship_attributes = { :id => @ship.id, :name => 'Davy Jones Gold Dagger' } + @ship.stub(:id, 'ABC1X') do + @pirate.ship_attributes = { :id => @ship.id, :name => 'Davy Jones Gold Dagger' } - assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name + assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name + end end def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy @@ -457,10 +458,11 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase end def test_should_modify_an_existing_record_if_there_is_a_matching_composite_id - @pirate.stubs(:id).returns('ABC1X') - @ship.pirate_attributes = { :id => @pirate.id, :catchphrase => 'Arr' } + @pirate.stub(:id, 'ABC1X') do + @ship.pirate_attributes = { :id => @pirate.id, :catchphrase => 'Arr' } - assert_equal 'Arr', @ship.pirate.catchphrase + assert_equal 'Arr', @ship.pirate.catchphrase + end end def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy @@ -638,17 +640,19 @@ module NestedAttributesOnACollectionAssociationTests end def test_should_take_a_hash_with_composite_id_keys_and_assign_the_attributes_to_the_associated_models - @child_1.stubs(:id).returns('ABC1X') - @child_2.stubs(:id).returns('ABC2X') - - @pirate.attributes = { - association_getter => [ - { :id => @child_1.id, :name => 'Grace OMalley' }, - { :id => @child_2.id, :name => 'Privateers Greed' } - ] - } + @child_1.stub(:id, 'ABC1X') do + @child_2.stub(:id, 'ABC2X') do + + @pirate.attributes = { + association_getter => [ + { :id => @child_1.id, :name => 'Grace OMalley' }, + { :id => @child_2.id, :name => 'Privateers Greed' } + ] + } - assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.name, @child_2.name] + assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.name, @child_2.name] + end + end end def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record diff --git a/activerecord/test/cases/relation/mutation_test.rb b/activerecord/test/cases/relation/mutation_test.rb index ba4d9d2503..88d2dd55ab 100644 --- a/activerecord/test/cases/relation/mutation_test.rb +++ b/activerecord/test/cases/relation/mutation_test.rb @@ -55,9 +55,10 @@ module ActiveRecord test '#order! on non-string does not attempt regexp match for references' do obj = Object.new - obj.expects(:=~).never - assert relation.order!(obj) - assert_equal [obj], relation.order_values + assert_not_called(obj, :=~) do + assert relation.order!(obj) + assert_equal [obj], relation.order_values + end end test '#references!' do diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 29a6ec7522..ec5bdfd725 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -487,13 +487,17 @@ class TransactionTest < ActiveRecord::TestCase end def test_rollback_when_commit_raises - Topic.connection.expects(:begin_db_transaction) - Topic.connection.expects(:commit_db_transaction).raises('OH NOES') - Topic.connection.expects(:rollback_db_transaction) + assert_called(Topic.connection, :begin_db_transaction) do + Topic.connection.stub(:commit_db_transaction, ->{ raise('OH NOES') }) do + assert_called(Topic.connection, :rollback_db_transaction) do - assert_raise RuntimeError do - Topic.transaction do - # do nothing + e = assert_raise RuntimeError do + Topic.transaction do + # do nothing + end + end + assert_equal 'OH NOES', e.message + end end end end diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index fefba5b0fd..80c5fdba17 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -126,14 +126,10 @@ module ActiveSupport def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter) halted_lambda = chain_config[:terminator] - if chain_config.key?(:terminator) && user_conditions.any? + if user_conditions.any? halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter) - elsif chain_config.key? :terminator - halting(callback_sequence, user_callback, halted_lambda, filter) - elsif user_conditions.any? - conditional(callback_sequence, user_callback, user_conditions) else - simple callback_sequence, user_callback + halting(callback_sequence, user_callback, halted_lambda, filter) end end @@ -175,42 +171,15 @@ module ActiveSupport end end private_class_method :halting - - def self.conditional(callback_sequence, user_callback, user_conditions) - callback_sequence.before do |env| - target = env.target - value = env.value - - if user_conditions.all? { |c| c.call(target, value) } - user_callback.call target, value - end - - env - end - end - private_class_method :conditional - - def self.simple(callback_sequence, user_callback) - callback_sequence.before do |env| - user_callback.call env.target, env.value - - env - end - end - private_class_method :simple end class After def self.build(callback_sequence, user_callback, user_conditions, chain_config) if chain_config[:skip_after_callbacks_if_terminated] - if chain_config.key?(:terminator) && user_conditions.any? + if user_conditions.any? halting_and_conditional(callback_sequence, user_callback, user_conditions) - elsif chain_config.key?(:terminator) - halting(callback_sequence, user_callback) - elsif user_conditions.any? - conditional callback_sequence, user_callback, user_conditions else - simple callback_sequence, user_callback + halting(callback_sequence, user_callback) end else if user_conditions.any? @@ -273,14 +242,10 @@ module ActiveSupport class Around def self.build(callback_sequence, user_callback, user_conditions, chain_config) - if chain_config.key?(:terminator) && user_conditions.any? + if user_conditions.any? halting_and_conditional(callback_sequence, user_callback, user_conditions) - elsif chain_config.key? :terminator - halting(callback_sequence, user_callback) - elsif user_conditions.any? - conditional(callback_sequence, user_callback, user_conditions) else - simple(callback_sequence, user_callback) + halting(callback_sequence, user_callback) end end @@ -318,33 +283,6 @@ module ActiveSupport end end private_class_method :halting - - def self.conditional(callback_sequence, user_callback, user_conditions) - callback_sequence.around do |env, &run| - target = env.target - value = env.value - - if user_conditions.all? { |c| c.call(target, value) } - user_callback.call(target, value) { - run.call.value - } - env - else - run.call - end - end - end - private_class_method :conditional - - def self.simple(callback_sequence, user_callback) - callback_sequence.around do |env, &run| - user_callback.call(env.target, env.value) { - run.call.value - } - env - end - end - private_class_method :simple end end diff --git a/activesupport/lib/active_support/core_ext/date_and_time/zones.rb b/activesupport/lib/active_support/core_ext/date_and_time/zones.rb index 96c6df9407..d29a8db5cf 100644 --- a/activesupport/lib/active_support/core_ext/date_and_time/zones.rb +++ b/activesupport/lib/active_support/core_ext/date_and_time/zones.rb @@ -4,7 +4,7 @@ module DateAndTime # if Time.zone_default is set. Otherwise, it returns the current time. # # Time.zone = 'Hawaii' # => 'Hawaii' - # DateTime.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00 + # Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00 # Date.new(2000).in_time_zone # => Sat, 01 Jan 2000 00:00:00 HST -10:00 # # This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt> as the local zone @@ -14,7 +14,6 @@ module DateAndTime # and the conversion will be based on that zone instead of <tt>Time.zone</tt>. # # Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00 - # DateTime.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00 # Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00 def in_time_zone(zone = ::Time.zone) time_zone = ::Time.find_zone! zone diff --git a/activesupport/lib/active_support/core_ext/string/strip.rb b/activesupport/lib/active_support/core_ext/string/strip.rb index 9fdd9d8d2e..a523e76b69 100644 --- a/activesupport/lib/active_support/core_ext/string/strip.rb +++ b/activesupport/lib/active_support/core_ext/string/strip.rb @@ -20,7 +20,6 @@ class String # Technically, it looks for the least indented non-empty line # in the whole string, and removes that amount of leading whitespace. def strip_heredoc - indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0 - gsub(/^[ \t]{#{indent}}/, '') + gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, ''.freeze) end end diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 817522677f..07fc787550 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -132,7 +132,7 @@ module ActiveSupport # Returns a string of the object's date, time, zone and offset from UTC. # - # Time.zone.now.httpdate # => "Thu, 04 Dec 2014 11:00:25 EST -05:00" + # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25 EST -05:00" def inspect "#{time.strftime('%a, %d %b %Y %H:%M:%S')} #{zone} #{formatted_offset}" end diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 2699a064d7..c8dbe92171 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -23,7 +23,7 @@ module ActiveSupport # config.time_zone = 'Eastern Time (US & Canada)' # end # - # Time.zone # => #<TimeZone:0x514834...> + # Time.zone # => #<ActiveSupport::TimeZone:0x514834...> # Time.zone.name # => "Eastern Time (US & Canada)" # Time.zone.now # => Sun, 18 May 2008 14:30:44 EDT -04:00 # @@ -195,7 +195,7 @@ module ActiveSupport # Assumes self represents an offset from UTC in seconds (as returned from # Time#utc_offset) and turns this into an +HH:MM formatted string. # - # TimeZone.seconds_to_utc_offset(-21_600) # => "-06:00" + # ActiveSupport::TimeZone.seconds_to_utc_offset(-21_600) # => "-06:00" def seconds_to_utc_offset(seconds, colon = true) format = colon ? UTC_OFFSET_WITH_COLON : UTC_OFFSET_WITHOUT_COLON sign = (seconds < 0 ? '-' : '+') diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index 19bdea2b8a..9ab2841619 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -1118,7 +1118,7 @@ Rails default exception handling displays a "500 Server Error" message for all e ### The Default 500 and 404 Templates -By default a production application will render either a 404 or a 500 error message. These messages are contained in static HTML files in the `public` folder, in `404.html` and `500.html` respectively. You can customize these files to add some extra information and layout, but remember that they are static; i.e. you can't use RHTML or layouts in them, just plain HTML. +By default a production application will render either a 404 or a 500 error message. These messages are contained in static HTML files in the `public` folder, in `404.html` and `500.html` respectively. You can customize these files to add some extra information and style, but remember that they are static HTML; i.e. you can't use ERB, SCSS, CoffeeScript, or layouts for them. ### `rescue_from` diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index c0a4a0ba39..8ea0f383c0 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -10,7 +10,7 @@ After reading this guide, you will know: * How to find records using a variety of methods and conditions. * How to specify the order, retrieved attributes, grouping, and other properties of the found records. * How to use eager loading to reduce the number of database queries needed for data retrieval. -* How to use dynamic finders methods. +* How to use dynamic finder methods. * How to use method chaining to use multiple ActiveRecord methods together. * How to check for the existence of particular records. * How to perform various calculations on Active Record models. @@ -392,7 +392,7 @@ Now what if that number could vary, say as an argument from somewhere? The find Client.where("orders_count = ?", params[:orders]) ``` -Active Record will go through the first element in the conditions value and any additional elements will replace the question marks `(?)` in the first element. +Active Record will take the first argument as the conditions string and any additional arguments will replace the question marks `(?)` in it. If you want to specify multiple conditions: @@ -420,7 +420,7 @@ TIP: For more information on the dangers of SQL injection, see the [Ruby on Rail #### Placeholder Conditions -Similar to the `(?)` replacement style of params, you can also specify keys/values hash in your array conditions: +Similar to the `(?)` replacement style of params, you can also specify keys in your conditions string along with a corresponding keys/values hash: ```ruby Client.where("created_at >= :start_date AND created_at <= :end_date", @@ -431,7 +431,7 @@ This makes for clearer readability if you have a large number of variable condit ### Hash Conditions -Active Record also allows you to pass in hash conditions which can increase the readability of your conditions syntax. With hash conditions, you pass in a hash with keys of the fields you want conditionalised and the values of how you want to conditionalise them: +Active Record also allows you to pass in hash conditions which can increase the readability of your conditions syntax. With hash conditions, you pass in a hash with keys of the fields you want qualified and the values of how you want to qualify them: NOTE: Only equality, range and subset checking are possible with Hash conditions. @@ -531,7 +531,7 @@ Client.order("orders_count ASC, created_at DESC") Client.order("orders_count ASC", "created_at DESC") ``` -If you want to call `order` multiple times e.g. in different context, new order will append previous one: +If you want to call `order` multiple times, subsequent orders will be appended to the first: ```ruby Client.order("orders_count ASC").order("created_at DESC") @@ -619,9 +619,9 @@ SELECT * FROM clients LIMIT 5 OFFSET 30 Group ----- -To apply a `GROUP BY` clause to the SQL fired by the finder, you can specify the `group` method on the find. +To apply a `GROUP BY` clause to the SQL fired by the finder, you can use the `group` method. -For example, if you want to find a collection of the dates orders were created on: +For example, if you want to find a collection of the dates on which orders were created: ```ruby Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)") @@ -639,7 +639,7 @@ GROUP BY date(created_at) ### Total of grouped items -To get the total of grouped items on a single query call `count` after the `group`. +To get the total of grouped items on a single query, call `count` after the `group`. ```ruby Order.group(:status).count @@ -675,7 +675,7 @@ GROUP BY date(created_at) HAVING sum(price) > 100 ``` -This will return single order objects for each day, but only those that are ordered more than $100 in a day. +This returns the date and total price for each order object, grouped by the day they were ordered and where the price is more than $100. Overriding Conditions --------------------- @@ -705,8 +705,7 @@ Article.where(id: 10, trashed: false).unscope(where: :id) # SELECT "articles".* FROM "articles" WHERE trashed = 0 ``` -A relation which has used `unscope` will affect any relation it is -merged in to: +A relation which has used `unscope` will affect any relation into which it is merged: ```ruby Article.order('id asc').merge(Article.unscope(:order)) @@ -750,7 +749,7 @@ SELECT * FROM articles WHERE id = 10 SELECT * FROM comments WHERE article_id = 10 ORDER BY name ``` -In case the `reorder` clause is not used, the SQL executed would be: +In the case where the `reorder` clause is not used, the SQL executed would be: ```sql SELECT * FROM articles WHERE id = 10 @@ -839,7 +838,7 @@ end Readonly Objects ---------------- -Active Record provides `readonly` method on a relation to explicitly disallow modification of any of the returned objects. Any attempt to alter a readonly record will not succeed, raising an `ActiveRecord::ReadOnlyRecord` exception. +Active Record provides the `readonly` method on a relation to explicitly disallow modification of any of the returned objects. Any attempt to alter a readonly record will not succeed, raising an `ActiveRecord::ReadOnlyRecord` exception. ```ruby client = Client.readonly.first @@ -1052,7 +1051,7 @@ SELECT categories.* FROM categories ### Specifying Conditions on the Joined Tables -You can specify conditions on the joined tables using the regular [Array](#array-conditions) and [String](#pure-string-conditions) conditions. [Hash conditions](#hash-conditions) provides a special syntax for specifying conditions for the joined tables: +You can specify conditions on the joined tables using the regular [Array](#array-conditions) and [String](#pure-string-conditions) conditions. [Hash conditions](#hash-conditions) provide a special syntax for specifying conditions for the joined tables: ```ruby time_range = (Time.now.midnight - 1.day)..Time.now.midnight @@ -1091,7 +1090,7 @@ This code looks fine at the first sight. But the problem lies within the total n Active Record lets you specify in advance all the associations that are going to be loaded. This is possible by specifying the `includes` method of the `Model.find` call. With `includes`, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries. -Revisiting the above case, we could rewrite `Client.limit(10)` to use eager load addresses: +Revisiting the above case, we could rewrite `Client.limit(10)` to eager load addresses: ```ruby clients = Client.includes(:address).limit(10) @@ -1428,7 +1427,7 @@ It's common that you need to find a record or create it if it doesn't exist. You ### `find_or_create_by` -The `find_or_create_by` method checks whether a record with the attributes exists. If it doesn't, then `create` is called. Let's see an example. +The `find_or_create_by` method checks whether a record with the specified attributes exists. If it doesn't, then `create` is called. Let's see an example. Suppose you want to find a client named 'Andy', and if there's none, create one. You can do so by running: @@ -1868,6 +1867,6 @@ following pointers may be helpful: * SQLite3: [EXPLAIN QUERY PLAN](http://www.sqlite.org/eqp.html) -* MySQL: [EXPLAIN Output Format](http://dev.mysql.com/doc/refman/5.6/en/explain-output.html) +* MySQL: [EXPLAIN Output Format](http://dev.mysql.com/doc/refman/5.7/en/explain-output.html) * PostgreSQL: [Using EXPLAIN](http://www.postgresql.org/docs/current/static/using-explain.html) diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md index b99113ed3e..dadac7fb54 100644 --- a/guides/source/active_record_validations.md +++ b/guides/source/active_record_validations.md @@ -273,9 +273,13 @@ available helpers. This method validates that a checkbox on the user interface was checked when a form was submitted. This is typically used when the user needs to agree to your application's terms of service, confirm that some text is read, or any similar -concept. This validation is very specific to web applications and this -'acceptance' does not need to be recorded anywhere in your database (if you -don't have a field for it, the helper will just create a virtual attribute). +concept. + +This validation is very specific to web applications and this +'acceptance' does not need to be recorded anywhere in your database. If you +don't have a field for it, the helper will just create a virtual attribute. If +the field does exist in your database, the `accept` option must be set to +`true` or else the validation will not run. ```ruby class Person < ActiveRecord::Base @@ -636,7 +640,7 @@ class Holiday < ActiveRecord::Base message: "should happen once per year" } end ``` -Should you wish to create a database constraint to prevent possible violations of a uniqueness validation using the `:scope` option, you must create a unique index on both columns in your database. See [the MySQL manual](http://dev.mysql.com/doc/refman/5.6/en/multiple-column-indexes.html) for more details about multiple column indexes or [the PostgreSQL manual](http://www.postgresql.org/docs/current/static/ddl-constraints.html) for examples of unique constraints that refer to a group of columns. +Should you wish to create a database constraint to prevent possible violations of a uniqueness validation using the `:scope` option, you must create a unique index on both columns in your database. See [the MySQL manual](http://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html) for more details about multiple column indexes or [the PostgreSQL manual](http://www.postgresql.org/docs/current/static/ddl-constraints.html) for examples of unique constraints that refer to a group of columns. There is also a `:case_sensitive` option that you can use to define whether the uniqueness constraint will be case sensitive or not. This option defaults to diff --git a/guides/source/i18n.md b/guides/source/i18n.md index 272a0e3623..987320a0f8 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -51,7 +51,7 @@ Thus, the Ruby I18n gem is split into two parts: As a user you should always only access the public methods on the I18n module, but it is useful to know about the capabilities of the backend. -NOTE: It is possible (or even desirable) to swap the shipped Simple backend with a more powerful one, which would store translation data in a relational database, GetText dictionary, or similar. See section [Using different backends](#using-different-backends) below. +NOTE: It is possible to swap the shipped Simple backend with a more powerful one, which would store translation data in a relational database, GetText dictionary, or similar. See section [Using different backends](#using-different-backends) below. ### The Public I18n API diff --git a/guides/source/rails_application_templates.md b/guides/source/rails_application_templates.md index b7364536c3..edd54826cf 100644 --- a/guides/source/rails_application_templates.md +++ b/guides/source/rails_application_templates.md @@ -78,7 +78,7 @@ gem_group :development, :test do end ``` -### add_source(source, options = {}) +### add_source(source, options={}, &block) Adds the given source to the generated application's `Gemfile`. @@ -88,6 +88,14 @@ For example, if you need to source a gem from `"http://code.whytheluckystiff.net add_source "http://code.whytheluckystiff.net" ``` +If block is given, gem entries in block are wrapped into the source group. + +```ruby +add_source "http://gems.github.com/" do + gem "rspec-rails" +end +``` + ### environment/application(data=nil, options={}, &block) Adds a line inside the `Application` class for `config/application.rb`. diff --git a/guides/source/security.md b/guides/source/security.md index 93c270064a..5a6ac9446a 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -245,7 +245,9 @@ Or the attacker places the code into the onmouseover event handler of an image: <img src="http://www.harmless.com/img" width="400" height="400" onmouseover="..." /> ``` -There are many other possibilities, like using a `<script>` tag to make a cross-site request to a URL with a JSONP or JavaScript response. The response is executable code that the attacker can find a way to run, possibly extracting sensitive data. To protect against this data leakage, we disallow cross-site `<script>` tags. Only Ajax requests may have JavaScript responses since `XMLHttpRequest` is subject to the browser Same-Origin policy - meaning only your site can initiate the request. +There are many other possibilities, like using a `<script>` tag to make a cross-site request to a URL with a JSONP or JavaScript response. The response is executable code that the attacker can find a way to run, possibly extracting sensitive data. To protect against this data leakage, we must disallow cross-site `<script>` tags. Ajax requests, however, obey the browser's same-origin policy (only your own site is allowed to initiate `XmlHttpRequest`) so we can safely allow them to return JavaScript responses. + +Note: We can't distinguish a `<script>` tag's origin—whether it's a tag on your own site or on some other malicious site—so we must block all `<script>` across the board, even if it's actually a safe same-origin script served from your own site. In these cases, explicitly skip CSRF protection on actions that serve JavaScript meant for a `<script>` tag. To protect against all other forged requests, we introduce a _required security token_ that our site knows but other sites don't know. We include the security token in requests and verify it on the server. This is a one-liner in your application controller, and is the default for newly created rails applications: diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 30c0fcb294..52464a1c51 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -314,11 +314,11 @@ Upgrading from Rails 4.0 to Rails 4.1 ### CSRF protection from remote `<script>` tags -Or, "whaaat my tests are failing!!!?" +Or, "whaaat my tests are failing!!!?" or "my `<script>` widget is busted!!" Cross-site request forgery (CSRF) protection now covers GET requests with -JavaScript responses, too. This prevents a third-party site from referencing -your JavaScript URL and attempting to run it to extract sensitive data. +JavaScript responses, too. This prevents a third-party site from remotely +referencing your JavaScript with a `<script>` tag to extract sensitive data. This means that your functional and integration tests that use @@ -334,8 +334,9 @@ xhr :get, :index, format: :js to explicitly test an `XmlHttpRequest`. -If you really mean to load JavaScript from remote `<script>` tags, skip CSRF -protection on that action. +Note: Your own `<script>` tags are treated as cross-origin and blocked by +default, too. If you really mean to load JavaScript from `<script>` tags, +you must now explicitly skip CSRF protection on those actions. ### Spring diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index faf6846e4b..f007d11c72 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,8 @@ +* Fix displaying mailer previews on non local requests when config + `action_mailer.show_previews` is set + + *Wojciech Wnętrzak* + * `rails server` will now honour the `PORT` environment variable *David Cornu* diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 38074e80e0..0f44f4694e 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -205,24 +205,21 @@ module Rails end def rails_gemfile_entry - if options.dev? - [ - GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH), + dev_edge_common = [ GemfileEntry.github('sprockets-rails', 'rails/sprockets-rails'), GemfileEntry.github('sprockets', 'rails/sprockets'), GemfileEntry.github('sass-rails', 'rails/sass-rails'), GemfileEntry.github('arel', 'rails/arel'), GemfileEntry.github('rack', 'rack/rack') ] + if options.dev? + [ + GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH) + ] + dev_edge_common elsif options.edge? [ - GemfileEntry.github('rails', 'rails/rails'), - GemfileEntry.github('sprockets-rails', 'rails/sprockets-rails'), - GemfileEntry.github('sprockets', 'rails/sprockets'), - GemfileEntry.github('sass-rails', 'rails/sass-rails'), - GemfileEntry.github('arel', 'rails/arel'), - GemfileEntry.github('rack', 'rack/rack') - ] + GemfileEntry.github('rails', 'rails/rails') + ] + dev_edge_common else [GemfileEntry.version('rails', Rails::VERSION::STRING, diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 6a1c2faaab..975be07622 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -50,8 +50,6 @@ group :development do <% end -%> end <% end -%> -<% if RUBY_PLATFORM.match(/bccwin|cygwin|emx|mingw|mswin|wince|java/) -%> # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] -<% end -%> diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml index f5b62e8fb3..5ca549a8c8 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml @@ -7,7 +7,7 @@ # gem 'activerecord-jdbcmysql-adapter' # # And be sure to use new-style password hashing: -# http://dev.mysql.com/doc/refman/5.6/en/old-client.html +# http://dev.mysql.com/doc/refman/5.7/en/old-client.html # default: &default adapter: mysql diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml index b0767bd93a..119c2fe2c3 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml @@ -7,7 +7,7 @@ # gem 'mysql2' # # And be sure to use new-style password hashing: -# http://dev.mysql.com/doc/refman/5.6/en/old-client.html +# http://dev.mysql.com/doc/refman/5.7/en/old-client.html # default: &default adapter: mysql2 diff --git a/railties/lib/rails/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb index 78a857e0f1..ed0ea9dd4d 100644 --- a/railties/lib/rails/mailers_controller.rb +++ b/railties/lib/rails/mailers_controller.rb @@ -3,7 +3,7 @@ require 'rails/application_controller' class Rails::MailersController < Rails::ApplicationController # :nodoc: prepend_view_path ActionDispatch::DebugExceptions::RESCUES_TEMPLATE_PATH - before_action :require_local! + before_action :require_local!, unless: :show_previews? before_action :find_preview, only: :preview def index @@ -41,6 +41,10 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: end protected + def show_previews? + ActionMailer::Base.show_previews + end + def find_preview candidates = [] params[:path].to_s.scan(%r{/|$}){ candidates << $` } diff --git a/railties/test/application/mailer_previews_test.rb b/railties/test/application/mailer_previews_test.rb index e462d2c15e..643d876a26 100644 --- a/railties/test/application/mailer_previews_test.rb +++ b/railties/test/application/mailer_previews_test.rb @@ -31,7 +31,7 @@ module ApplicationTests test "/rails/mailers is accessible with correct configuraiton" do add_to_config "config.action_mailer.show_previews = true" app("production") - get "/rails/mailers" + get "/rails/mailers", {}, {"REMOTE_ADDR" => "4.2.42.42"} assert_equal 200, last_response.status end |