Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/tags/rel_0-14-4/actionpack/README

Revision 2908, 14.8 kB (checked in by david, 3 years ago)

Fix READMEs (closes #2680) [coffee2code]

  • Property svn:executable set to *
Line 
1 = Action Pack -- On rails from request to response
2
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.
8
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 ContactController
14 would be responsible for listing contacts, creating, deleting, and updating
15 contacts. A WeblogController could be responsible for both posts and comments.
16
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.
21
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.
30
31 A short rundown of the major features:
32
33 * Actions grouped in controller as methods instead of separate command objects
34   and can therefore share helper methods.
35
36     BlogController < ActionController::Base
37       def display
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 => "display") :
46           render(:action => "edit")
47       end
48      
49       private
50         def find_customer() Customer.find(params[:id]) end
51     end
52
53   {Learn more}[link:classes/ActionController/Base.html]
54
55
56 * Embedded Ruby for templates (no new "easy" template language)
57
58     <% for post in @posts %>
59       Title: <%= post.title %>
60     <% end %>
61
62     All post titles: <%= @post.collect{ |p| p.title }.join ", " %>
63
64     <% unless @person.is_client? %>
65       Not for clients to see...
66     <% end %>
67  
68   {Learn more}[link:classes/ActionView.html]
69
70
71 * Builder-based templates (great for XML content, like RSS)
72
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"
80
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
92
93   {Learn more}[link:classes/ActionView/Base.html]
94
95
96 * Filters for pre and post processing of the response (as methods, procs, and classes)
97
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 list
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  
120
121 * Helpers for forms, dates, action links, and text
122
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, 25) %>
127  
128   {Learn more}[link:classes/ActionView/Helpers.html]
129
130
131 * Layout sharing for template reuse (think simple version of Struts
132   Tiles[http://jakarta.apache.org/struts/userGuide/dev_tiles.html])
133
134     class WeblogController < ActionController::Base
135       layout "weblog_layout"
136      
137       def hello_world
138       end
139     end
140
141     Layout file (called weblog_layout):
142       <html><body><%= @content_for_layout %></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>
149
150   {Learn more}[link:classes/ActionController/Layout/ClassMethods.html]
151
152
153 * Routing makes pretty urls incredibly easy
154
155     map.connect 'clients/:client_name/:project_name/:controller/:action'
156
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
164
165     redirect_to(:client_name => "nextangle", :project_name => "rails") =>
166       /clients/nextangle/rails/project/dash
167
168   {Learn more}[link:classes/ActionController/Base.html]
169
170
171 * Javascript and Ajax integration.
172
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]
178
179
180 * Pagination for navigating lists of results.
181
182     # controller
183     def list
184       @pages, @people =
185         paginate :people, :order => 'last_name, first_name'
186     end
187
188     # view
189     <%= link_to "Previous page", { :page => @pages.current.previous } if @pages.current.previous %>
190     <%= link_to "Next page", { :page => @pages.current.next } if @pages.current.next %>
191
192   {Learn more}[link:classes/ActionController/Pagination.html]
193
194
195 * Easy testing of both controller and template result through TestRequest/Response
196
197     class LoginControllerTest < Test::Unit::TestCase
198       def setup
199         @controller = LoginController.new
200         @request    = ActionController::TestRequest.new
201         @response   = ActionController::TestResponse.new
202       end
203
204       def test_failing_authenticate
205         process :authenticate, :user_name => "nop", :password => ""
206         assert flash.has_key?(:alert)
207         assert_redirected_to :action => "index"
208       end
209     end
210
211   {Learn more}[link:classes/ActionController/TestRequest.html]
212
213
214 * Automated benchmarking and integrated logging
215
216     Processing WeblogController#index (for 127.0.0.1 at Fri May 28 00:41:55)
217     Parameters: {"action"=>"index", "controller"=>"weblog"}
218     Rendering weblog/index (200 OK)
219     Completed in 0.029281 (34 reqs/sec)
220
221     If Active Record is used as the model, you'll have the database debugging
222     as well:
223
224     Processing WeblogController#create (for 127.0.0.1 at Sat Jun 19 14:04:23)
225     Params: {"controller"=>"weblog", "action"=>"create", 
226              "post"=>{"title"=>"this is good"} }
227     SQL (0.000627) INSERT INTO posts (title) VALUES('this is good')
228     Redirected to http://test/weblog/display/5
229     Completed in 0.221764 (4 reqs/sec) | DB: 0.059920 (27%)
230
231     You specify a logger through a class method, such as:
232
233     ActionController::Base.logger = Logger.new("Application Log")
234     ActionController::Base.logger = Log4r::Logger.new("Application Log")
235
236
237 * Caching at three levels of granularity (page, action, fragment)
238
239     class WeblogController < ActionController::Base
240       caches_page :show
241       caches_action :account
242      
243       def show
244         # the output of the method will be cached as
245         # ActionController::Base.page_cache_directory + "/weblog/show/n.html"
246         # and the web server will pick it up without even hitting Rails
247       end
248      
249       def account
250         # the output of the method will be cached in the fragment store
251         # but Rails is hit to retrieve it, so filters are run
252       end
253      
254       def update
255         List.update(params[:list][:id], params[:list])
256         expire_page   :action => "show", :id => params[:list][:id]
257         expire_action :action => "account"
258         redirect_to   :action => "show", :id => params[:list][:id]
259       end
260     end
261
262   {Learn more}[link:classes/ActionController/Caching.html]
263
264
265 * Component requests from one controller to another
266
267     class WeblogController < ActionController::Base
268       # Performs a method and then lets hello_world output its render
269       def delegate_action
270         do_other_stuff_before_hello_world
271         render_component :controller => "greeter",  :action => "hello_world"
272       end
273     end
274  
275     class GreeterController < ActionController::Base
276       def hello_world
277         render_text "Hello World!"
278       end
279     end
280  
281     The same can be done in a view to do a partial rendering:
282  
283       Let's see a greeting:
284       <%= render_component :controller => "greeter", :action => "hello_world" %>
285
286   {Learn more}[link:classes/ActionController/Components.html]
287  
288
289 * Powerful debugging mechanism for local requests
290
291     All exceptions raised on actions performed on the request of a local user
292     will be presented with a tailored debugging screen that includes exception
293     message, stack trace, request parameters, session contents, and the
294     half-finished response.
295
296   {Learn more}[link:classes/ActionController/Rescue.html]
297
298
299 * Scaffolding for Action Record model objects
300
301     require 'account' # must be an Active Record class
302     class AccountController < ActionController::Base
303       scaffold :account
304     end
305    
306     The AccountController now has the full CRUD range of actions and default
307     templates: list, show, destroy, new, create, edit, update
308    
309   {Learn more}link:classes/ActionController/Scaffolding/ClassMethods.html
310
311
312 * Form building for Active Record model objects
313
314     The post object has a title (varchar), content (text), and
315     written_on (date)
316
317     <%= form "post" %>
318    
319     ...will generate something like (the selects will have more options, of
320     course):
321    
322     <form action="create" method="POST">
323       <p>
324         <b>Title:</b><br/>
325         <input type="text" name="post[title]" value="<%= @post.title %>" />
326       </p>
327       <p>
328         <b>Content:</b><br/>
329         <textarea name="post[content]"><%= @post.title %></textarea>
330       </p>
331       <p>
332         <b>Written on:</b><br/>
333         <select name='post[written_on(3i)]'><option>18</option></select>
334         <select name='post[written_on(2i)]'><option value='7'>July</option></select>
335         <select name='post[written_on(1i)]'><option>2004</option></select>
336       </p>
337
338       <input type="submit" value="Create">
339     </form>
340
341     This form generates a @params["post"] array that can be used directly in a save action:
342    
343     class WeblogController < ActionController::Base
344       def save
345         post = Post.create(params[:post])
346         redirect_to :action => "display", :id => post.id
347       end
348     end
349
350   {Learn more}[link:classes/ActionView/Helpers/ActiveRecordHelper.html]
351
352
353 * Runs on top of WEBrick, CGI, FCGI, and mod_ruby
354
355
356 == Simple example
357
358 This example will implement a simple weblog system using inline templates and
359 an Active Record model. So let's build that WeblogController with just a few
360 methods:
361
362   require 'action_controller'
363   require 'post'
364
365   class WeblogController < ActionController::Base
366     layout "weblog/layout"
367  
368     def index
369       @posts = Post.find_all
370     end
371    
372     def display
373       @post = Post.find(:params[:id])
374     end
375    
376     def new
377       @post = Post.new
378     end
379    
380     def create
381       @post = Post.create(params[:post])
382       redirect_to :action => "display", :id => @post.id
383     end
384   end
385
386   WeblogController::Base.template_root = File.dirname(__FILE__)
387   WeblogController.process_cgi if $0 == __FILE__
388
389 The last two lines are responsible for telling ActionController where the
390 template files are located and actually running the controller on a new
391 request from the web-server (like to be Apache).
392
393 And the templates look like this:
394
395   weblog/layout.rhtml:
396     <html><body>
397     <%= @content_for_layout %>
398     </body></html>
399
400   weblog/index.rhtml:
401     <% for post in @posts %>
402       <p><%= link_to(post.title, :action => "display", :id => post.id %></p>
403     <% end %>
404
405   weblog/display.rhtml:
406     <p>
407       <b><%= post.title %></b><br/>
408       <b><%= post.content %></b>
409     </p>
410
411   weblog/new.rhtml:
412     <%= form "post" %>
413  
414 This simple setup will list all the posts in the system on the index page,
415 which is called by accessing /weblog/. It uses the form builder for the Active
416 Record model to make the new screen, which in turn hands everything over to
417 the create action (that's the default target for the form builder when given a
418 new model). After creating the post, it'll redirect to the display page using
419 an URL such as /weblog/display/5 (where 5 is the id of the post).
420
421
422 == Examples
423
424 Action Pack ships with three examples that all demonstrate an increasingly
425 detailed view of the possibilities. First is blog_controller that is just a
426 single file for the whole MVC (but still split into separate parts). Second is
427 the debate_controller that uses separate template files and multiple screens.
428 Third is the address_book_controller that uses the layout feature to separate
429 template casing from content.
430
431 Please note that you might need to change the "shebang" line to
432 #!/usr/local/env ruby, if your Ruby is not placed in /usr/local/bin/ruby
433
434
435 == Download
436
437 The latest version of Action Pack can be found at
438
439 * http://rubyforge.org/project/showfiles.php?group_id=249
440
441 Documentation can be found at
442
443 * http://ap.rubyonrails.com
444
445
446 == Installation
447
448 You can install Action Pack with the following command.
449
450   % [sudo] ruby install.rb
451
452 from its distribution directory.
453
454
455 == License
456
457 Action Pack is released under the MIT license.
458
459
460 == Support
461
462 The Action Pack homepage is http://www.rubyonrails.com. You can find
463 the Action Pack RubyForge page at http://rubyforge.org/projects/actionpack.
464 And as Jim from Rake says:
465
466    Feel free to submit commits or feature requests.  If you send a patch,
467    remember to update the corresponding unit tests.  If fact, I prefer
468    new feature to be submitted in the form of new unit tests.
469
470 For other information, feel free to ask on the ruby-talk mailing list (which
471 is mirrored to comp.lang.ruby) or contact mailto:david@loudthinking.com.
Note: See TracBrowser for help on using the browser.