Action Controller Overview
For most conventional RESTful applications, the controller will receive the request (this is invisible to you as the developer), fetch or save data from a model and use a view to create HTML output.
1. Methods and Actions
A controller is a Ruby class which inherits from ApplicationController and has methods just like any other class. controller初始化过程:When your application receives a request, the routing will determine which controller and action to run, then Rails creates an instance of that controller and runs the method with the same name as the action.
Note that the empty method from the example above could work just fine because Rails will by default render the new.html.erb view unless the action says otherwise.
Only public methods are callable as actions. It is a best practice to lower the visibility of methods which are not intended to be actions, like auxiliary methods or filters.
2. Parameters
You will probably want to access data sent in by the user or other parameters in your controller actions. There are two kinds of parameters possible in a web application. The first are parameters that are sent as part of the URL , called query string parameters. The query string is everything after “?” in the URL . The second type of parameter is usually referred to as POST data. This information usually comes from an HTML form which has been filled in by the user. It’s called POST data because it can only be sent as part of an HTTP POST request. Rails does not make any distinction between query string parameters and POST parameters, and both are available in the params hash in your controller.
2.1 Hash and Array Parameters
The params hash is not limited to one-dimensional keys and values. It can contain arrays and (nested) hashes.
There are two types:
(1). GET /clients?ids[]=1&ids[]=2&ids[]=3
(2).
<
form
action
=
"/clients"
method
=
"post"
>
<
input
type
=
"text"
name
=
"client[name]"
value
=
"Acme"
/>
<
input
type
=
"text"
name
=
"client[phone]"
value
=
"12345"
/>
<
input
type
=
"text"
name
=
"client[address][postcode]"
value
=
"12345"
/>
<
input
type
=
"text"
name
=
"client[address][city]"
value
=
"Carrot City"
/>
</
form
>
Note that the params hash is actually an instance of HashWithIndifferentAccess from Active Support, which acts like a hash that lets you use symbols and strings interchangeably as keys.
2.2 Routing Parameters
The params hash will always contain the :controller and :action keys, but you should use the methods controller_name and action_name instead to access these values.
2.3 default_url_options
进一步分析实际作用
3. Session
Your application has a session for each user in which you can store small amounts of data that will be persisted between requests. The session is only available in the controller and the view and can use one of a number of different storage mechanisms:
- CookieStore – Stores everything on the client.
- DRbStore – Stores the data on a DRb server.
- MemCacheStore – Stores the data in a memcache.
- ActiveRecordStore – Stores the data in a database using Active Record.
3.1 Accessing the Session
3.2 The Flash
The flash is a special part of the session which is cleared with each request. This means that values stored there will only be available in the next request, which is useful for storing error messages etc.
3.2.1 using flash normally
flash[
:notice
] =
"You have successfully logged out"
Note it is also possible to assign a flash message as part of the redirection.
redirect_to root_url,
:notice
=>
"You have successfully logged out"
If you want a flash value to be carried over to another request, use the keep method:
flash.keep
3.2.2 flash now
By default, adding values to the flash will make them available to the next request, but sometimes you may want to access those values in the same request . For example, if the create action fails to save a resource and you render the new template directly, that’s not going to result in a new request, but you may still want to display a message using the flash. 注意了,render是不产生new or next request的,所以需要:
flash.now[
:error
] =
"Could not save client"
render
:action
=>
"new"
4. Cookies
Your application can store small amounts of data on the client — called cookies — that will be persisted across requests and even sessions.
class CommentsController < ApplicationController
def new
# Auto-fill the commenter's name if it has been stored in a cookie
@comment = Comment.new(:name => cookies[:commenter_name])
end
def create
@comment = Comment.new(params[:comment])
if @comment.save
flash[:notice] = "Thanks for your comment!"
if params[:remember_name]
# Remember the commenter's name.
cookies[:commenter_name] = @comment.name
else
# Delete cookie for the commenter's name cookie, if any.
cookies.delete(:commenter_name)
end
redirect_to @comment.article
else
render :action => "new"
end
end
end
Note that while for session values you set the key to nil , to delete a cookie value you should use cookies.delete(:key) .
5. Rendering xml and json data
6. Filters
Filters are methods that are run before, after or “around” a controller action. 常见于阻止action 运行,终止action运行等
Filters are inherited, so if you set a filter on ApplicationController , it will be run on every controller in your application.
(1) "Before filters" may halt the request cycle.
before_filter
:require_login
skip_before_filter
:require_login
,
:only
=> [
:new
,
:create
]
(2) After Filters and Around Filters
6.2 Other Ways to Use Filters
7. Verification
Verifications make sure certain criteria are met in order for a controller or action to run. They can specify that a certain key (or several keys in the form of an array) is present in the params , session or flash hashes or that a certain HTTP method was used or that the request was made using XMLHttpRequest (Ajax).
The default action taken when these criteria are not met is to render a 400 Bad Request response, but you can customize this by specifying a redirect URL or rendering something else and you can also add flash messages and HTTP headers to the response.
8. Request Forgery Protection
class LoginsController < ApplicationController
verify :params => [:username, :password],
:render => {:action => "new"},
:add_flash => {
:error => "Username and password required to log in"
}
Now the create action won’t run unless the “username” and “password” parameters are present, and if they’re not, an error message will be added to the flash and the new action will be rendered. But there’s something rather important missing from the verification above: It will be used for every action in LoginsController, which is not what we want. You can limit which actions it will be used for with the :only and :except options just like a filter:
9. Request Forgery Protection
The first step to avoid this is to make sure all “destructive” actions (create, update and destroy) can only be accessed with non-GET requests. If you’re following RESTful conventions you’re already doing this.
The form_authenticity_token generates a valid authentication token. That’s useful in places where Rails does not add it automatically, like in custom Ajax calls.
10. The Request and Response Objects
In every controller there are two accessor methods pointing to the request and the response objects associated with the request cycle that is currently in execution. The request method contains an instance of AbstractRequest and the response method returns a response object representing what is going to be sent back to the client.
10.1
Rails collects all of the parameters sent along with the request in the params hash, whether they are sent as part of the query string or the post body. The request object has three accessors that give you access to these parameters depending on where they came from.
10.2 The response Object
The response object is not usually used directly, but is built up during the execution of the action and rendering of the data that is being sent back to the user, but sometimes – like in an after filter – it can be useful to access the response directly.
11. HTTP Authentications
Rails comes with two built-in HTTP authentication mechanisms:
- Basic Authentication
- Digest Authentication
11.1 Basic Authentication
Using the built-in authentication is quite easy and only requires you to use one method, authenticate_or_request_with_http_basic .
???Digest::
SHA1
.hexdigest(password) ==
PASSWORD
一个设计思路:
With this in place, you can create namespaced controllers that inherit from AdminController . The before filter will thus be run for all actions in those controllers, protecting them with HTTP basic authentication.
11.2 Digest Authentication
具体使用场合和使用方法,需要了解
12. Streaming and File Downloads
Sometimes you may want to send a file to the user instead of rendering an HTML page. All controllers in Rails have the send_data and the send_file methods, which will both stream data to the client.
12.1 Send.data
12.2 Sending Files
12.3 RESTful Downloads
Rails provides an easy and quite sleek way of doing “RESTful downloads”.
设计要点:
It is not recommended that you stream static files through Rails if you can instead keep them in a public folder on your web server. It is much more efficient to let the user download the file directly using Apache or another web server, keeping the request from unnecessarily going through the whole Rails stack. Although if you do need the request to go through Rails for some reason, you can set the :x_sendfile option to true, and Rails will let the web server handle sending the file to the user, freeing up the Rails process to do other things. Note that your web server needs to support the X-Sendfile header for this to work.
13. Parameter Filtering
The filter_parameter_logging method can be used to filter out sensitive information from the log. It works by replacing certain values in the params hash with “[FILTERED ]” as they are written to the log.
14. Rescue
Rails’ default exception handling displays a “500 Server Error” message for all exceptions. If the request was made locally, a nice traceback and some added information gets displayed so you can figure out what went wrong and deal with it. If the request was remote Rails will just display a simple “500 Server Error” message to the user, or a “404 Not Found” if there was a routing error or a record could not be found. Sometimes you might want to customize how these errors are caught and how they’re displayed to the user. There are several levels of exception handling available in a Rails application:
14.1 The Default 500 and 404 Templates
14.2 rescue_from
When an exception occurs which is caught by a rescue_from directive , the exception object is passed to the handler. The handler can be a method or a Proc object passed to the :with option. You can also use a block directly instead of an explicit Proc object.
class ApplicationController < ActionController::Base
rescue_from User::NotAuthorized, :with => :user_not_authorized
private
def user_not_authorized
flash[:error] = "You don't have access to this section."
redirect_to :back
end
end
class ClientsController < ApplicationController
# Check that the user has the right authorization to access clients.
before_filter :check_authorization
# Note how the actions don't have to worry about all the auth stuff.
def edit
@client = Client.find(params[:id])
end
private
# If the user is not authorized, just throw the exception.
def check_authorization
raise User::NotAuthorized unless current_user.admin?
end
end
工作流程:
(1)rescue_from自动直接地捕获exception,When an exception occurs which is caught by a rescue_from directive
上例是User::NotAuthorized; 被父类 的rescue_from捕获;
(2)the exception object is passed to the handle