diff options
20 files changed, 486 insertions, 503 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 78ae506389..05cbe472e0 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -218,13 +218,13 @@ * Preserve default url options when generating URLs. - Fixes an issue that would cause default_url_options to be lost when + Fixes an issue that would cause `default_url_options` to be lost when generating URLs with fewer positional arguments than parameters in the route definition. *Tekin Suleyman* -* Deprecate *_via_redirect integration test methods. +* Deprecate `*_via_redirect` integration test methods. Use `follow_redirect!` manually after the request call for the same behavior. @@ -247,11 +247,11 @@ *Jonas Baumann* -* Deprecate all *_filter callbacks in favor of *_action callbacks. +* Deprecate all `*_filter` callbacks in favor of `*_action` callbacks. *Rafael Mendonça França* -* Allow you to pass `prepend: false` to protect_from_forgery to have the +* Allow you to pass `prepend: false` to `protect_from_forgery` to have the verification callback appended instead of prepended to the chain. This allows you to let the verification step depend on prior callbacks. diff --git a/actionpack/lib/action_controller/api.rb b/actionpack/lib/action_controller/api.rb index d8149e0232..3af63b8892 100644 --- a/actionpack/lib/action_controller/api.rb +++ b/actionpack/lib/action_controller/api.rb @@ -4,7 +4,7 @@ require 'action_controller/log_subscriber' module ActionController # API Controller is a lightweight version of <tt>ActionController::Base</tt>, - # created for applications that don't require all functionality that a complete + # created for applications that don't require all functionalities that a complete # \Rails controller provides, allowing you to create controllers with just the # features that you need for API only applications. # @@ -61,10 +61,10 @@ module ActionController # In some scenarios you may want to add back some functionality provided by # <tt>ActionController::Base</tt> that is not present by default in # <tt>ActionController::API</tt>, for instance <tt>MimeResponds</tt>. This - # module gives you the <tt>respond_to</tt> and <tt>respond_with</tt> methods. - # Adding it is quite simple, you just need to include the module in a specific - # controller or in <tt>ApplicationController</tt> in case you want it - # available to your entire app: + # module gives you the <tt>respond_to</tt> method. Adding it is quite simple, + # you just need to include the module in a specific controller or in + # +ApplicationController+ in case you want it available in your entire + # application: # # class ApplicationController < ActionController::API # include ActionController::MimeResponds @@ -87,16 +87,18 @@ module ActionController class API < Metal abstract! - # Shortcut helper that returns all the ActionController::API modules except the ones passed in the argument: + # Shortcut helper that returns all the ActionController::API modules except + # the ones passed as arguments: # # class MetalController - # ActionController::API.without_modules(:Redirecting, :DataStreaming).each do |left| + # ActionController::API.without_modules(:ForceSSL, :UrlFor).each do |left| # include left # end # end # # This gives better control over what you want to exclude and makes it easier - # to create an api controller class, instead of listing the modules required manually. + # to create an API controller class, instead of listing the modules required + # manually. def self.without_modules(*modules) modules = modules.map do |m| m.is_a?(Symbol) ? ActionController.const_get(m) : m @@ -120,7 +122,7 @@ module ActionController ForceSSL, DataStreaming, - # Before callbacks should also be executed the earliest as possible, so + # Before callbacks should also be executed as early as possible, so # also include them at the bottom. AbstractController::Callbacks, diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 8a4ea70649..cdfc523bd4 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -40,7 +40,7 @@ module ActionController # wrap_parameters :person, include: [:username, :password] # end # - # On ActiveRecord models with no +:include+ or +:exclude+ option set, + # On Active Record models with no +:include+ or +:exclude+ option set, # it will only wrap the parameters returned by the class method # <tt>attribute_names</tt>. # diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index d389d7f6fe..d570f8e965 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* Make `remove_index :table, :column` reversible. + + *Yves Senn* + * Fixed an error which would occur in dirty checking when calling `update_attributes` from a getter. @@ -12,7 +16,7 @@ * Add `:enum_prefix`/`:enum_suffix` option to `enum` definition. - Fixes #17511 and #17415 + Fixes #17511, #17415. *Igor Kapkov* @@ -22,7 +26,7 @@ *Sean Griffin & jmondo* -* Deprecate the PG `:point` type in favor of a new one which will return +* Deprecate the PostgreSQL `:point` type in favor of a new one which will return `Point` objects instead of an `Array` *Sean Griffin* @@ -84,7 +88,8 @@ *Jonathan Worek* -* Pass `:extend` option for `has_and_belongs_to_many` associations to the underlying `has_many :through`. +* Pass `:extend` option for `has_and_belongs_to_many` associations to the + underlying `has_many :through`. *Jaehyun Shin* 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 c8be038d76..49ffd7ccf0 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -587,7 +587,7 @@ module ActiveRecord # # Removes the +index_accounts_on_column+ in the +accounts+ table. # - # remove_index :accounts, :column + # remove_index :accounts, :branch_id # # Removes the index named +index_accounts_on_branch_id+ in the +accounts+ table. # diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb index 84b05d9136..c0d9d9c1c8 100644 --- a/activerecord/lib/active_record/enum.rb +++ b/activerecord/lib/active_record/enum.rb @@ -75,8 +75,8 @@ module ActiveRecord # # Conversation.where("status <> ?", Conversation.statuses[:archived]) # - # You can use <tt>:enum_prefix</tt>/<tt>:enum_suffix</tt> option then you need - # to define multiple enums with same values. If option value is <tt>true</tt>, + # You can use the +:enum_prefix+ or +:enum_suffix+ options when you need + # to define multiple enums with same values. If the passed value is +true+, # the methods are prefixed/suffixed with the name of the enum. # # class Invoice < ActiveRecord::Base diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 192a456846..1e0c04cd23 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -142,6 +142,9 @@ module ActiveRecord # specified by +column_name+. # * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index # specified by +index_name+. + # * <tt>add_reference(:table_name, :reference_name)</tt>: Adds a new column + # +reference_name_id+ by default a integer. See + # ActiveRecord::ConnectionAdapters::SchemaStatements#add_reference for details. # # == Irreversible transformations # diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index ee4545ed71..b592c004aa 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -151,14 +151,16 @@ module ActiveRecord end def invert_remove_index(args) - table, options = *args - - unless options && options.is_a?(Hash) && options[:column] - raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option." + table, options_or_column = *args + if (options = options_or_column).is_a?(Hash) + unless options[:column] + raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option." + end + options = options.dup + [:add_index, [table, options.delete(:column), options]] + elsif (column = options_or_column).present? + [:add_index, [table, column]] end - - options = options.dup - [:add_index, [table, options.delete(:column), options]] end alias :invert_add_belongs_to :invert_add_reference diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index d168786e71..bd8024e143 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -159,7 +159,7 @@ db_namespace = namespace :db do end # desc "Raises an error if there are pending migrations" - task :abort_if_pending_migrations => :environment do + task :abort_if_pending_migrations => [:environment, :load_config] do pending_migrations = ActiveRecord::Migrator.open(ActiveRecord::Migrator.migrations_paths).pending_migrations if pending_migrations.any? diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb index 8144f3e5c5..99230aa3d5 100644 --- a/activerecord/test/cases/invertible_migration_test.rb +++ b/activerecord/test/cases/invertible_migration_test.rb @@ -144,13 +144,17 @@ module ActiveRecord end def test_exception_on_removing_index_without_column_option - RemoveIndexMigration1.new.migrate(:up) - migration = RemoveIndexMigration2.new - migration.migrate(:up) + index_definition = ["horses", [:name, :color]] + migration1 = RemoveIndexMigration1.new + migration1.migrate(:up) + assert migration1.connection.index_exists?(*index_definition) - assert_raises(IrreversibleMigration) do - migration.migrate(:down) - end + migration2 = RemoveIndexMigration2.new + migration2.migrate(:up) + assert_not migration2.connection.index_exists?(*index_definition) + + migration2.migrate(:down) + assert migration2.connection.index_exists?(*index_definition) end def test_migrate_up diff --git a/activerecord/test/cases/migration/command_recorder_test.rb b/activerecord/test/cases/migration/command_recorder_test.rb index 24d3c085a7..90b7c6b38a 100644 --- a/activerecord/test/cases/migration/command_recorder_test.rb +++ b/activerecord/test/cases/migration/command_recorder_test.rb @@ -206,6 +206,11 @@ module ActiveRecord end def test_invert_remove_index + add = @recorder.inverse_of :remove_index, [:table, :one] + assert_equal [:add_index, [:table, :one]], add + end + + def test_invert_remove_index_with_column add = @recorder.inverse_of :remove_index, [:table, {column: [:one, :two], options: true}] assert_equal [:add_index, [:table, [:one, :two], options: true]], add end diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb index eee9bbaead..b2a4404968 100644 --- a/activesupport/lib/active_support/message_verifier.rb +++ b/activesupport/lib/active_support/message_verifier.rb @@ -44,7 +44,7 @@ module ActiveSupport # tampered_message = signed_message.chop # editing the message invalidates the signature # verifier.valid_message?(tampered_message) # => false def valid_message?(signed_message) - return if signed_message.blank? + return if signed_message.nil? || !signed_message.valid_encoding? || signed_message.blank? data, digest = signed_message.split("--") data.present? && digest.present? && ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(data)) diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb index be68bb2e2e..a0764f6d6b 100644 --- a/activesupport/test/inflector_test.rb +++ b/activesupport/test/inflector_test.rb @@ -8,6 +8,20 @@ class InflectorTest < ActiveSupport::TestCase include InflectorTestCases include ConstantizeTestCases + def setup + # Dups the singleton before each test, restoring the original inflections later. + # + # This helper is implemented by setting @__instance__ because in some tests + # there are module functions that access ActiveSupport::Inflector.inflections, + # so we need to replace the singleton itself. + @original_inflections = ActiveSupport::Inflector::Inflections.instance_variable_get(:@__instance__)[:en] + ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: @original_inflections.dup) + end + + def teardown + ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: @original_inflections) + end + def test_pluralize_plurals assert_equal "plurals", ActiveSupport::Inflector.pluralize("plurals") assert_equal "Plurals", ActiveSupport::Inflector.pluralize("Plurals") @@ -26,20 +40,18 @@ class InflectorTest < ActiveSupport::TestCase end def test_uncountable_word_is_not_greedy - with_dup do - uncountable_word = "ors" - countable_word = "sponsor" + uncountable_word = "ors" + countable_word = "sponsor" - ActiveSupport::Inflector.inflections.uncountable << uncountable_word + ActiveSupport::Inflector.inflections.uncountable << uncountable_word - assert_equal uncountable_word, ActiveSupport::Inflector.singularize(uncountable_word) - assert_equal uncountable_word, ActiveSupport::Inflector.pluralize(uncountable_word) - assert_equal ActiveSupport::Inflector.pluralize(uncountable_word), ActiveSupport::Inflector.singularize(uncountable_word) + assert_equal uncountable_word, ActiveSupport::Inflector.singularize(uncountable_word) + assert_equal uncountable_word, ActiveSupport::Inflector.pluralize(uncountable_word) + assert_equal ActiveSupport::Inflector.pluralize(uncountable_word), ActiveSupport::Inflector.singularize(uncountable_word) - assert_equal "sponsor", ActiveSupport::Inflector.singularize(countable_word) - assert_equal "sponsors", ActiveSupport::Inflector.pluralize(countable_word) - assert_equal "sponsor", ActiveSupport::Inflector.singularize(ActiveSupport::Inflector.pluralize(countable_word)) - end + assert_equal "sponsor", ActiveSupport::Inflector.singularize(countable_word) + assert_equal "sponsors", ActiveSupport::Inflector.pluralize(countable_word) + assert_equal "sponsor", ActiveSupport::Inflector.singularize(ActiveSupport::Inflector.pluralize(countable_word)) end SingularToPlural.each do |singular, plural| @@ -70,11 +82,9 @@ class InflectorTest < ActiveSupport::TestCase def test_overwrite_previous_inflectors - with_dup do - assert_equal("series", ActiveSupport::Inflector.singularize("series")) - ActiveSupport::Inflector.inflections.singular "series", "serie" - assert_equal("serie", ActiveSupport::Inflector.singularize("series")) - end + assert_equal("series", ActiveSupport::Inflector.singularize("series")) + ActiveSupport::Inflector.inflections.singular "series", "serie" + assert_equal("serie", ActiveSupport::Inflector.singularize("series")) end MixtureToTitleCase.each_with_index do |(before, titleized), index| @@ -367,10 +377,8 @@ class InflectorTest < ActiveSupport::TestCase %w{plurals singulars uncountables humans}.each do |inflection_type| class_eval <<-RUBY, __FILE__, __LINE__ + 1 def test_clear_#{inflection_type} - with_dup do - ActiveSupport::Inflector.inflections.clear :#{inflection_type} - assert ActiveSupport::Inflector.inflections.#{inflection_type}.empty?, \"#{inflection_type} inflections should be empty after clear :#{inflection_type}\" - end + ActiveSupport::Inflector.inflections.clear :#{inflection_type} + assert ActiveSupport::Inflector.inflections.#{inflection_type}.empty?, \"#{inflection_type} inflections should be empty after clear :#{inflection_type}\" end RUBY end @@ -405,73 +413,63 @@ class InflectorTest < ActiveSupport::TestCase end def test_clear_all - with_dup do - ActiveSupport::Inflector.inflections do |inflect| - # ensure any data is present - inflect.plural(/(quiz)$/i, '\1zes') - inflect.singular(/(database)s$/i, '\1') - inflect.uncountable('series') - inflect.human("col_rpted_bugs", "Reported bugs") - - inflect.clear :all - - assert inflect.plurals.empty? - assert inflect.singulars.empty? - assert inflect.uncountables.empty? - assert inflect.humans.empty? - end + ActiveSupport::Inflector.inflections do |inflect| + # ensure any data is present + inflect.plural(/(quiz)$/i, '\1zes') + inflect.singular(/(database)s$/i, '\1') + inflect.uncountable('series') + inflect.human("col_rpted_bugs", "Reported bugs") + + inflect.clear :all + + assert inflect.plurals.empty? + assert inflect.singulars.empty? + assert inflect.uncountables.empty? + assert inflect.humans.empty? end end def test_clear_with_default - with_dup do - ActiveSupport::Inflector.inflections do |inflect| - # ensure any data is present - inflect.plural(/(quiz)$/i, '\1zes') - inflect.singular(/(database)s$/i, '\1') - inflect.uncountable('series') - inflect.human("col_rpted_bugs", "Reported bugs") - - inflect.clear - - assert inflect.plurals.empty? - assert inflect.singulars.empty? - assert inflect.uncountables.empty? - assert inflect.humans.empty? - end + ActiveSupport::Inflector.inflections do |inflect| + # ensure any data is present + inflect.plural(/(quiz)$/i, '\1zes') + inflect.singular(/(database)s$/i, '\1') + inflect.uncountable('series') + inflect.human("col_rpted_bugs", "Reported bugs") + + inflect.clear + + assert inflect.plurals.empty? + assert inflect.singulars.empty? + assert inflect.uncountables.empty? + assert inflect.humans.empty? end end Irregularities.each do |singular, plural| define_method("test_irregularity_between_#{singular}_and_#{plural}") do - with_dup do - ActiveSupport::Inflector.inflections do |inflect| - inflect.irregular(singular, plural) - assert_equal singular, ActiveSupport::Inflector.singularize(plural) - assert_equal plural, ActiveSupport::Inflector.pluralize(singular) - end + ActiveSupport::Inflector.inflections do |inflect| + inflect.irregular(singular, plural) + assert_equal singular, ActiveSupport::Inflector.singularize(plural) + assert_equal plural, ActiveSupport::Inflector.pluralize(singular) end end end Irregularities.each do |singular, plural| define_method("test_pluralize_of_irregularity_#{plural}_should_be_the_same") do - with_dup do - ActiveSupport::Inflector.inflections do |inflect| - inflect.irregular(singular, plural) - assert_equal plural, ActiveSupport::Inflector.pluralize(plural) - end + ActiveSupport::Inflector.inflections do |inflect| + inflect.irregular(singular, plural) + assert_equal plural, ActiveSupport::Inflector.pluralize(plural) end end end Irregularities.each do |singular, plural| define_method("test_singularize_of_irregularity_#{singular}_should_be_the_same") do - with_dup do - ActiveSupport::Inflector.inflections do |inflect| - inflect.irregular(singular, plural) - assert_equal singular, ActiveSupport::Inflector.singularize(singular) - end + ActiveSupport::Inflector.inflections do |inflect| + inflect.irregular(singular, plural) + assert_equal singular, ActiveSupport::Inflector.singularize(singular) end end end @@ -503,12 +501,10 @@ class InflectorTest < ActiveSupport::TestCase %w(plurals singulars uncountables humans acronyms).each do |scope| define_method("test_clear_inflections_with_#{scope}") do - with_dup do - # clear the inflections - ActiveSupport::Inflector.inflections do |inflect| - inflect.clear(scope) - assert_equal [], inflect.send(scope) - end + # clear the inflections + ActiveSupport::Inflector.inflections do |inflect| + inflect.clear(scope) + assert_equal [], inflect.send(scope) end end end @@ -520,18 +516,4 @@ class InflectorTest < ActiveSupport::TestCase assert_equal "HTTP", ActiveSupport::Inflector.pluralize("HTTP") end - - # Dups the singleton and yields, restoring the original inflections later. - # Use this in tests what modify the state of the singleton. - # - # This helper is implemented by setting @__instance__ because in some tests - # there are module functions that access ActiveSupport::Inflector.inflections, - # so we need to replace the singleton itself. - def with_dup - original = ActiveSupport::Inflector::Inflections.instance_variable_get(:@__instance__)[:en] - ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original.dup) - yield - ensure - ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original) - end end diff --git a/activesupport/test/message_verifier_test.rb b/activesupport/test/message_verifier_test.rb index 6c3519df9a..668d78492e 100644 --- a/activesupport/test/message_verifier_test.rb +++ b/activesupport/test/message_verifier_test.rb @@ -24,6 +24,7 @@ class MessageVerifierTest < ActiveSupport::TestCase data, hash = @verifier.generate(@data).split("--") assert !@verifier.valid_message?(nil) assert !@verifier.valid_message?("") + assert !@verifier.valid_message?("\xff") # invalid encoding assert !@verifier.valid_message?("#{data.reverse}--#{hash}") assert !@verifier.valid_message?("#{data}--#{hash.reverse}") assert !@verifier.valid_message?("purejunk") diff --git a/guides/source/3_0_release_notes.md b/guides/source/3_0_release_notes.md index 9ad32e8168..696493a3cf 100644 --- a/guides/source/3_0_release_notes.md +++ b/guides/source/3_0_release_notes.md @@ -88,7 +88,7 @@ $ cd myapp Rails now uses a `Gemfile` in the application root to determine the gems you require for your application to start. This `Gemfile` is processed by the [Bundler](http://github.com/carlhuda/bundler,) which then installs all your dependencies. It can even install all the dependencies locally to your application so that it doesn't depend on the system gems. -More information: - [bundler homepage](http://gembundler.com) +More information: - [bundler homepage](http://bundler.io/) ### Living on the Edge diff --git a/guides/source/3_1_release_notes.md b/guides/source/3_1_release_notes.md index d753346fa3..327495704a 100644 --- a/guides/source/3_1_release_notes.md +++ b/guides/source/3_1_release_notes.md @@ -151,7 +151,7 @@ $ cd myapp Rails now uses a `Gemfile` in the application root to determine the gems you require for your application to start. This `Gemfile` is processed by the [Bundler](https://github.com/carlhuda/bundler) gem, which then installs all your dependencies. It can even install all the dependencies locally to your application so that it doesn't depend on the system gems. -More information: - [bundler homepage](http://gembundler.com) +More information: - [bundler homepage](http://bundler.io/) ### Living on the Edge diff --git a/guides/source/3_2_release_notes.md b/guides/source/3_2_release_notes.md index 6ddf77d9c0..c52c39b705 100644 --- a/guides/source/3_2_release_notes.md +++ b/guides/source/3_2_release_notes.md @@ -81,7 +81,7 @@ $ cd myapp Rails now uses a `Gemfile` in the application root to determine the gems you require for your application to start. This `Gemfile` is processed by the [Bundler](https://github.com/carlhuda/bundler) gem, which then installs all your dependencies. It can even install all the dependencies locally to your application so that it doesn't depend on the system gems. -More information: [Bundler homepage](http://gembundler.com) +More information: [Bundler homepage](http://bundler.io/) ### Living on the Edge diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md index 9feaff098a..b9444510ea 100644 --- a/guides/source/4_0_release_notes.md +++ b/guides/source/4_0_release_notes.md @@ -36,7 +36,7 @@ $ cd myapp Rails now uses a `Gemfile` in the application root to determine the gems you require for your application to start. This `Gemfile` is processed by the [Bundler](https://github.com/carlhuda/bundler) gem, which then installs all your dependencies. It can even install all the dependencies locally to your application so that it doesn't depend on the system gems. -More information: [Bundler homepage](http://gembundler.com) +More information: [Bundler homepage](http://bundler.io) ### Living on the Edge diff --git a/guides/source/active_record_postgresql.md b/guides/source/active_record_postgresql.md index dcc523eb0f..fe112a4708 100644 --- a/guides/source/active_record_postgresql.md +++ b/guides/source/active_record_postgresql.md @@ -266,13 +266,14 @@ revision = Revision.first revision.identifier # => "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11" ``` -You can use `uuid` type to define references in migrations +You can use `uuid` type to define references in migrations: ```ruby # db/migrate/20150418012400_create_blog.rb -create_table :posts, id: :uuid +enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto') +create_table :posts, id: :uuid, default: 'gen_random_uuid()' -create_table :comments, id: :uuid do |t| +create_table :comments, id: :uuid, default: 'gen_random_uuid()' do |t| # t.belongs_to :post, type: :uuid t.references :post, type: :uuid end @@ -288,6 +289,8 @@ class Comment < ActiveRecord::Base end ``` +See [this section](#uuid-primary-keys) for more details on using UUIDs as primary key. + ### Bit String Types * [type definition](http://www.postgresql.org/docs/current/static/datatype-bit.html) @@ -377,6 +380,9 @@ device = Device.create device.id # => "814865cd-5a1d-4771-9306-4268f188fe9e" ``` +NOTE: `uuid_generate_v4()` (from `uuid-ossp`) is assumed if no `:default` option was +passed to `create_table`. + Full Text Search ---------------- diff --git a/guides/source/api_app.md b/guides/source/api_app.md index 0a6335ed88..29ca872254 100644 --- a/guides/source/api_app.md +++ b/guides/source/api_app.md @@ -1,435 +1,408 @@ -Using Rails for API-only Apps -============================= +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** + + +Using Rails for API-only Applications +===================================== In this guide you will learn: -- What Rails provides for API-only applications -- How to configure Rails to start without any browser features -- How to decide which middlewares you will want to include -- How to decide which modules to use in your controller +* What Rails provides for API-only applications +* How to configure Rails to start without any browser features +* How to decide which middlewares you will want to include +* How to decide which modules to use in your controller -endprologue. +-------------------------------------------------------------------------------- -### What is an API app? +What is an API app? +------------------- -Traditionally, when people said that they used Rails as an “API”, they -meant providing a programmatically accessible API alongside their web -application.\ -For example, GitHub provides [an API](http://developer.github.com) that -you can use from your own custom clients. +Traditionally, when people said that they used Rails as an "API", they meant +providing a programmatically accessible API alongside their web application. +For example, GitHub provides [an API](http://developer.github.com) that you +can use from your own custom clients. -With the advent of client-side frameworks, more developers are using -Rails to build a backend that is shared between their web application -and other native applications. +With the advent of client-side frameworks, more developers are using Rails to +build a back-end that is shared between their web application and other native +applications. -For example, Twitter uses its [public API](https://dev.twitter.com) in -its web application, which is built as a static site that consumes JSON -resources. +For example, Twitter uses its [public API](https://dev.twitter.com) in its web +application, which is built as a static site that consumes JSON resources. -Instead of using Rails to generate dynamic HTML that will communicate -with the server through forms and links, many developers are treating -their web application as just another client, delivered as static HTML, -CSS and JavaScript, and consuming a simple JSON API +Instead of using Rails to generate dynamic HTML that will communicate with the +server through forms and links, many developers are treating their web application +as just another client, delivered as static HTML, CSS and JavaScript consuming +a simple JSON API. -This guide covers building a Rails application that serves JSON -resources to an API client **or** client-side framework. +This guide covers building a Rails application that serves JSON resources to an +API client **or** a client-side framework. -### Why use Rails for JSON APIs? +Why use Rails for JSON APIs? +---------------------------- -The first question a lot of people have when thinking about building a -JSON API using Rails is: “isn’t using Rails to spit out some JSON -overkill? Shouldn’t I just use something like Sinatra?” +The first question a lot of people have when thinking about building a JSON API +using Rails is: "isn't using Rails to spit out some JSON overkill? Shouldn't I +just use something like Sinatra?". For very simple APIs, this may be true. However, even in very HTML-heavy -applications, most of an application’s logic is actually outside of the -view layer. +applications, most of an application's logic is actually outside of the view +layer. -The reason most people use Rails is that it provides a set of defaults -that allows us to get up and running quickly without having to make a -lot of trivial decisions. +The reason most people use Rails is that it provides a set of defaults that +allows us to get up and running quickly without having to make a lot of trivial +decisions. -Let’s take a look at some of the things that Rails provides out of the -box that are still applicable to API applications. +Let's take a look at some of the things that Rails provides out of the box that are +still applicable to API applications. Handled at the middleware layer: -- Reloading: Rails applications support transparent reloading. This - works even if your application gets big and restarting the server - for every request becomes non-viable. -- Development Mode: Rails application come with smart defaults for - development, making development pleasant without compromising - production-time performance. -- Test Mode: Ditto test mode. -- Logging: Rails applications log every request, with a level of - verbosity appropriate for the current mode. Rails logs in - development include information about the request environment, - database queries, and basic performance information. -- Security: Rails detects and thwarts [IP spoofing - attacks](http://en.wikipedia.org/wiki/IP_address_spoofing) and - handles cryptographic signatures in a [timing - attack](http://en.wikipedia.org/wiki/Timing_attack) aware way. Don’t - know what an IP spoofing attack or a timing attack is? Exactly. -- Parameter Parsing: Want to specify your parameters as JSON instead - of as a URL-encoded String? No problem. Rails will decode the JSON - for you and make it available in *params*. Want to use nested - URL-encoded params? That works too. -- Conditional GETs: Rails handles conditional *GET*, (*ETag* and - *Last-Modified*), processing request headers and returning the - correct response headers and status code. All you need to do is use - the - [stale?](http://api.rubyonrails.org/classes/ActionController/ConditionalGet.html#method-i-stale-3F) - check in your controller, and Rails will handle all of the HTTP - details for you. -- Caching: If you use *dirty?* with public cache control, Rails will - automatically cache your responses. You can easily configure the - cache store. -- HEAD requests: Rails will transparently convert *HEAD* requests into - *GET* requests, and return just the headers on the way out. This - makes *HEAD* work reliably in all Rails APIs. - -While you could obviously build these up in terms of existing Rack -middlewares, I think this list demonstrates that the default Rails -middleware stack provides a lot of value, even if you’re “just -generating JSON”. - -Handled at the ActionPack layer: - -- Resourceful Routing: If you’re building a RESTful JSON API, you want - to be using the Rails router. Clean and conventional mapping from - HTTP to controllers means not having to spend time thinking about - how to model your API in terms of HTTP. -- URL Generation: The flip side of routing is URL generation. A good - API based on HTTP includes URLs (see [the GitHub gist - API](http://developer.github.com/v3/gists/) for an example). -- Header and Redirection Responses: *head :no\_content* and - *redirect\_to user\_url(current\_user)* come in handy. Sure, you - could manually add the response headers, but why? -- Caching: Rails provides page, action and fragment caching. Fragment - caching is especially helpful when building up a nested JSON object. -- Basic, Digest and Token Authentication: Rails comes with - out-of-the-box support for three kinds of HTTP authentication. -- Instrumentation: Rails 3.0 added an instrumentation API that will - trigger registered handlers for a variety of events, such as action - processing, sending a file or data, redirection, and database - queries. The payload of each event comes with relevant information - (for the action processing event, the payload includes the - controller, action, params, request format, request method and the - request’s full path). -- Generators: This may be passé for advanced Rails users, but it can - be nice to generate a resource and get your model, controller, test - stubs, and routes created for you in a single command. -- Plugins: Many third-party libraries come with support for Rails that - reduces or eliminates the cost of setting up and gluing together the - library and the web framework. This includes things like overriding - default generators, adding rake tasks, and honoring Rails choices - (like the logger and cache backend). - -Of course, the Rails boot process also glues together all registered -components. For example, the Rails boot process is what uses your -*config/database.yml* file when configuring ActiveRecord. - -**The short version is**: you may not have thought about which parts of -Rails are still applicable even if you remove the view layer, but the -answer turns out to be “most of it”. - -### The Basic Configuration - -If you’re building a Rails application that will be an API server first -and foremost, you can start with a more limited subset of Rails and add -in features as needed. +- Reloading: Rails applications support transparent reloading. This works even if + your application gets big and restarting the server for every request becomes + non-viable. +- Development Mode: Rails applications come with smart defaults for development, + making development pleasant without compromising production-time performance. +- Test Mode: Ditto development mode. +- Logging: Rails applications log every request, with a level of verbosity + appropriate for the current mode. Rails logs in development include information + about the request environment, database queries, and basic performance + information. +- Security: Rails detects and thwarts [IP spoofing + attacks](http://en.wikipedia.org/wiki/IP_address_spoofing) and handles + cryptographic signatures in a [timing + attack](http://en.wikipedia.org/wiki/Timing_attack) aware way. Don't know what + an IP spoofing attack or a timing attack is? Exactly. +- Parameter Parsing: Want to specify your parameters as JSON instead of as a + URL-encoded String? No problem. Rails will decode the JSON for you and make + it available in `params`. Want to use nested URL-encoded parameters? That + works too. +- Conditional GETs: Rails handles conditional `GET`, (`ETag` and `Last-Modified`), + processing request headers and returning the correct response headers and status + code. All you need to do is use the + [`stale?`](http://api.rubyonrails.org/classes/ActionController/ConditionalGet.html#method-i-stale-3F) + check in your controller, and Rails will handle all of the HTTP details for you. +- Caching: If you use `dirty?` with public cache control, Rails will automatically + cache your responses. You can easily configure the cache store. +- HEAD requests: Rails will transparently convert `HEAD` requests into `GET` ones, + and return just the headers on the way out. This makes `HEAD` work reliably in + all Rails APIs. + +While you could obviously build these up in terms of existing Rack middlewares, +this list demonstrates that the default Rails middleware stack provides a lot +of value, even if you're "just generating JSON". + +Handled at the Action Pack layer: + +- Resourceful Routing: If you're building a RESTful JSON API, you want to be + using the Rails router. Clean and conventional mapping from HTTP to controllers + means not having to spend time thinking about how to model your API in terms + of HTTP. +- URL Generation: The flip side of routing is URL generation. A good API based + on HTTP includes URLs (see [the GitHub gist API](http://developer.github.com/v3/gists/) + for an example). +- Header and Redirection Responses: `head :no_content` and + `redirect_to user_url(current_user)` come in handy. Sure, you could manually + add the response headers, but why? +- Caching: Rails provides page, action and fragment caching. Fragment caching + is especially helpful when building up a nested JSON object. +- Basic, Digest and Token Authentication: Rails comes with out-of-the-box support + for three kinds of HTTP authentication. +- Instrumentation: Rails has an instrumentation API that will trigger registered + handlers for a variety of events, such as action processing, sending a file or + data, redirection, and database queries. The payload of each event comes with + relevant information (for the action processing event, the payload includes + the controller, action, parameters, request format, request method and the + request's full path). +- Generators: This may be passé for advanced Rails users, but it can be nice to + generate a resource and get your model, controller, test stubs, and routes + created for you in a single command. +- Plugins: Many third-party libraries come with support for Rails that reduce + or eliminate the cost of setting up and gluing together the library and the + web framework. This includes things like overriding default generators, adding + rake tasks, and honoring Rails choices (like the logger and cache back-end). + +Of course, the Rails boot process also glues together all registered components. +For example, the Rails boot process is what uses your `config/database.yml` file +when configuring Active Record. + +**The short version is**: you may not have thought about which parts of Rails +are still applicable even if you remove the view layer, but the answer turns out +to be "most of it". + +The Basic Configuration +----------------------- + +If you're building a Rails application that will be an API server first and +foremost, you can start with a more limited subset of Rails and add in features +as needed. You can generate a new api Rails app: -<shell>\ -\$ rails new my\_api --api\ -</shell> +```bash +$ rails new my_api --api +``` This will do three main things for you: -- Configure your application to start with a more limited set of - middleware than normal. Specifically, it will not include any - middleware primarily useful for browser applications (like cookie - support) by default. -- Make *ApplicationController* inherit from *ActionController::API* - instead of *ActionController::Base*. As with middleware, this will - leave out any *ActionController* modules that provide functionality - primarily used by browser applications. -- Configure the generators to skip generating views, helpers and - assets when you generate a new resource. - -If you want to take an existing app and make it an API app, follow the +- Configure your application to start with a more limited set of middlewares + than normal. Specifically, it will not include any middleware primarily useful + for browser applications (like cookies support) by default. +- Make `ApplicationController` inherit from `ActionController::API` instead of + `ActionController::Base`. As with middlewares, this will leave out any Action + Controller modules that provide functionalities primarily used by browser + applications. +- Configure the generators to skip generating views, helpers and assets when + you generate a new resource. + +If you want to take an existing application and make it an API one, read the following steps. -In *config/application.rb* add the following line at the top of the -*Application* class: - -<ruby>\ -config.api\_only!\ -</ruby> - -Change *app/controllers/application\_controller.rb*: - -<ruby> - -1. instead of\ - class ApplicationController \< ActionController::Base\ - end - -<!-- --> - -1. do\ - class ApplicationController \< ActionController::API\ - end\ - </ruby> - -### Choosing Middlewares - -An API application comes with the following middlewares by default. - -- *Rack::Cache*: Caches responses with public *Cache-Control* headers - using HTTP caching semantics. See below for more information. -- *Rack::Sendfile*: Uses a front-end server’s file serving support - from your Rails application. -- *Rack::Lock*: If your application is not marked as threadsafe - (*config.threadsafe!*), this middleware will add a mutex around your - requests. -- *ActionDispatch::RequestId*: -- *Rails::Rack::Logger*: -- *Rack::Runtime*: Adds a header to the response listing the total - runtime of the request. -- *ActionDispatch::ShowExceptions*: Rescue exceptions and re-dispatch - them to an exception handling application -- *ActionDispatch::DebugExceptions*: Log exceptions -- *ActionDispatch::RemoteIp*: Protect against IP spoofing attacks -- *ActionDispatch::Reloader*: In development mode, support code - reloading. -- *ActionDispatch::ParamsParser*: Parse XML, YAML and JSON parameters - when the request’s *Content-Type* is one of those. -- *ActionDispatch::Head*: Dispatch *HEAD* requests as *GET* requests, - and return only the status code and headers. -- *Rack::ConditionalGet*: Supports the *stale?* feature in Rails - controllers. -- *Rack::ETag*: Automatically set an *ETag* on all string responses. - This means that if the same response is returned from a controller - for the same URL, the server will return a *304 Not Modified*, even - if no additional caching steps are taken. This is primarily a - client-side optimization; it reduces bandwidth costs but not server - processing time. - -Other plugins, including *ActiveRecord*, may add additional middlewares. -In general, these middlewares are agnostic to the type of app you are +In `config/application.rb` add the following line at the top of the `Application` +class definition: + +```ruby +config.api_only = true +``` + +Finally, inside `app/controllers/application_controller.rb`, instead of: + +```ruby +class ApplicationController < ActionController::Base +end +``` + +do: + +```ruby +class ApplicationController < ActionController::API +end +``` + +Choosing Middlewares +-------------------- + +An API application comes with the following middlewares by default: + +- `Rack::Sendfile` +- `ActionDispatch::Static` +- `Rack::Lock` +- `ActiveSupport::Cache::Strategy::LocalCache::Middleware` +- `ActionDispatch::RequestId` +- `Rails::Rack::Logger` +- `Rack::Runtime` +- `ActionDispatch::ShowExceptions` +- `ActionDispatch::DebugExceptions` +- `ActionDispatch::RemoteIp` +- `ActionDispatch::Reloader` +- `ActionDispatch::Callbacks` +- `ActionDispatch::ParamsParser` +- `Rack::Head` +- `Rack::ConditionalGet` +- `Rack::ETag` + +See the [internal middlewares](rails_on_rack.html#internal-middleware-stack) +section of the Rack guide for further information on them. + +Other plugins, including Active Record, may add additional middlewares. In +general, these middlewares are agnostic to the type of application you are building, and make sense in an API-only Rails application. You can get a list of all middlewares in your application via: -<shell>\ -\$ rake middleware\ -</shell> +```bash +$ rake middleware +``` -#### Using Rack::Cache +### Using the Cache Middleware -When used with Rails, *Rack::Cache* uses the Rails cache store for its -entity and meta stores. This means that if you use memcache, for your -Rails app, for instance, the built-in HTTP cache will use memcache. +By default, Rails will add a middleware that provides a cache store based on +the configuration of your application (memcache by default). This means that +the built-in HTTP cache will rely on it. -To make use of *Rack::Cache*, you will want to use *stale?* in your -controller. Here’s an example of *stale?* in use. +For instance, using the `stale?` method: -<ruby>\ -def show\ +```ruby +def show @post = Post.find(params[:id]) -if stale?(:last\_modified =\> `post.updated_at) - render json: `post\ - end\ -end\ -</ruby> + if stale?(last_modified: @post.updated_at) + render json: @post + end +end +``` -The call to *stale?* will compare the *If-Modified-Since* header in the -request with *@post.updated\_at*. If the header is newer than the last -modified, this action will return a *304 Not Modified* response. -Otherwise, it will render the response and include a *Last-Modified* -header with the response. +The call to `stale?` will compare the `If-Modified-Since` header in the request +with `@post.updated_at`. If the header is newer than the last modified, this +action will return a "304 Not Modified" response. Otherwise, it will render the +response and include a `Last-Modified` header in it. -Normally, this mechanism is used on a per-client basis. *Rack::Cache* +Normally, this mechanism is used on a per-client basis. The cache middleware allows us to share this caching mechanism across clients. We can enable -cross-client caching in the call to *stale?* +cross-client caching in the call to `stale?`: -<ruby>\ -def show\ +```ruby +def show @post = Post.find(params[:id]) -if stale?(:last\_modified =\> `post.updated_at, :public => true) - render json: `post\ - end\ -end\ -</ruby> + if stale?(last_modified: @post.updated_at, public: true) + render json: @post + end +end +``` -This means that *Rack::Cache* will store off *Last-Modified* value for a -URL in the Rails cache, and add an *If-Modified-Since* header to any +This means that the cache middleware will store off the `Last-Modified` value +for a URL in the Rails cache, and add an `If-Modified-Since` header to any subsequent inbound requests for the same URL. Think of it as page caching using HTTP semantics. -NOTE: The *Rack::Cache* middleware is always outside of the *Rack::Lock* -mutex, even in single-threaded apps. +NOTE: This middleware is always outside of the `Rack::Lock` mutex, even in +single-threaded applications. -#### Using Rack::Sendfile +### Using Rack::Sendfile -When you use the *send\_file* method in a Rails controller, it sets the -*X-Sendfile* header. *Rack::Sendfile* is responsible for actually -sending the file. +When you use the `send_file` method inside a Rails controller, it sets the +`X-Sendfile` header. `Rack::Sendfile` is responsible for actually sending the +file. -If your front-end server supports accelerated file sending, -*Rack::Sendfile* will offload the actual file sending work to the -front-end server. +If your front-end server supports accelerated file sending, `Rack::Sendfile` +will offload the actual file sending work to the front-end server. -You can configure the name of the header that your front-end server uses -for this purposes using *config.action\_dispatch.x\_sendfile\_header* in -the appropriate environment config file. +You can configure the name of the header that your front-end server uses for +this purpose using `config.action_dispatch.x_sendfile_header` in the appropriate +environment's configuration file. -You can learn more about how to use *Rack::Sendfile* with popular +You can learn more about how to use `Rack::Sendfile` with popular front-ends in [the Rack::Sendfile -documentation](http://rubydoc.info/github/rack/rack/master/Rack/Sendfile) +documentation](http://rubydoc.info/github/rack/rack/master/Rack/Sendfile). -The values for popular servers once they are configured to support +Here are some values for popular servers, once they are configured, to support accelerated file sending: -<ruby> - -1. Apache and lighttpd\ - config.action\_dispatch.x\_sendfile\_header = “X-Sendfile” - -<!-- --> - -1. nginx\ - config.action\_dispatch.x\_sendfile\_header = “X-Accel-Redirect”\ - </ruby> - -Make sure to configure your server to support these options following -the instructions in the *Rack::Sendfile* documentation. - -NOTE: The *Rack::Sendfile* middleware is always outside of the -*Rack::Lock* mutex, even in single-threaded apps. - -#### Using ActionDispatch::ParamsParser - -*ActionDispatch::ParamsParser* will take parameters from the client in -JSON and make them available in your controller as *params*. - -To use this, your client will need to make a request with JSON-encoded -parameters and specify the *Content-Type* as *application/json*. - -Here’s an example in jQuery: - -<plain>\ -jQuery.ajax({\ - type: ‘POST’,\ - url: ‘/people’\ - dataType: ‘json’,\ - contentType: ‘application/json’,\ - data: JSON.stringify({ person: { firstName: “Yehuda”, lastName: “Katz” -} }), - -success: function(json) { }\ -});\ -</plain> - -*ActionDispatch::ParamsParser* will see the *Content-Type* and your -params will be *{ :person =\> { :firstName =\> “Yehuda”, :lastName =\> -“Katz” } }*. - -#### Other Middlewares - -Rails ships with a number of other middlewares that you might want to -use in an API app, especially if one of your API clients is the browser: - -- *Rack::MethodOverride*: Allows the use of the *\_method* hack to - route POST requests to other verbs. -- *ActionDispatch::Cookies*: Supports the *cookie* method in - *ActionController*, including support for signed and encrypted - cookies. -- *ActionDispatch::Flash*: Supports the *flash* mechanism in - *ActionController*. -- *ActionDispatch::BestStandards*: Tells Internet Explorer to use the - most standards-compliant available renderer. In production mode, if - ChromeFrame is available, use ChromeFrame. -- Session Management: If a *config.session\_store* is supplied, this - middleware makes the session available as the *session* method in - *ActionController*. - -Any of these middlewares can be adding via: - -<ruby>\ -config.middleware.use Rack::MethodOverride\ -</ruby> - -#### Removing Middlewares - -If you don’t want to use a middleware that is included by default in the -API-only middleware set, you can remove it using -*config.middleware.delete*: - -<ruby>\ -config.middleware.delete ::Rack::Sendfile\ -</ruby> - -Keep in mind that removing these features may remove support for certain -features in *ActionController*. - -### Choosing Controller Modules - -An API application (using *ActionController::API*) comes with the -following controller modules by default: - -- *ActionController::UrlFor*: Makes *url\_for* and friends available -- *ActionController::Redirecting*: Support for *redirect\_to* -- *ActionController::Rendering*: Basic support for rendering -- *ActionController::Renderers::All*: Support for *render :json* and - friends -- *ActionController::ConditionalGet*: Support for *stale?* -- *ActionController::ForceSSL*: Support for *force\_ssl* -- *ActionController::RackDelegation*: Support for the *request* and - *response* methods returning *ActionDispatch::Request* and - *ActionDispatch::Response* objects. -- *ActionController::DataStreaming*: Support for *send\_file* and - *send\_data* -- *AbstractController::Callbacks*: Support for *before\_filter* and - friends -- *ActionController::Instrumentation*: Support for the instrumentation - hooks defined by *ActionController* (see [the - source](https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/instrumentation.rb) - for more). -- *ActionController::Rescue*: Support for *rescue\_from*. - -Other plugins may add additional modules. You can get a list of all -modules included into *ActionController::API* in the rails console: - -<shell>\ -\$ irb\ -\>\> ActionController::API.ancestors - -ActionController::Metal.ancestors\ -</shell> - -#### Adding Other Modules - -All ActionController modules know about their dependent modules, so you -can feel free to include any modules into your controllers, and all -dependencies will be included and set up as well. +```ruby +# Apache and lighttpd +config.action_dispatch.x_sendfile_header = "X-Sendfile" + +# Nginx +config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" +``` + +Make sure to configure your server to support these options following the +instructions in the `Rack::Sendfile` documentation. + +NOTE: The `Rack::Sendfile` middleware is always outside of the `Rack::Lock` +mutex, even in single-threaded applications. + +### Using ActionDispatch::ParamsParser + +`ActionDispatch::ParamsParser` will take parameters from the client in the JSON +format and make them available in your controller inside `params`. + +To use this, your client will need to make a request with JSON-encoded parameters +and specify the `Content-Type` as `application/json`. + +Here's an example in jQuery: + +```javascript +jQuery.ajax({ + type: 'POST', + url: '/people', + dataType: 'json', + contentType: 'application/json', + data: JSON.stringify({ person: { firstName: "Yehuda", lastName: "Katz" } }), + success: function(json) { } +}); +``` + +`ActionDispatch::ParamsParser` will see the `Content-Type` and your parameters +will be: + +```ruby +{ :person => { :firstName => "Yehuda", :lastName => "Katz" } } +``` + +### Other Middlewares + +Rails ships with a number of other middlewares that you might want to use in an +API application, especially if one of your API clients is the browser: + +- `Rack::MethodOverride` +- `ActionDispatch::Cookies` +- `ActionDispatch::Flash` +- For sessions management + * `ActionDispatch::Session::CacheStore` + * `ActionDispatch::Session::CookieStore` + * `ActionDispatch::Session::MemCacheStore` + +Any of these middlewares can be added via: + +```ruby +config.middleware.use Rack::MethodOverride +``` + +### Removing Middlewares + +If you don't want to use a middleware that is included by default in the API-only +middleware set, you can remove it with: + +```ruby +config.middleware.delete ::Rack::Sendfile +``` + +Keep in mind that removing these middlewares will remove support for certain +features in Action Controller. + +Choosing Controller Modules +--------------------------- + +An API application (using `ActionController::API`) comes with the following +controller modules by default: + +- `ActionController::UrlFor`: Makes `url_for` and friends available. +- `ActionController::Redirecting`: Support for `redirect_to`. +- `ActionController::Rendering`: Basic support for rendering. +- `ActionController::Renderers::All`: Support for `render :json` and friends. +- `ActionController::ConditionalGet`: Support for `stale?`. +- `ActionController::ForceSSL`: Support for `force_ssl`. +- `ActionController::RackDelegation`: Support for the `request` and `response` + methods returning `ActionDispatch::Request` and `ActionDispatch::Response` + objects. +- `ActionController::DataStreaming`: Support for `send_file` and `send_data`. +- `AbstractController::Callbacks`: Support for `before_filter` and friends. +- `ActionController::Instrumentation`: Support for the instrumentation + hooks defined by Action Controller (see [the instrumentation + guide](active_support_instrumentation.html#action-controller)). +- `ActionController::Rescue`: Support for `rescue_from`. +- `ActionController::BasicImplicitRender`: Makes sure to return an empty response + if there's not an explicit one. +- `ActionController::StrongParameters`: Support for parameters white-listing in + combination with Active Model mass assignment. +- `ActionController::ParamsWrapper`: Wraps the parameters hash into a nested hash + so you don't have to specify root elements sending POST requests for instance. + +Other plugins may add additional modules. You can get a list of all modules +included into `ActionController::API` in the rails console: + +```bash +$ bin/rails c +>> ActionController::API.ancestors - ActionController::Metal.ancestors +``` + +### Adding Other Modules + +All Action Controller modules know about their dependent modules, so you can feel +free to include any modules into your controllers, and all dependencies will be +included and set up as well. Some common modules you might want to add: -- *AbstractController::Translation*: Support for the *l* and *t* - localization and translation methods. These delegate to - *I18n.translate* and *I18n.localize*. -- *ActionController::HTTPAuthentication::Basic* (or *Digest* - or +Token): Support for basic, digest or token HTTP authentication. -- *AbstractController::Layouts*: Support for layouts when rendering. -- *ActionController::MimeResponds*: Support for content negotiation - (*respond\_to*, *respond\_with*). -- *ActionController::Cookies*: Support for *cookies*, which includes - support for signed and encrypted cookies. This requires the cookie - middleware. - -The best place to add a module is in your *ApplicationController*. You -can also add modules to individual controllers. +- `AbstractController::Translation`: Support for the `l` and `t` localization + and translation methods. +- `ActionController::HTTPAuthentication::Basic` (or `Digest` or `Token`): Support + for basic, digest or token HTTP authentication. +- `AbstractController::Layouts`: Support for layouts when rendering. +- `ActionController::MimeResponds`: Support for `respond_to`. +- `ActionController::Cookies`: Support for `cookies`, which includes + support for signed and encrypted cookies. This requires the cookies middleware. + +The best place to add a module is in your `ApplicationController` but you can +also add modules to individual controllers. |