it|s all
[simply.git] / vendor / rails / actionpack / README
blobe4ce4aa044600340f5816c434152f2886501be22
1 = Action Pack -- On rails from request to response
3 Action Pack splits the response to a web request into a controller part
4 (performing the logic) and a view part (rendering a template). This two-step
5 approach is known as an action, which will normally create, read, update, or
6 delete (CRUD for short) some sort of model part (often backed by a database)
7 before choosing either to render a template or redirecting to another action.
9 Action Pack implements these actions as public methods on Action Controllers
10 and uses Action Views to implement the template rendering. Action Controllers
11 are then responsible for handling all the actions relating to a certain part
12 of an application. This grouping usually consists of actions for lists and for
13 CRUDs revolving around a single (or a few) model objects. So ContactsController
14 would be responsible for listing contacts, creating, deleting, and updating
15 contacts. A WeblogController could be responsible for both posts and comments.
17 Action View templates are written using embedded Ruby in tags mingled in with
18 the HTML. To avoid cluttering the templates with code, a bunch of helper
19 classes provide common behavior for forms, dates, and strings. And it's easy
20 to add specific helpers to keep the separation as the application evolves.
22 Note: Some of the features, such as scaffolding and form building, are tied to
23 ActiveRecord[http://activerecord.rubyonrails.org] (an object-relational
24 mapping package), but that doesn't mean that Action Pack depends on Active
25 Record. Action Pack is an independent package that can be used with any sort
26 of backend (Instiki[http://www.instiki.org], which is based on an older version
27 of Action Pack, used Madeleine for example). Read more about the role Action
28 Pack can play when used together with Active Record on
29 http://www.rubyonrails.org.
31 A short rundown of the major features:
33 * Actions grouped in controller as methods instead of separate command objects
34   and can therefore share helper methods
36     CustomersController < ActionController::Base
37       def show
38         @customer = find_customer
39       end
40       
41       def update
42         @customer = find_customer
43         @customer.attributes = params[:customer]
44         @customer.save ? 
45           redirect_to(:action => "show") :
46           render(:action => "edit")
47       end
48       
49       private
50         def find_customer() Customer.find(params[:id]) end
51     end
53   {Learn more}[link:classes/ActionController/Base.html]
56 * Embedded Ruby for templates (no new "easy" template language)
58     <% for post in @posts %>
59       Title: <%= post.title %>
60     <% end %>
62     All post titles: <%= @posts.collect{ |p| p.title }.join ", " %>
64     <% unless @person.is_client? %>
65       Not for clients to see...
66     <% end %>
67   
68   {Learn more}[link:classes/ActionView.html]
71 * Builder-based templates (great for XML content, like RSS)
73     xml.rss("version" => "2.0") do
74       xml.channel do
75         xml.title(@feed_title)
76         xml.link(@url)
77         xml.description "Basecamp: Recent items"
78         xml.language "en-us"
79         xml.ttl "40"
81         for item in @recent_items
82           xml.item do
83             xml.title(item_title(item))
84             xml.description(item_description(item))
85             xml.pubDate(item_pubDate(item))
86             xml.guid(@recent_items.url(item))
87             xml.link(@recent_items.url(item))
88           end
89         end
90       end
91     end
93   {Learn more}[link:classes/ActionView/Base.html]
96 * Filters for pre and post processing of the response (as methods, procs, and classes)
98     class WeblogController < ActionController::Base
99       before_filter :authenticate, :cache, :audit
100       after_filter { |c| c.response.body = Gzip::compress(c.response.body) }
101       after_filter LocalizeFilter
102       
103       def index
104         # Before this action is run, the user will be authenticated, the cache
105         # will be examined to see if a valid copy of the results already
106         # exists, and the action will be logged for auditing.
107         
108         # After this action has run, the output will first be localized then 
109         # compressed to minimize bandwidth usage
110       end
111       
112       private
113         def authenticate
114           # Implement the filter with full access to both request and response
115         end
116     end
117   
118   {Learn more}[link:classes/ActionController/Filters/ClassMethods.html]
119   
121 * Helpers for forms, dates, action links, and text
123     <%= text_field "post", "title", "size" => 30 %>
124     <%= html_date_select(Date.today) %>
125     <%= link_to "New post", :controller => "post", :action => "new" %>
126     <%= truncate(post.title, :length => 25) %>
128   {Learn more}[link:classes/ActionView/Helpers.html]
131 * Layout sharing for template reuse (think simple version of Struts 
132   Tiles[http://jakarta.apache.org/struts/userGuide/dev_tiles.html])
134     class WeblogController < ActionController::Base
135       layout "weblog_layout"
136       
137       def hello_world
138       end
139     end
141     Layout file (called weblog_layout):
142       <html><body><%= yield %></body></html>
143     
144     Template for hello_world action:
145       <h1>Hello world</h1>
146     
147     Result of running hello_world action:
148       <html><body><h1>Hello world</h1></body></html>
150   {Learn more}[link:classes/ActionController/Layout/ClassMethods.html]
153 * Routing makes pretty urls incredibly easy
155     map.connect 'clients/:client_name/:project_name/:controller/:action'
157     Accessing /clients/37signals/basecamp/project/dash calls ProjectController#dash with
158     { "client_name" => "37signals", "project_name" => "basecamp" } in params[:params]
159     
160     From that URL, you can rewrite the redirect in a number of ways:
161     
162     redirect_to(:action => "edit") =>
163       /clients/37signals/basecamp/project/dash
165     redirect_to(:client_name => "nextangle", :project_name => "rails") =>
166       /clients/nextangle/rails/project/dash
168   {Learn more}[link:classes/ActionController/Base.html]
171 * Javascript and Ajax integration
173     link_to_function "Greeting", "alert('Hello world!')"
174     link_to_remote "Delete this post", :update => "posts", 
175                    :url => { :action => "destroy", :id => post.id }
176   
177   {Learn more}[link:classes/ActionView/Helpers/JavaScriptHelper.html]
180 * Easy testing of both controller and rendered template through ActionController::TestCase
182     class LoginControllerTest < ActionController::TestCase
183       def test_failing_authenticate
184         process :authenticate, :user_name => "nop", :password => ""
185         assert flash.has_key?(:alert)
186         assert_redirected_to :action => "index"
187       end
188     end
190   {Learn more}[link:classes/ActionController/TestCase.html]
193 * Automated benchmarking and integrated logging
195     Processing WeblogController#index (for 127.0.0.1 at Fri May 28 00:41:55)
196     Parameters: {"action"=>"index", "controller"=>"weblog"}
197     Rendering weblog/index (200 OK)
198     Completed in 0.029281 (34 reqs/sec)
200     If Active Record is used as the model, you'll have the database debugging
201     as well:
203     Processing PostsController#create (for 127.0.0.1 at Sat Jun 19 14:04:23)
204     Params: {"controller"=>"posts", "action"=>"create",
205              "post"=>{"title"=>"this is good"} }
206     SQL (0.000627) INSERT INTO posts (title) VALUES('this is good')
207     Redirected to http://example.com/posts/5
208     Completed in 0.221764 (4 reqs/sec) | DB: 0.059920 (27%)
210     You specify a logger through a class method, such as:
212     ActionController::Base.logger = Logger.new("Application Log")
213     ActionController::Base.logger = Log4r::Logger.new("Application Log")
216 * Caching at three levels of granularity (page, action, fragment)
218     class WeblogController < ActionController::Base
219       caches_page :show
220       caches_action :account
221       
222       def show
223         # the output of the method will be cached as 
224         # ActionController::Base.page_cache_directory + "/weblog/show/n.html"
225         # and the web server will pick it up without even hitting Rails
226       end
227       
228       def account
229         # the output of the method will be cached in the fragment store
230         # but Rails is hit to retrieve it, so filters are run
231       end
232       
233       def update
234         List.update(params[:list][:id], params[:list])
235         expire_page   :action => "show", :id => params[:list][:id]
236         expire_action :action => "account"
237         redirect_to   :action => "show", :id => params[:list][:id]
238       end
239     end
241   {Learn more}[link:classes/ActionController/Caching.html]
244 * Powerful debugging mechanism for local requests
246     All exceptions raised on actions performed on the request of a local user
247     will be presented with a tailored debugging screen that includes exception
248     message, stack trace, request parameters, session contents, and the
249     half-finished response.
251   {Learn more}[link:classes/ActionController/Rescue.html]
254 * Scaffolding for Active Record model objects
256     class AccountController < ActionController::Base
257       scaffold :account
258     end
259     
260     The AccountController now has the full CRUD range of actions and default
261     templates: list, show, destroy, new, create, edit, update
262     
263   {Learn more}[link:classes/ActionController/Scaffolding/ClassMethods.html]
266 * Form building for Active Record model objects
268     The post object has a title (varchar), content (text), and 
269     written_on (date)
271     <%= form "post" %>
272     
273     ...will generate something like (the selects will have more options, of
274     course):
275     
276     <form action="create" method="POST">
277       <p>
278         <b>Title:</b><br/> 
279         <input type="text" name="post[title]" value="<%= @post.title %>" />
280       </p>
281       <p>
282         <b>Content:</b><br/>
283         <textarea name="post[content]"><%= @post.title %></textarea>
284       </p>
285       <p>
286         <b>Written on:</b><br/>
287         <select name='post[written_on(3i)]'><option>18</option></select>
288         <select name='post[written_on(2i)]'><option value='7'>July</option></select>
289         <select name='post[written_on(1i)]'><option>2004</option></select>
290       </p>
292       <input type="submit" value="Create">
293     </form>
295     This form generates a params[:post] array that can be used directly in a save action:
296     
297     class WeblogController < ActionController::Base
298       def create
299         post = Post.create(params[:post])
300         redirect_to :action => "show", :id => post.id
301       end
302     end
304   {Learn more}[link:classes/ActionView/Helpers/ActiveRecordHelper.html]
307 * Runs on top of WEBrick, Mongrel, CGI, FCGI, and mod_ruby
310 == Simple example (from outside of Rails)
312 This example will implement a simple weblog system using inline templates and
313 an Active Record model. So let's build that WeblogController with just a few
314 methods:
316   require 'action_controller'
317   require 'post'
319   class WeblogController < ActionController::Base
320     layout "weblog/layout"
321   
322     def index
323       @posts = Post.find(:all)
324     end
325     
326     def show
327       @post = Post.find(params[:id])
328     end
329     
330     def new
331       @post = Post.new
332     end
333     
334     def create
335       @post = Post.create(params[:post])
336       redirect_to :action => "show", :id => @post.id
337     end
338   end
340   WeblogController::Base.view_paths = [ File.dirname(__FILE__) ]
341   WeblogController.process_cgi if $0 == __FILE__
343 The last two lines are responsible for telling ActionController where the
344 template files are located and actually running the controller on a new
345 request from the web-server (like to be Apache).
347 And the templates look like this:
349   weblog/layout.html.erb:
350     <html><body>
351     <%= yield %>
352     </body></html>
354   weblog/index.html.erb:
355     <% for post in @posts %>
356       <p><%= link_to(post.title, :action => "show", :id => post.id) %></p>
357     <% end %>
359   weblog/show.html.erb:
360     <p>
361       <b><%= @post.title %></b><br/>
362       <b><%= @post.content %></b>
363     </p>
365   weblog/new.html.erb:
366     <%= form "post" %>
367   
368 This simple setup will list all the posts in the system on the index page,
369 which is called by accessing /weblog/. It uses the form builder for the Active
370 Record model to make the new screen, which in turn hands everything over to
371 the create action (that's the default target for the form builder when given a
372 new model). After creating the post, it'll redirect to the show page using
373 an URL such as /weblog/5 (where 5 is the id of the post).
376 == Download
378 The latest version of Action Pack can be found at
380 * http://rubyforge.org/project/showfiles.php?group_id=249
382 Documentation can be found at 
384 * http://api.rubyonrails.com
387 == Installation
389 You can install Action Pack with the following command.
391   % [sudo] ruby install.rb
393 from its distribution directory.
396 == License
398 Action Pack is released under the MIT license.
401 == Support
403 The Action Pack homepage is http://www.rubyonrails.org. You can find
404 the Action Pack RubyForge page at http://rubyforge.org/projects/actionpack.
405 And as Jim from Rake says:
407    Feel free to submit commits or feature requests.  If you send a patch,
408    remember to update the corresponding unit tests.  If fact, I prefer
409    new feature to be submitted in the form of new unit tests.