e4ce4aa044600340f5816c434152f2886501be22
[feedcatcher.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 ContactsController
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 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
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: <%= @posts.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, :length => 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 * Easy testing of both controller and rendered template through ActionController::TestCase
181
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
189
190 {Learn more}[link:classes/ActionController/TestCase.html]
191
192
193 * Automated benchmarking and integrated logging
194
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)
199
200 If Active Record is used as the model, you'll have the database debugging
201 as well:
202
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%)
209
210 You specify a logger through a class method, such as:
211
212 ActionController::Base.logger = Logger.new("Application Log")
213 ActionController::Base.logger = Log4r::Logger.new("Application Log")
214
215
216 * Caching at three levels of granularity (page, action, fragment)
217
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
240
241 {Learn more}[link:classes/ActionController/Caching.html]
242
243
244 * Powerful debugging mechanism for local requests
245
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.
250
251 {Learn more}[link:classes/ActionController/Rescue.html]
252
253
254 * Scaffolding for Active Record model objects
255
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]
264
265
266 * Form building for Active Record model objects
267
268 The post object has a title (varchar), content (text), and
269 written_on (date)
270
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>
291
292 <input type="submit" value="Create">
293 </form>
294
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
303
304 {Learn more}[link:classes/ActionView/Helpers/ActiveRecordHelper.html]
305
306
307 * Runs on top of WEBrick, Mongrel, CGI, FCGI, and mod_ruby
308
309
310 == Simple example (from outside of Rails)
311
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:
315
316 require 'action_controller'
317 require 'post'
318
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
339
340 WeblogController::Base.view_paths = [ File.dirname(__FILE__) ]
341 WeblogController.process_cgi if $0 == __FILE__
342
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).
346
347 And the templates look like this:
348
349 weblog/layout.html.erb:
350 <html><body>
351 <%= yield %>
352 </body></html>
353
354 weblog/index.html.erb:
355 <% for post in @posts %>
356 <p><%= link_to(post.title, :action => "show", :id => post.id) %></p>
357 <% end %>
358
359 weblog/show.html.erb:
360 <p>
361 <b><%= @post.title %></b><br/>
362 <b><%= @post.content %></b>
363 </p>
364
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).
374
375
376 == Download
377
378 The latest version of Action Pack can be found at
379
380 * http://rubyforge.org/project/showfiles.php?group_id=249
381
382 Documentation can be found at
383
384 * http://api.rubyonrails.com
385
386
387 == Installation
388
389 You can install Action Pack with the following command.
390
391 % [sudo] ruby install.rb
392
393 from its distribution directory.
394
395
396 == License
397
398 Action Pack is released under the MIT license.
399
400
401 == Support
402
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:
406
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.