Froze rails gems
[depot.git] / vendor / rails / actionpack / README
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 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 => "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 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
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><%= 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>
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 rendered template through ActionController::TestCase
196
197 class LoginControllerTest < ActionController::TestCase
198 def test_failing_authenticate
199 process :authenticate, :user_name => "nop", :password => ""
200 assert flash.has_key?(:alert)
201 assert_redirected_to :action => "index"
202 end
203 end
204
205 {Learn more}[link:classes/ActionController/TestCase.html]
206
207
208 * Automated benchmarking and integrated logging
209
210 Processing WeblogController#index (for 127.0.0.1 at Fri May 28 00:41:55)
211 Parameters: {"action"=>"index", "controller"=>"weblog"}
212 Rendering weblog/index (200 OK)
213 Completed in 0.029281 (34 reqs/sec)
214
215 If Active Record is used as the model, you'll have the database debugging
216 as well:
217
218 Processing WeblogController#create (for 127.0.0.1 at Sat Jun 19 14:04:23)
219 Params: {"controller"=>"weblog", "action"=>"create",
220 "post"=>{"title"=>"this is good"} }
221 SQL (0.000627) INSERT INTO posts (title) VALUES('this is good')
222 Redirected to http://test/weblog/display/5
223 Completed in 0.221764 (4 reqs/sec) | DB: 0.059920 (27%)
224
225 You specify a logger through a class method, such as:
226
227 ActionController::Base.logger = Logger.new("Application Log")
228 ActionController::Base.logger = Log4r::Logger.new("Application Log")
229
230
231 * Caching at three levels of granularity (page, action, fragment)
232
233 class WeblogController < ActionController::Base
234 caches_page :show
235 caches_action :account
236
237 def show
238 # the output of the method will be cached as
239 # ActionController::Base.page_cache_directory + "/weblog/show/n.html"
240 # and the web server will pick it up without even hitting Rails
241 end
242
243 def account
244 # the output of the method will be cached in the fragment store
245 # but Rails is hit to retrieve it, so filters are run
246 end
247
248 def update
249 List.update(params[:list][:id], params[:list])
250 expire_page :action => "show", :id => params[:list][:id]
251 expire_action :action => "account"
252 redirect_to :action => "show", :id => params[:list][:id]
253 end
254 end
255
256 {Learn more}[link:classes/ActionController/Caching.html]
257
258
259 * Component requests from one controller to another
260
261 class WeblogController < ActionController::Base
262 # Performs a method and then lets hello_world output its render
263 def delegate_action
264 do_other_stuff_before_hello_world
265 render_component :controller => "greeter", :action => "hello_world"
266 end
267 end
268
269 class GreeterController < ActionController::Base
270 def hello_world
271 render_text "Hello World!"
272 end
273 end
274
275 The same can be done in a view to do a partial rendering:
276
277 Let's see a greeting:
278 <%= render_component :controller => "greeter", :action => "hello_world" %>
279
280 {Learn more}[link:classes/ActionController/Components.html]
281
282
283 * Powerful debugging mechanism for local requests
284
285 All exceptions raised on actions performed on the request of a local user
286 will be presented with a tailored debugging screen that includes exception
287 message, stack trace, request parameters, session contents, and the
288 half-finished response.
289
290 {Learn more}[link:classes/ActionController/Rescue.html]
291
292
293 * Scaffolding for Active Record model objects
294
295 class AccountController < ActionController::Base
296 scaffold :account
297 end
298
299 The AccountController now has the full CRUD range of actions and default
300 templates: list, show, destroy, new, create, edit, update
301
302 {Learn more}[link:classes/ActionController/Scaffolding/ClassMethods.html]
303
304
305 * Form building for Active Record model objects
306
307 The post object has a title (varchar), content (text), and
308 written_on (date)
309
310 <%= form "post" %>
311
312 ...will generate something like (the selects will have more options, of
313 course):
314
315 <form action="create" method="POST">
316 <p>
317 <b>Title:</b><br/>
318 <input type="text" name="post[title]" value="<%= @post.title %>" />
319 </p>
320 <p>
321 <b>Content:</b><br/>
322 <textarea name="post[content]"><%= @post.title %></textarea>
323 </p>
324 <p>
325 <b>Written on:</b><br/>
326 <select name='post[written_on(3i)]'><option>18</option></select>
327 <select name='post[written_on(2i)]'><option value='7'>July</option></select>
328 <select name='post[written_on(1i)]'><option>2004</option></select>
329 </p>
330
331 <input type="submit" value="Create">
332 </form>
333
334 This form generates a params[:post] array that can be used directly in a save action:
335
336 class WeblogController < ActionController::Base
337 def create
338 post = Post.create(params[:post])
339 redirect_to :action => "display", :id => post.id
340 end
341 end
342
343 {Learn more}[link:classes/ActionView/Helpers/ActiveRecordHelper.html]
344
345
346 * Runs on top of WEBrick, Mongrel, CGI, FCGI, and mod_ruby
347
348
349 == Simple example (from outside of Rails)
350
351 This example will implement a simple weblog system using inline templates and
352 an Active Record model. So let's build that WeblogController with just a few
353 methods:
354
355 require 'action_controller'
356 require 'post'
357
358 class WeblogController < ActionController::Base
359 layout "weblog/layout"
360
361 def index
362 @posts = Post.find(:all)
363 end
364
365 def display
366 @post = Post.find(params[:id])
367 end
368
369 def new
370 @post = Post.new
371 end
372
373 def create
374 @post = Post.create(params[:post])
375 redirect_to :action => "display", :id => @post.id
376 end
377 end
378
379 WeblogController::Base.view_paths = [ File.dirname(__FILE__) ]
380 WeblogController.process_cgi if $0 == __FILE__
381
382 The last two lines are responsible for telling ActionController where the
383 template files are located and actually running the controller on a new
384 request from the web-server (like to be Apache).
385
386 And the templates look like this:
387
388 weblog/layout.erb:
389 <html><body>
390 <%= yield %>
391 </body></html>
392
393 weblog/index.erb:
394 <% for post in @posts %>
395 <p><%= link_to(post.title, :action => "display", :id => post.id %></p>
396 <% end %>
397
398 weblog/display.erb:
399 <p>
400 <b><%= post.title %></b><br/>
401 <b><%= post.content %></b>
402 </p>
403
404 weblog/new.erb:
405 <%= form "post" %>
406
407 This simple setup will list all the posts in the system on the index page,
408 which is called by accessing /weblog/. It uses the form builder for the Active
409 Record model to make the new screen, which in turn hands everything over to
410 the create action (that's the default target for the form builder when given a
411 new model). After creating the post, it'll redirect to the display page using
412 an URL such as /weblog/display/5 (where 5 is the id of the post).
413
414
415 == Examples
416
417 Action Pack ships with three examples that all demonstrate an increasingly
418 detailed view of the possibilities. First is blog_controller that is just a
419 single file for the whole MVC (but still split into separate parts). Second is
420 the debate_controller that uses separate template files and multiple screens.
421 Third is the address_book_controller that uses the layout feature to separate
422 template casing from content.
423
424 Please note that you might need to change the "shebang" line to
425 #!/usr/local/env ruby, if your Ruby is not placed in /usr/local/bin/ruby
426
427 Also note that these examples are all for demonstrating using Action Pack on
428 its own. Not for when it's used inside of Rails.
429
430 == Download
431
432 The latest version of Action Pack can be found at
433
434 * http://rubyforge.org/project/showfiles.php?group_id=249
435
436 Documentation can be found at
437
438 * http://api.rubyonrails.com
439
440
441 == Installation
442
443 You can install Action Pack with the following command.
444
445 % [sudo] ruby install.rb
446
447 from its distribution directory.
448
449
450 == License
451
452 Action Pack is released under the MIT license.
453
454
455 == Support
456
457 The Action Pack homepage is http://www.rubyonrails.org. You can find
458 the Action Pack RubyForge page at http://rubyforge.org/projects/actionpack.
459 And as Jim from Rake says:
460
461 Feel free to submit commits or feature requests. If you send a patch,
462 remember to update the corresponding unit tests. If fact, I prefer
463 new feature to be submitted in the form of new unit tests.