diff options
-rw-r--r-- | Gemfile.lock | 2 | ||||
-rw-r--r-- | actionpack/CHANGELOG.md | 6 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/middleware/exception_wrapper.rb | 4 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/request/session.rb | 24 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/form_options_helper.rb | 21 | ||||
-rw-r--r-- | actionview/test/actionpack/controller/render_test.rb | 20 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations.rb | 19 | ||||
-rw-r--r-- | activerecord/lib/active_record/attribute_methods/serialization.rb | 3 | ||||
-rw-r--r-- | activerecord/lib/active_record/enum.rb | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/fixtures.rb | 2 | ||||
-rw-r--r-- | activerecord/test/cases/serialized_attribute_test.rb | 8 | ||||
-rw-r--r-- | guides/source/active_job_basics.md | 34 | ||||
-rw-r--r-- | guides/source/testing.md | 7 | ||||
-rw-r--r-- | railties/CHANGELOG.md | 4 | ||||
-rw-r--r-- | railties/lib/rails/test_unit/reporter.rb | 6 | ||||
-rw-r--r-- | railties/test/test_unit/reporter_test.rb | 14 | ||||
-rw-r--r-- | tools/test.rb | 2 |
17 files changed, 118 insertions, 60 deletions
diff --git a/Gemfile.lock b/Gemfile.lock index 3cc20f1c9c..c6d7ad0926 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -308,4 +308,4 @@ DEPENDENCIES w3c_validators BUNDLED WITH - 1.10.2 + 1.10.3 diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 7b2f150c67..78ae506389 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,9 @@ +* Adds`Rack::Utils::ParameterTypeError` and `Rack::Utils::InvalidParameterError` + to the rescue_responses hash in `ExceptionWrapper` (Rack recommends + integrators serve 400s for both of these). + + *Grey Baker* + * Add support for API only apps. ActionController::API is added as a replacement of ActionController::Base for this kind of applications. diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb index d176a73633..8c3d45584d 100644 --- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb +++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb @@ -17,7 +17,9 @@ module ActionDispatch 'ActionController::InvalidCrossOriginRequest' => :unprocessable_entity, 'ActionDispatch::ParamsParser::ParseError' => :bad_request, 'ActionController::BadRequest' => :bad_request, - 'ActionController::ParameterMissing' => :bad_request + 'ActionController::ParameterMissing' => :bad_request, + 'Rack::Utils::ParameterTypeError' => :bad_request, + 'Rack::Utils::InvalidParameterError' => :bad_request ) cattr_accessor :rescue_templates diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb index 773d41de88..a8a3cd20b9 100644 --- a/actionpack/lib/action_dispatch/request/session.rb +++ b/actionpack/lib/action_dispatch/request/session.rb @@ -17,7 +17,7 @@ module ActionDispatch session.merge! session_was if session_was set(env, session) - Options.set(env, Request::Session::Options.new(store, env, default_options)) + Options.set(env, Request::Session::Options.new(store, default_options)) session end @@ -38,20 +38,19 @@ module ActionDispatch env[ENV_SESSION_OPTIONS_KEY] end - def initialize(by, env, default_options) + def initialize(by, default_options) @by = by - @env = env @delegate = default_options.dup end def [](key) - if key == :id - @delegate.fetch(key) { - @delegate[:id] = @by.send(:extract_session_id, @env) - } - else - @delegate[key] - end + @delegate[key] + end + + def id(env) + @delegate.fetch(:id) { + @by.send(:extract_session_id, env) + } end def []=(k,v); @delegate[k] = v; end @@ -68,7 +67,7 @@ module ActionDispatch end def id - options[:id] + options.id(@env) end def options @@ -78,8 +77,7 @@ module ActionDispatch def destroy clear options = self.options || {} - new_sid = @by.send(:destroy_session, @env, options[:id], options) - options[:id] = new_sid # Reset session id with a new value or nil + @by.send(:destroy_session, @env, options.id(@env), options) # Load the new sid to be written with the response @loaded = false diff --git a/actionview/lib/action_view/helpers/form_options_helper.rb b/actionview/lib/action_view/helpers/form_options_helper.rb index d3deee0df3..1b7b188d65 100644 --- a/actionview/lib/action_view/helpers/form_options_helper.rb +++ b/actionview/lib/action_view/helpers/form_options_helper.rb @@ -707,6 +707,27 @@ module ActionView # collection_check_boxes(:post, :author_ids, Author.all, :id, :name_with_initial) do |b| # b.label(:"data-value" => b.value) { b.check_box + b.text } # end + # + # ==== Gotcha + # + # When no selection is made for a collection of checkboxes most + # web browsers will not send any value. + # + # For example, if we have a +User+ model with +category_ids+ field and we + # have the following code in our update action: + # + # @user.update(params[:user]) + # + # If no +category_ids+ are selected then we can safely assume this field + # will not be updated. + # + # This is possible thanks to a hidden field generated by the helper method + # for every collection of checkboxes. + # This hidden field is given the same field name as the checkboxes with a + # blank value. + # + # In the rare case you don't want this hidden field, you can pass the + # <tt>include_hidden: false</tt> option to the helper method. def collection_check_boxes(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block) Tags::CollectionCheckBoxes.new(object, method, self, collection, value_method, text_method, options, html_options).render(&block) end diff --git a/actionview/test/actionpack/controller/render_test.rb b/actionview/test/actionpack/controller/render_test.rb index c4228b5683..ebaf39a12d 100644 --- a/actionview/test/actionpack/controller/render_test.rb +++ b/actionview/test/actionpack/controller/render_test.rb @@ -1,6 +1,5 @@ require 'abstract_unit' require 'active_model' -require 'fileutils' class ApplicationController < ActionController::Base self.view_paths = File.join(FIXTURE_LOAD_PATH, "actionpack") @@ -679,14 +678,6 @@ class RenderTest < ActionController::TestCase ActionView::Base.logger = nil end - def case_sensitive_file_system? - fname = '.case_sensitive_file_system_test' - FileUtils.touch(fname) - !File.exist?(fname.upcase) - ensure - FileUtils.rm_f(fname) - end - # :ported: def test_simple_show get :hello_world @@ -753,15 +744,8 @@ class RenderTest < ActionController::TestCase end def test_render_action_upcased - action = :render_action_upcased_hello_world - - if case_sensitive_file_system? - assert_raise ActionView::MissingTemplate do - get action - end - else - get action - assert_equal 'Hello world!', @response.body + assert_raise ActionView::MissingTemplate do + get :render_action_upcased_hello_world end end diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 1ca648d48d..82cb3fed59 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -955,20 +955,16 @@ module ActiveRecord # The +traps+ association on +Dungeon+ and the +dungeon+ association on +Trap+ are # the inverse of each other and the inverse of the +dungeon+ association on +EvilWizard+ # is the +evil_wizard+ association on +Dungeon+ (and vice-versa). By default, - # Active Record doesn't know anything about these inverse relationships and so no object - # loading optimization is possible. For example: + # Active Record can guess the inverse of the association based on the name + # of the class. The result is the following: # # d = Dungeon.first # t = d.traps.first - # d.level == t.dungeon.level # => true - # d.level = 10 - # d.level == t.dungeon.level # => false + # d.object_id == t.dungeon.object_id # => true # # The +Dungeon+ instances +d+ and <tt>t.dungeon</tt> in the above example refer to - # the same object data from the database, but are actually different in-memory copies - # of that data. Specifying the <tt>:inverse_of</tt> option on associations lets you tell - # Active Record about inverse relationships and it will optimise object loading. For - # example, if we changed our model definitions to: + # the same in-memory instance since the association matches the name of the class. + # The result would be the same if we added +:inverse_of+ to our model definitions: # # class Dungeon < ActiveRecord::Base # has_many :traps, inverse_of: :dungeon @@ -983,15 +979,14 @@ module ActiveRecord # belongs_to :dungeon, inverse_of: :evil_wizard # end # - # Then, from our code snippet above, +d+ and <tt>t.dungeon</tt> are actually the same - # in-memory instance and our final <tt>d.level == t.dungeon.level</tt> will return +true+. - # # There are limitations to <tt>:inverse_of</tt> support: # # * does not work with <tt>:through</tt> associations. # * does not work with <tt>:polymorphic</tt> associations. # * for +belongs_to+ associations +has_many+ inverse associations are ignored. # + # For more information, see the documentation for the +:inverse_of+ option. + # # == Deleting from associations # # === Dependent associations diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index fd7099e0de..e03bf5945d 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -11,6 +11,9 @@ module ActiveRecord # serialized object must be of that class on assignment and retrieval. # Otherwise <tt>SerializationTypeMismatch</tt> will be raised. # + # Empty objects as +{}+, in the case of +Hash+, or +[]+, in the case of + # +Array+, will always be persisted as null. + # # Keep in mind that database adapters handle certain serialization tasks # for you. For instance: +json+ and +jsonb+ types in PostgreSQL will be # converted between JSON object/array syntax and Ruby +Hash+ or +Array+ diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb index ad33c84dbc..84b05d9136 100644 --- a/activerecord/lib/active_record/enum.rb +++ b/activerecord/lib/active_record/enum.rb @@ -89,7 +89,7 @@ module ActiveRecord # enum verification: [:done, :fail], enum_prefix: :verification_status # end # - # Note that <tt>:enum_prefix</tt>/<tt>:enum_postfix</tt> are reserved keywords + # Note that <tt>:enum_prefix</tt>/<tt>:enum_suffix</tt> are reserved keywords # and can not be used as an enum name. module Enum diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 738fab2bd9..b01444a090 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -110,7 +110,7 @@ module ActiveRecord # <% 1.upto(1000) do |i| %> # fix_<%= i %>: # id: <%= i %> - # name: guy_<%= 1 %> + # name: guy_<%= i %> # <% end %> # # This will create 1000 very simple fixtures. diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb index a31c3c828c..6056156698 100644 --- a/activerecord/test/cases/serialized_attribute_test.rb +++ b/activerecord/test/cases/serialized_attribute_test.rb @@ -287,4 +287,12 @@ class SerializedAttributeTest < ActiveRecord::TestCase assert_equal [topic, topic2], Topic.where(content: nil) end + + def test_nil_is_always_persisted_as_null + Topic.serialize(:content, Hash) + + topic = Topic.create!(content: { foo: "bar" }) + topic.update_attribute :content, nil + assert_equal [topic], Topic.where(content: nil) + end end diff --git a/guides/source/active_job_basics.md b/guides/source/active_job_basics.md index 29d0c32b09..22f3c0146a 100644 --- a/guides/source/active_job_basics.md +++ b/guides/source/active_job_basics.md @@ -4,7 +4,7 @@ Active Job Basics ================= This guide provides you with all you need to get started in creating, -enqueueing and executing background jobs. +enqueuing and executing background jobs. After reading this guide, you will know: @@ -20,7 +20,7 @@ Introduction ------------ Active Job is a framework for declaring jobs and making them run on a variety -of queueing backends. These jobs can be everything from regularly scheduled +of queuing backends. These jobs can be everything from regularly scheduled clean-ups, to billing charges, to mailings. Anything that can be chopped up into small units of work and run in parallel, really. @@ -28,11 +28,14 @@ into small units of work and run in parallel, really. The Purpose of Active Job ----------------------------- The main point is to ensure that all Rails apps will have a job infrastructure -in place, even if it's in the form of an "immediate runner". We can then have -framework features and other gems build on top of that, without having to -worry about API differences between various job runners such as Delayed Job -and Resque. Picking your queuing backend becomes more of an operational concern, -then. And you'll be able to switch between them without having to rewrite your jobs. +in place. We can then have framework features and other gems build on top of that, +without having to worry about API differences between various job runners such as +Delayed Job and Resque. Picking your queuing backend becomes more of an operational +concern, then. And you'll be able to switch between them without having to rewrite +your jobs. + +NOTE: Rails by default comes with an "immediate runner" queuing implementation. +That means that each job that has been enqueued will run immediately. Creating a Job @@ -78,7 +81,7 @@ end Enqueue a job like so: ```ruby -# Enqueue a job to be performed as soon the queueing system is +# Enqueue a job to be performed as soon the queuing system is # free. MyJob.perform_later record ``` @@ -99,17 +102,20 @@ That's it! Job Execution ------------- -If no adapter is set, the job is immediately executed. +For enqueuing and executing jobs you need to set up a queuing backend, that is to +say you need to decide for a 3rd-party queuing library that Rails should use. +Rails itself does not provide a sophisticated queuing system and just executes the +job immediately if no adapter is set. ### Backends -Active Job has built-in adapters for multiple queueing backends (Sidekiq, +Active Job has built-in adapters for multiple queuing backends (Sidekiq, Resque, Delayed Job and others). To get an up-to-date list of the adapters see the API Documentation for [ActiveJob::QueueAdapters](http://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html). ### Setting the Backend -You can easily set your queueing backend: +You can easily set your queuing backend: ```ruby # config/application.rb @@ -123,6 +129,10 @@ module YourApp end ``` +NOTE: Since jobs run in parallel to your Rails application, most queuing libraries +require that you start a library-specific queuing service (in addition to +starting your Rails app) for the job processing to work. For information on +how to do that refer to the documentation of your respective library. Queues ------ @@ -212,7 +222,7 @@ end ProcessVideoJob.perform_later(Video.last) ``` -NOTE: Make sure your queueing backend "listens" on your queue name. For some +NOTE: Make sure your queuing backend "listens" on your queue name. For some backends you need to specify the queues to listen to. diff --git a/guides/source/testing.md b/guides/source/testing.md index 230e8162f3..2fd54a48fc 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -141,6 +141,13 @@ users(:david).id email(david.partner.email, david.location_tonight) ``` +To get multiple fixtures at once, you can pass in a list of fixture names. For example: + +```ruby +# this will return an array containing the fixtures david and steve +users(:david, :steve) +``` + ### Console Tasks for Running your Tests Rails comes with a CLI command to run tests. diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 3536929d00..ca07ff349c 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,7 @@ +* Make it possible to customize the executable inside rerun snippets. + + *Yves Senn* + * Add support for API only apps. Middleware stack was slimmed down and it has only the needed middleware for API apps & generators generates the right files, diff --git a/railties/lib/rails/test_unit/reporter.rb b/railties/lib/rails/test_unit/reporter.rb index bfdc9754d4..faf551f381 100644 --- a/railties/lib/rails/test_unit/reporter.rb +++ b/railties/lib/rails/test_unit/reporter.rb @@ -1,7 +1,11 @@ +require "active_support/core_ext/class/attribute" require "minitest" module Rails class TestUnitReporter < Minitest::StatisticsReporter + class_attribute :executable + self.executable = "bin/rails test" + def report return if results.empty? io.puts @@ -15,7 +19,7 @@ module Rails filtered_results.reject!(&:skipped?) unless options[:verbose] filtered_results.map do |result| location, line = result.method(result.name).source_location - "bin/rails test #{relative_path_for(location)}:#{line}" + "#{self.executable} #{relative_path_for(location)}:#{line}" end.join "\n" end diff --git a/railties/test/test_unit/reporter_test.rb b/railties/test/test_unit/reporter_test.rb index 77883612f5..d619a3e515 100644 --- a/railties/test/test_unit/reporter_test.rb +++ b/railties/test/test_unit/reporter_test.rb @@ -43,6 +43,20 @@ class TestUnitReporterTest < ActiveSupport::TestCase assert_rerun_snippet_count 1 end + test "allows to customize the executable in the rerun snippet" do + original_executable = Rails::TestUnitReporter.executable + begin + Rails::TestUnitReporter.executable = "bin/test" + verbose = Rails::TestUnitReporter.new @output, verbose: true + @reporter.record(failed_test) + @reporter.report + + assert_match %r{^bin/test .*test/test_unit/reporter_test.rb:6$}, @output.string + ensure + Rails::TestUnitReporter.executable = original_executable + end + end + private def assert_rerun_snippet_count(snippet_count) assert_equal snippet_count, @output.string.scan(%r{^bin/rails test }).size diff --git a/tools/test.rb b/tools/test.rb index 50cce2081a..70f295b554 100644 --- a/tools/test.rb +++ b/tools/test.rb @@ -8,3 +8,5 @@ module Rails @root ||= Pathname.new(COMPONENT_ROOT) end end + +Rails::TestUnitReporter.executable = "bin/test" |