aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/action_controller.rb3
-rw-r--r--actionpack/lib/action_controller/api.rb145
-rw-r--r--actionpack/lib/action_controller/base.rb6
-rw-r--r--actionpack/lib/action_controller/metal/basic_implicit_render.rb11
-rw-r--r--actionpack/lib/action_controller/metal/implicit_render.rb9
-rw-r--r--actionpack/lib/action_controller/test_case.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb7
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb25
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb22
9 files changed, 203 insertions, 27 deletions
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index a1893ce920..89fc4520d3 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -7,6 +7,7 @@ require 'action_controller/metal/strong_parameters'
module ActionController
extend ActiveSupport::Autoload
+ autoload :API
autoload :Base
autoload :Caching
autoload :Metal
@@ -15,7 +16,6 @@ module ActionController
autoload :FormBuilder
autoload_under "metal" do
- autoload :Compatibility
autoload :ConditionalGet
autoload :Cookies
autoload :DataStreaming
@@ -25,6 +25,7 @@ module ActionController
autoload :Head
autoload :Helpers
autoload :HttpAuthentication
+ autoload :BasicImplicitRender
autoload :ImplicitRender
autoload :Instrumentation
autoload :MimeResponds
diff --git a/actionpack/lib/action_controller/api.rb b/actionpack/lib/action_controller/api.rb
new file mode 100644
index 0000000000..d8149e0232
--- /dev/null
+++ b/actionpack/lib/action_controller/api.rb
@@ -0,0 +1,145 @@
+require 'action_view'
+require 'action_controller'
+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
+ # \Rails controller provides, allowing you to create controllers with just the
+ # features that you need for API only applications.
+ #
+ # An API Controller is different from a normal controller in the sense that
+ # by default it doesn't include a number of features that are usually required
+ # by browser access only: layouts and templates rendering, cookies, sessions,
+ # flash, assets, and so on. This makes the entire controller stack thinner,
+ # suitable for API applications. It doesn't mean you won't have such
+ # features if you need them: they're all available for you to include in
+ # your application, they're just not part of the default API Controller stack.
+ #
+ # By default, only the ApplicationController in a \Rails application inherits
+ # from <tt>ActionController::API</tt>. All other controllers in turn inherit
+ # from ApplicationController.
+ #
+ # A sample controller could look like this:
+ #
+ # class PostsController < ApplicationController
+ # def index
+ # @posts = Post.all
+ # render json: @posts
+ # end
+ # end
+ #
+ # Request, response and parameters objects all work the exact same way as
+ # <tt>ActionController::Base</tt>.
+ #
+ # == Renders
+ #
+ # The default API Controller stack includes all renderers, which means you
+ # can use <tt>render :json</tt> and brothers freely in your controllers. Keep
+ # in mind that templates are not going to be rendered, so you need to ensure
+ # your controller is calling either <tt>render</tt> or <tt>redirect</tt> in
+ # all actions, otherwise it will return 204 No Content response.
+ #
+ # def show
+ # @post = Post.find(params[:id])
+ # render json: @post
+ # end
+ #
+ # == Redirects
+ #
+ # Redirects are used to move from one action to another. You can use the
+ # <tt>redirect</tt> method in your controllers in the same way as
+ # <tt>ActionController::Base</tt>. For example:
+ #
+ # def create
+ # redirect_to root_url and return if not_authorized?
+ # # do stuff here
+ # end
+ #
+ # == Adding new behavior
+ #
+ # 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:
+ #
+ # class ApplicationController < ActionController::API
+ # include ActionController::MimeResponds
+ # end
+ #
+ # class PostsController < ApplicationController
+ # def index
+ # @posts = Post.all
+ #
+ # respond_to do |format|
+ # format.json { render json: @posts }
+ # format.xml { render xml: @posts }
+ # end
+ # end
+ # end
+ #
+ # Quite straightforward. Make sure to check <tt>ActionController::Base</tt>
+ # available modules if you want to include any other functionality that is
+ # not provided by <tt>ActionController::API</tt> out of the box.
+ class API < Metal
+ abstract!
+
+ # Shortcut helper that returns all the ActionController::API modules except the ones passed in the argument:
+ #
+ # class MetalController
+ # ActionController::API.without_modules(:Redirecting, :DataStreaming).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.
+ def self.without_modules(*modules)
+ modules = modules.map do |m|
+ m.is_a?(Symbol) ? ActionController.const_get(m) : m
+ end
+
+ MODULES - modules
+ end
+
+ MODULES = [
+ AbstractController::Rendering,
+
+ UrlFor,
+ Redirecting,
+ Rendering,
+ Renderers::All,
+ ConditionalGet,
+ RackDelegation,
+ BasicImplicitRender,
+ StrongParameters,
+
+ ForceSSL,
+ DataStreaming,
+
+ # Before callbacks should also be executed the earliest as possible, so
+ # also include them at the bottom.
+ AbstractController::Callbacks,
+
+ # Append rescue at the bottom to wrap as much as possible.
+ Rescue,
+
+ # Add instrumentations hooks at the bottom, to ensure they instrument
+ # all the methods properly.
+ Instrumentation,
+
+ # Params wrapper should come before instrumentation so they are
+ # properly showed in logs
+ ParamsWrapper
+ ]
+
+ MODULES.each do |mod|
+ include mod
+ end
+
+ ActiveSupport.run_load_hooks(:action_controller, self)
+ end
+end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index bfae372f53..2c3b3f4e05 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -50,9 +50,9 @@ module ActionController
#
# == Parameters
#
- # All request parameters, whether they come from a GET or POST request, or from the URL, are available through the params method
- # which returns a hash. For example, an action that was performed through <tt>/posts?category=All&limit=5</tt> will include
- # <tt>{ "category" => "All", "limit" => "5" }</tt> in params.
+ # All request parameters, whether they come from a query string in the URL or form data submitted through a POST request are
+ # available through the params method which returns a hash. For example, an action that was performed through
+ # <tt>/posts?category=All&limit=5</tt> will include <tt>{ "category" => "All", "limit" => "5" }</tt> in params.
#
# It's also possible to construct multi-dimensional parameter hashes by specifying keys using brackets, such as:
#
diff --git a/actionpack/lib/action_controller/metal/basic_implicit_render.rb b/actionpack/lib/action_controller/metal/basic_implicit_render.rb
new file mode 100644
index 0000000000..6c6f8381ff
--- /dev/null
+++ b/actionpack/lib/action_controller/metal/basic_implicit_render.rb
@@ -0,0 +1,11 @@
+module ActionController
+ module BasicImplicitRender
+ def send_action(method, *args)
+ super.tap { default_render unless performed? }
+ end
+
+ def default_render(*args)
+ head :no_content
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb
index 1573ea7099..d66b2214ce 100644
--- a/actionpack/lib/action_controller/metal/implicit_render.rb
+++ b/actionpack/lib/action_controller/metal/implicit_render.rb
@@ -1,17 +1,14 @@
module ActionController
module ImplicitRender
- def send_action(method, *args)
- ret = super
- default_render unless performed?
- ret
- end
+
+ include BasicImplicitRender
def default_render(*args)
if template_exists?(action_name.to_s, _prefixes, variants: request.variant)
render(*args)
else
logger.info "No template found for #{self.class.name}\##{action_name}, rendering head :no_content" if logger
- head :no_content
+ super
end
end
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index d34149143f..96f161fb09 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -165,7 +165,7 @@ module ActionController
# class BooksControllerTest < ActionController::TestCase
# def test_create
# # Simulate a POST response with the given HTTP parameters.
- # post(:create, book: { title: "Love Hina" })
+ # post(:create, params: { book: { title: "Love Hina" }})
#
# # Assert that the controller tried to redirect us to
# # the created book's URI.
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index 3aa0eef4ad..b098ea389f 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -13,7 +13,7 @@ module ActionDispatch
# located at `public/assets/application.js` if the file exists. If the file
# does not exist, a 404 "File not Found" response will be returned.
class FileHandler
- def initialize(root, cache_control, index = 'index')
+ def initialize(root, cache_control, index: 'index')
@root = root.chomp('/')
@compiled_root = /^#{Regexp.escape(root)}/
headers = cache_control && { 'Cache-Control' => cache_control }
@@ -21,7 +21,6 @@ module ActionDispatch
@index = index
end
-
# Takes a path to a file. If the file is found, has valid encoding, and has
# correct read permissions, the return value is a URI-escaped string
# representing the filename. Otherwise, false is returned.
@@ -105,9 +104,9 @@ module ActionDispatch
# produce a directory traversal using this middleware. Only 'GET' and 'HEAD'
# requests will result in a file being returned.
class Static
- def initialize(app, path, cache_control = nil, index = 'index')
+ def initialize(app, path, cache_control = nil, index: 'index')
@app = app
- @file_handler = FileHandler.new(path, cache_control, index)
+ @file_handler = FileHandler.new(path, cache_control, index: index)
end
def call(env)
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 15980db39b..7cfe4693c1 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1042,7 +1042,7 @@ module ActionDispatch
class Resource #:nodoc:
attr_reader :controller, :path, :options, :param
- def initialize(entities, options = {})
+ def initialize(entities, api_only = false, options = {})
@name = entities.to_s
@path = (options[:path] || @name).to_s
@controller = (options[:controller] || @name).to_s
@@ -1050,10 +1050,15 @@ module ActionDispatch
@param = (options[:param] || :id).to_sym
@options = options
@shallow = false
+ @api_only = api_only
end
def default_actions
- [:index, :create, :new, :show, :update, :destroy, :edit]
+ if @api_only
+ [:index, :create, :show, :update, :destroy]
+ else
+ [:index, :create, :new, :show, :update, :destroy, :edit]
+ end
end
def actions
@@ -1120,7 +1125,7 @@ module ActionDispatch
end
class SingletonResource < Resource #:nodoc:
- def initialize(entities, options)
+ def initialize(entities, api_only, options)
super
@as = nil
@controller = (options[:controller] || plural).to_s
@@ -1128,7 +1133,11 @@ module ActionDispatch
end
def default_actions
- [:show, :create, :update, :destroy, :new, :edit]
+ if @api_only
+ [:show, :create, :update, :destroy]
+ else
+ [:show, :create, :update, :destroy, :new, :edit]
+ end
end
def plural
@@ -1178,7 +1187,7 @@ module ActionDispatch
return self
end
- resource_scope(:resource, SingletonResource.new(resources.pop, options)) do
+ resource_scope(:resource, SingletonResource.new(resources.pop, api_only?, options)) do
yield if block_given?
concerns(options[:concerns]) if options[:concerns]
@@ -1336,7 +1345,7 @@ module ActionDispatch
return self
end
- resource_scope(:resources, Resource.new(resources.pop, options)) do
+ resource_scope(:resources, Resource.new(resources.pop, api_only?, options)) do
yield if block_given?
concerns(options[:concerns]) if options[:concerns]
@@ -1768,6 +1777,10 @@ module ActionDispatch
delete :destroy if parent_resource.actions.include?(:destroy)
end
end
+
+ def api_only?
+ @set.api_only?
+ end
end
# Routing Concerns allow you to declare common routes that can be reused
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index cf35e85b40..454593b59f 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -319,17 +319,23 @@ module ActionDispatch
end
def self.new_with_config(config)
+ route_set_config = DEFAULT_CONFIG
+
+ # engines apparently don't have this set
if config.respond_to? :relative_url_root
- new Config.new config.relative_url_root
- else
- # engines apparently don't have this set
- new
+ route_set_config.relative_url_root = config.relative_url_root
+ end
+
+ if config.respond_to? :api_only
+ route_set_config.api_only = config.api_only
end
+
+ new route_set_config
end
- Config = Struct.new :relative_url_root
+ Config = Struct.new :relative_url_root, :api_only
- DEFAULT_CONFIG = Config.new(nil)
+ DEFAULT_CONFIG = Config.new(nil, false)
def initialize(config = DEFAULT_CONFIG)
self.named_routes = NamedRouteCollection.new
@@ -352,6 +358,10 @@ module ActionDispatch
@config.relative_url_root
end
+ def api_only?
+ @config.api_only
+ end
+
def request_class
ActionDispatch::Request
end