diff options
author | Xavier Noria <fxn@hashref.com> | 2010-08-26 01:39:16 +0200 |
---|---|---|
committer | Xavier Noria <fxn@hashref.com> | 2010-08-26 01:39:16 +0200 |
commit | fa8e17b5c274d80dc161c48b4b8ca67809593620 (patch) | |
tree | 32f2ee690a2f96ec1ee613499929b724cafb6789 /actionpack/lib | |
parent | d2f55e7eee3f82a9a8cc53a2c48294685d75b15e (diff) | |
parent | ee7507b38e14c39dd21aef581cffbe5dc3bd273b (diff) | |
download | rails-fa8e17b5c274d80dc161c48b4b8ca67809593620.tar.gz rails-fa8e17b5c274d80dc161c48b4b8ca67809593620.tar.bz2 rails-fa8e17b5c274d80dc161c48b4b8ca67809593620.zip |
Merge remote branch 'docrails/master'
Diffstat (limited to 'actionpack/lib')
-rw-r--r-- | actionpack/lib/abstract_controller/base.rb | 28 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/callbacks.rb | 45 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/helpers.rb | 12 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/layouts.rb | 22 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/view_paths.rb | 14 | ||||
-rw-r--r-- | actionpack/lib/action_controller/base.rb | 163 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/url_helper.rb | 4 |
7 files changed, 227 insertions, 61 deletions
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index 79ebf29c7f..85270d84d8 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -6,6 +6,10 @@ module AbstractController class Error < StandardError; end class ActionNotFound < StandardError; end + # <tt>AbstractController::Base</tt> is a low-level API. Nobody should be + # using it directly, and subclasses (like ActionController::Base) are + # expected to provide their own +render+ method, since rendering means + # different things depending on the context. class Base attr_internal :response_body attr_internal :action_name @@ -36,13 +40,12 @@ module AbstractController controller.public_instance_methods(true) end - # The list of hidden actions to an empty Array. Defaults to an - # empty Array. This can be modified by other modules or subclasses + # The list of hidden actions to an empty array. Defaults to an + # empty array. This can be modified by other modules or subclasses # to specify particular actions as hidden. # # ==== Returns - # Array[String]:: An array of method names that should not be - # considered actions. + # * <tt>array</tt> - An array of method names that should not be considered actions. def hidden_actions [] end @@ -54,8 +57,7 @@ module AbstractController # itself. Finally, #hidden_actions are removed. # # ==== Returns - # Array[String]:: A list of all methods that should be considered - # actions. + # * <tt>array</tt> - A list of all methods that should be considered actions. def action_methods @action_methods ||= begin # All public instance methods of this class, including ancestors @@ -84,7 +86,7 @@ module AbstractController # controller_name. # # ==== Returns - # String + # * <tt>string</tt> def controller_path @controller_path ||= name.sub(/Controller$/, '').underscore unless anonymous? end @@ -104,7 +106,7 @@ module AbstractController # ActionNotFound error is raised. # # ==== Returns - # self + # * <tt>self</tt> def process(action, *args) @_action_name = action_name = action.to_s @@ -133,10 +135,10 @@ module AbstractController # can be considered an action. # # ==== Parameters - # name<String>:: The name of an action to be tested + # * <tt>name</tt> - The name of an action to be tested # # ==== Returns - # TrueClass, FalseClass + # * <tt>TrueClass</tt>, <tt>FalseClass</tt> def action_method?(name) self.class.action_methods.include?(name) end @@ -180,11 +182,11 @@ module AbstractController # returns nil, an ActionNotFound exception will be raised. # # ==== Parameters - # action_name<String>:: An action name to find a method name for + # * <tt>action_name</tt> - An action name to find a method name for # # ==== Returns - # String:: The name of the method that handles the action - # nil:: No method name could be found. Raise ActionNotFound. + # * <tt>string</tt> - The name of the method that handles the action + # * <tt>nil</tt> - No method name could be found. Raise ActionNotFound. def method_for_action(action_name) if action_method?(action_name) then action_name elsif respond_to?(:action_missing, true) then "_handle_action_missing" diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index 67efeb7063..7b0d80614d 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -28,9 +28,8 @@ module AbstractController # a Rails process. # # ==== Options - # :only<#to_s>:: The callback should be run only for this action - # :except<#to_s>:: The callback should be run for all actions - # except this action + # * <tt>only</tt> - The callback should be run only for this action + # * <tt>except<tt> - The callback should be run for all actions except this action def _normalize_callback_options(options) if only = options[:only] only = Array(only).map {|o| "action_name == '#{o}'"}.join(" || ") @@ -45,7 +44,7 @@ module AbstractController # Skip before, after, and around filters matching any of the names # # ==== Parameters - # *names<Object>:: A list of valid names that could be used for + # * <tt>names</tt> - A list of valid names that could be used for # callbacks. Note that skipping uses Ruby equality, so it's # impossible to skip a callback defined using an anonymous proc # using #skip_filter @@ -60,13 +59,13 @@ module AbstractController # the normalization across several methods that use it. # # ==== Parameters - # callbacks<Array[*Object, Hash]>:: A list of callbacks, with an optional + # * <tt>callbacks</tt> - An array of callbacks, with an optional # options hash as the last parameter. - # block<Proc>:: A proc that should be added to the callbacks. + # * <tt>block</tt> - A proc that should be added to the callbacks. # # ==== Block Parameters - # name<Symbol>:: The callback to be added - # options<Hash>:: A list of options to be used when adding the callback + # * <tt>name</tt> - The callback to be added + # * <tt>options</tt> - A hash of options to be used when adding the callback def _insert_callbacks(callbacks, block) options = callbacks.last.is_a?(Hash) ? callbacks.pop : {} _normalize_callback_options(options) @@ -82,27 +81,27 @@ module AbstractController class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 # Append a before, after or around filter. See _insert_callbacks # for details on the allowed parameters. - def #{filter}_filter(*names, &blk) - _insert_callbacks(names, blk) do |name, options| - set_callback(:process_action, :#{filter}, name, options) - end - end + def #{filter}_filter(*names, &blk) # def before_filter(*names, &blk) + _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options} + set_callback(:process_action, :#{filter}, name, options) # set_callback(:process_action, :before_filter, name, options) + end # end + end # end # Prepend a before, after or around filter. See _insert_callbacks # for details on the allowed parameters. - def prepend_#{filter}_filter(*names, &blk) - _insert_callbacks(names, blk) do |name, options| - set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) - end - end + def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk) + _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options| + set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true)) + end # end + end # end # Skip a before, after or around filter. See _insert_callbacks # for details on the allowed parameters. - def skip_#{filter}_filter(*names, &blk) - _insert_callbacks(names, blk) do |name, options| - skip_callback(:process_action, :#{filter}, name, options) - end - end + def skip_#{filter}_filter(*names, &blk) # def skip_before_filter(*names, &blk) + _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options| + skip_callback(:process_action, :#{filter}, name, options) # skip_callback(:process_action, :before, name, options) + end # end + end # end # *_filter is the same as append_*_filter alias_method :append_#{filter}_filter, :#{filter}_filter diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb index 4374b439d0..0c96a6ed15 100644 --- a/actionpack/lib/abstract_controller/helpers.rb +++ b/actionpack/lib/abstract_controller/helpers.rb @@ -40,7 +40,7 @@ module AbstractController # <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%> # # ==== Parameters - # meths<Array[#to_s]>:: The name of a method on the controller + # * <tt>method[, method]</tt> - A name or names of a method on the controller # to be made available on the view. def helper_method(*meths) meths.flatten.each do |meth| @@ -55,8 +55,8 @@ module AbstractController # The +helper+ class method can take a series of helper module names, a block, or both. # # ==== Parameters - # *args<Array[Module, Symbol, String, :all]> - # block<Block>:: A block defining helper methods + # * <tt>*args</tt> - Module, Symbol, String, :all + # * <tt>block</tt> - A block defining helper methods # # ==== Examples # When the argument is a module it will be included directly in the template class. @@ -100,7 +100,7 @@ module AbstractController # rendered through this controller. # # ==== Parameters - # mod<Module>:: The module to include into the current helper module + # * <tt>module</tt> - The module to include into the current helper module # for the class def add_template_helper(mod) _helpers.module_eval { include mod } @@ -118,10 +118,10 @@ module AbstractController # are returned. # # ==== Parameters - # args<Array[String, Symbol, Module]>:: A list of helpers + # * <tt>args</tt> - An array of helpers # # ==== Returns - # Array[Module]:: A normalized list of modules for the list of + # * <tt>Array</tt> - A normalized list of modules for the list of # helpers provided. def modules_for_helpers(args) args.flatten.map! do |arg| diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index 5cd7a90ab5..958e7f7ec8 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -114,11 +114,13 @@ module AbstractController # # class WeblogController < ActionController::Base # layout proc{ |controller| controller.logged_in? ? "writer_layout" : "reader_layout" } + # end # # Of course, the most common way of specifying a layout is still just as a plain template name: # # class WeblogController < ActionController::Base # layout "weblog_standard" + # end # # If no directory is specified for the template name, the template will by default be looked for in <tt>app/views/layouts/</tt>. # Otherwise, it will be looked up relative to the template root. @@ -183,7 +185,7 @@ module AbstractController # layout. # # ==== Returns - # Boolean:: True if the action has a layout, false otherwise. + # * <tt> Boolean</tt> - True if the action has a layout, false otherwise. def action_has_layout? return unless super @@ -209,11 +211,11 @@ module AbstractController # true:: raise an ArgumentError # # ==== Parameters - # layout<String, Symbol, false)>:: The layout to use. + # * <tt>String, Symbol, false</tt> - The layout to use. # # ==== Options (conditions) - # :only<#to_s, Array[#to_s]>:: A list of actions to apply this layout to. - # :except<#to_s, Array[#to_s]>:: Apply this layout to all actions but this one + # * :only - A list of actions to apply this layout to. + # * :except - Apply this layout to all actions but this one. def layout(layout, conditions = {}) include LayoutConditions unless conditions.empty? @@ -228,7 +230,7 @@ module AbstractController # value of this method. # # ==== Returns - # String:: A template name + # * <tt>String</tt> - A template name def _implied_layout_name controller_path end @@ -313,8 +315,8 @@ module AbstractController # the name type. # # ==== Parameters - # name<String|TrueClass|FalseClass|Symbol>:: The name of the template - # details<Hash{Symbol => Object}>:: A list of details to restrict + # * <tt>name</tt> - The name of the template + # * <tt>details</tt> - A list of details to restrict # the lookup to. By default, layout lookup is limited to the # formats specified for the current request. def _layout_for_option(name) @@ -333,14 +335,14 @@ module AbstractController # Optionally raises an exception if the layout could not be found. # # ==== Parameters - # details<Hash>:: A list of details to restrict the search by. This + # * <tt>details</tt> - A list of details to restrict the search by. This # might include details like the format or locale of the template. - # require_layout<Boolean>:: If this is true, raise an ArgumentError + # * <tt>require_logout</tt> - If this is true, raise an ArgumentError # with details about the fact that the exception could not be # found (defaults to false) # # ==== Returns - # Template:: The template object for the default layout (or nil) + # * <tt>template</tt> - The template object for the default layout (or nil) def _default_layout(require_layout = false) begin layout_name = _layout if action_has_layout? diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb index b552a649d1..6544c8949a 100644 --- a/actionpack/lib/abstract_controller/view_paths.rb +++ b/actionpack/lib/abstract_controller/view_paths.rb @@ -34,9 +34,9 @@ module AbstractController # Append a path to the list of view paths for this controller. # # ==== Parameters - # path<String, ViewPath>:: If a String is provided, it gets converted into - # the default view path. You may also provide a custom view path - # (see ActionView::ViewPathSet for more information) + # * <tt>path</tt> - If a String is provided, it gets converted into + # the default view path. You may also provide a custom view path + # (see ActionView::ViewPathSet for more information) def append_view_path(path) self.view_paths = view_paths.dup + Array(path) end @@ -44,9 +44,9 @@ module AbstractController # Prepend a path to the list of view paths for this controller. # # ==== Parameters - # path<String, ViewPath>:: If a String is provided, it gets converted into - # the default view path. You may also provide a custom view path - # (see ActionView::ViewPathSet for more information) + # * <tt>path</tt> - If a String is provided, it gets converted into + # the default view path. You may also provide a custom view path + # (see ActionView::ViewPathSet for more information) def prepend_view_path(path) self.view_paths = Array(path) + view_paths.dup end @@ -59,7 +59,7 @@ module AbstractController # Set the view paths. # # ==== Parameters - # paths<ViewPathSet, Object>:: If a ViewPathSet is provided, use that; + # * <tt>paths</tt> - If a ViewPathSet is provided, use that; # otherwise, process the parameter into a ViewPathSet. def view_paths=(paths) self._view_paths = ActionView::Base.process_view_paths(paths) diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 9dfffced75..165bf089c0 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -1,6 +1,169 @@ require "action_controller/log_subscriber" module ActionController + # Action Controllers are the core of a web request in \Rails. They are made up of one or more actions that are executed + # on request and then either render a template or redirect to another action. An action is defined as a public method + # on the controller, which will automatically be made accessible to the web-server through \Rails Routes. + # + # By default, only the ApplicationController in a \Rails application inherits from <tt>ActionController::Base</tt>. All other + # controllers in turn inherit from ApplicationController. This gives you one class to configure things such as + # request forgery protection and filtering of sensitive request parameters. + # + # A sample controller could look like this: + # + # class PostsController < ApplicationController + # def index + # @posts = Post.all + # end + # + # def create + # @post = Post.create params[:post] + # redirect_to posts_path + # end + # end + # + # Actions, by default, render a template in the <tt>app/views</tt> directory corresponding to the name of the controller and action + # after executing code in the action. For example, the +index+ action of the PostsController would render the + # template <tt>app/views/posts/index.erb</tt> by default after populating the <tt>@posts</tt> instance variable. + # + # Unlike index, the create action will not render a template. After performing its main purpose (creating a + # new post), it initiates a redirect instead. This redirect works by returning an external + # "302 Moved" HTTP response that takes the user to the index action. + # + # These two methods represent the two basic action archetypes used in Action Controllers. Get-and-show and do-and-redirect. + # Most actions are variations of these themes. + # + # == Requests + # + # For every request, the router determines the value of the +controller+ and +action+ keys. These determine which controller + # and action are called. The remaining request parameters, the session (if one is available), and the full request with + # all the HTTP headers are made available to the action through accessor methods. Then the action is performed. + # + # The full request object is available via the request accessor and is primarily used to query for HTTP headers: + # + # def server_ip + # location = request.env["SERVER_ADDR"] + # render :text => "This server hosted at #{location}" + # end + # + # == 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. + # + # It's also possible to construct multi-dimensional parameter hashes by specifying keys using brackets, such as: + # + # <input type="text" name="post[name]" value="david"> + # <input type="text" name="post[address]" value="hyacintvej"> + # + # A request stemming from a form holding these inputs will include <tt>{ "post" => { "name" => "david", "address" => "hyacintvej" } }</tt>. + # If the address input had been named "post[address][street]", the params would have included + # <tt>{ "post" => { "address" => { "street" => "hyacintvej" } } }</tt>. There's no limit to the depth of the nesting. + # + # == Sessions + # + # Sessions allows you to store objects in between requests. This is useful for objects that are not yet ready to be persisted, + # such as a Signup object constructed in a multi-paged process, or objects that don't change much and are needed all the time, such + # as a User object for a system that requires login. The session should not be used, however, as a cache for objects where it's likely + # they could be changed unknowingly. It's usually too much work to keep it all synchronized -- something databases already excel at. + # + # You can place objects in the session by using the <tt>session</tt> method, which accesses a hash: + # + # session[:person] = Person.authenticate(user_name, password) + # + # And retrieved again through the same hash: + # + # Hello #{session[:person]} + # + # For removing objects from the session, you can either assign a single key to +nil+: + # + # # removes :person from session + # session[:person] = nil + # + # or you can remove the entire session with +reset_session+. + # + # Sessions are stored by default in a browser cookie that's cryptographically signed, but unencrypted. + # This prevents the user from tampering with the session but also allows him to see its contents. + # + # Do not put secret information in cookie-based sessions! + # + # Other options for session storage: + # + # * ActiveRecord::SessionStore - Sessions are stored in your database, which works better than PStore with multiple app servers and, + # unlike CookieStore, hides your session contents from the user. To use ActiveRecord::SessionStore, set + # + # config.action_controller.session_store = :active_record_store + # + # in your <tt>config/environment.rb</tt> and run <tt>rake db:sessions:create</tt>. + # + # == Responses + # + # Each action results in a response, which holds the headers and document to be sent to the user's browser. The actual response + # object is generated automatically through the use of renders and redirects and requires no user intervention. + # + # == Renders + # + # Action Controller sends content to the user by using one of five rendering methods. The most versatile and common is the rendering + # of a template. Included in the Action Pack is the Action View, which enables rendering of ERb templates. It's automatically configured. + # The controller passes objects to the view by assigning instance variables: + # + # def show + # @post = Post.find(params[:id]) + # end + # + # Which are then automatically available to the view: + # + # Title: <%= @post.title %> + # + # You don't have to rely on the automated rendering. Especially actions that could result in the rendering of different templates will use + # the manual rendering methods: + # + # def search + # @results = Search.find(params[:query]) + # case @results + # when 0 then render :action => "no_results" + # when 1 then render :action => "show" + # when 2..10 then render :action => "show_many" + # end + # end + # + # Read more about writing ERb and Builder templates in ActionView::Base. + # + # == Redirects + # + # Redirects are used to move from one action to another. For example, after a <tt>create</tt> action, which stores a blog entry to a database, + # we might like to show the user the new entry. Because we're following good DRY principles (Don't Repeat Yourself), we're going to reuse (and redirect to) + # a <tt>show</tt> action that we'll assume has already been created. The code might look like this: + # + # def create + # @entry = Entry.new(params[:entry]) + # if @entry.save + # # The entry was saved correctly, redirect to show + # redirect_to :action => 'show', :id => @entry.id + # else + # # things didn't go so well, do something else + # end + # end + # + # In this case, after saving our new entry to the database, the user is redirected to the <tt>show</tt> method which is then executed. + # + # == Calling multiple redirects or renders + # + # An action may contain only a single render or a single redirect. Attempting to try to do either again will result in a DoubleRenderError: + # + # def do_something + # redirect_to :action => "elsewhere" + # render :action => "overthere" # raises DoubleRenderError + # end + # + # If you need to redirect on the condition of something, then be sure to add "and return" to halt execution. + # + # def do_something + # redirect_to(:action => "elsewhere") and return if monkeys.nil? + # render :action => "overthere" # won't be called if monkeys is nil + # end + # class Base < Metal abstract! diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index a5c6718c58..b0401c9859 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -367,8 +367,8 @@ module ActionView # "Go Back" link instead of a link to the comments page, we could do something like this... # # <%= - # link_to_unless_current("Comment", { :controller => 'comments', :action => 'new}) do - # link_to("Go back", { :controller => 'posts', :action => 'index' }) + # link_to_unless_current("Comment", { :controller => "comments", :action => "new" }) do + # link_to("Go back", { :controller => "posts", :action => "index" }) # end # %> def link_to_unless_current(name, options = {}, html_options = {}, &block) |