aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/README.rdoc
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/README.rdoc')
-rw-r--r--actionpack/README.rdoc382
1 files changed, 382 insertions, 0 deletions
diff --git a/actionpack/README.rdoc b/actionpack/README.rdoc
new file mode 100644
index 0000000000..272feb63d0
--- /dev/null
+++ b/actionpack/README.rdoc
@@ -0,0 +1,382 @@
+= Action Pack -- On rails from request to response
+
+Action Pack splits the response to a web request into a controller part
+(performing the logic) and a view part (rendering a template). This two-step
+approach is known as an action, which will normally create, read, update, or
+delete (CRUD for short) some sort of model part (often backed by a database)
+before choosing either to render a template or redirecting to another action.
+
+Action Pack implements these actions as public methods on Action Controllers
+and uses Action Views to implement the template rendering. Action Controllers
+are then responsible for handling all the actions relating to a certain part
+of an application. This grouping usually consists of actions for lists and for
+CRUDs revolving around a single (or a few) model objects. So ContactsController
+would be responsible for listing contacts, creating, deleting, and updating
+contacts. A WeblogController could be responsible for both posts and comments.
+
+Action View templates are written using embedded Ruby in tags mingled in with
+the HTML. To avoid cluttering the templates with code, a bunch of helper
+classes provide common behavior for forms, dates, and strings. And it's easy
+to add specific helpers to keep the separation as the application evolves.
+
+A short rundown of the major features:
+
+* Actions grouped in controller as methods instead of separate command objects
+ and can therefore share helper methods
+
+ CustomersController < ActionController::Base
+ def show
+ @customer = find_customer
+ end
+
+ def update
+ @customer = find_customer
+ @customer.attributes = params[:customer]
+ @customer.save ?
+ redirect_to(:action => "show") :
+ render(:action => "edit")
+ end
+
+ private
+ def find_customer() Customer.find(params[:id]) end
+ end
+
+ {Learn more}[link:classes/ActionController/Base.html]
+
+
+* Embedded Ruby for templates (no new "easy" template language)
+
+ <% for post in @posts %>
+ Title: <%= post.title %>
+ <% end %>
+
+ All post titles: <%= @posts.collect{ |p| p.title }.join ", " %>
+
+ <% unless @person.is_client? %>
+ Not for clients to see...
+ <% end %>
+
+ {Learn more}[link:classes/ActionView.html]
+
+
+* Builder-based templates (great for XML content, like RSS)
+
+ xml.rss("version" => "2.0") do
+ xml.channel do
+ xml.title(@feed_title)
+ xml.link(@url)
+ xml.description "Basecamp: Recent items"
+ xml.language "en-us"
+ xml.ttl "40"
+
+ for item in @recent_items
+ xml.item do
+ xml.title(item_title(item))
+ xml.description(item_description(item))
+ xml.pubDate(item_pubDate(item))
+ xml.guid(@recent_items.url(item))
+ xml.link(@recent_items.url(item))
+ end
+ end
+ end
+ end
+
+ {Learn more}[link:classes/ActionView/Base.html]
+
+
+* Filters for pre and post processing of the response (as methods, procs, and classes)
+
+ class WeblogController < ActionController::Base
+ before_filter :authenticate, :cache, :audit
+ after_filter { |c| c.response.body = Gzip::compress(c.response.body) }
+ after_filter LocalizeFilter
+
+ def index
+ # Before this action is run, the user will be authenticated, the cache
+ # will be examined to see if a valid copy of the results already
+ # exists, and the action will be logged for auditing.
+
+ # After this action has run, the output will first be localized then
+ # compressed to minimize bandwidth usage
+ end
+
+ private
+ def authenticate
+ # Implement the filter with full access to both request and response
+ end
+ end
+
+ {Learn more}[link:classes/ActionController/Filters/ClassMethods.html]
+
+
+* Helpers for forms, dates, action links, and text
+
+ <%= text_field "post", "title", "size" => 30 %>
+ <%= html_date_select(Date.today) %>
+ <%= link_to "New post", :controller => "post", :action => "new" %>
+ <%= truncate(post.title, :length => 25) %>
+
+ {Learn more}[link:classes/ActionView/Helpers.html]
+
+
+* Layout sharing for template reuse (think simple version of Struts
+ Tiles[http://jakarta.apache.org/struts/userGuide/dev_tiles.html])
+
+ class WeblogController < ActionController::Base
+ layout "weblog_layout"
+
+ def hello_world
+ end
+ end
+
+ Layout file (called weblog_layout):
+ <html><body><%= yield %></body></html>
+
+ Template for hello_world action:
+ <h1>Hello world</h1>
+
+ Result of running hello_world action:
+ <html><body><h1>Hello world</h1></body></html>
+
+ {Learn more}[link:classes/ActionController/Layout/ClassMethods.html]
+
+
+* Routing makes pretty urls incredibly easy
+
+ map.connect 'clients/:client_name/:project_name/:controller/:action'
+
+ Accessing /clients/37signals/basecamp/project/dash calls ProjectController#dash with
+ { "client_name" => "37signals", "project_name" => "basecamp" } in params[:params]
+
+ From that URL, you can rewrite the redirect in a number of ways:
+
+ redirect_to(:action => "edit") =>
+ /clients/37signals/basecamp/project/dash
+
+ redirect_to(:client_name => "nextangle", :project_name => "rails") =>
+ /clients/nextangle/rails/project/dash
+
+ {Learn more}[link:classes/ActionController/Base.html]
+
+
+* Easy testing of both controller and rendered template through ActionController::TestCase
+
+ class LoginControllerTest < ActionController::TestCase
+ def test_failing_authenticate
+ process :authenticate, :user_name => "nop", :password => ""
+ assert flash.has_key?(:alert)
+ assert_redirected_to :action => "index"
+ end
+ end
+
+ {Learn more}[link:classes/ActionController/TestCase.html]
+
+
+* Automated benchmarking and integrated logging
+
+ Started GET "/weblog" for 127.0.0.1 at Fri May 28 00:41:55
+ Processing by WeblogController#index as HTML
+ Rendered weblog/index.html.erb within layouts/application (25.7ms)
+ Completed 200 OK in 29.3ms
+
+ If Active Record is used as the model, you'll have the database debugging
+ as well:
+
+ Started POST "/posts" for 127.0.0.1 at Sat Jun 19 14:04:23
+ Processing by PostsController#create as HTML
+ Parameters: {"post"=>{"title"=>"this is good"}}
+ SQL (0.6ms) INSERT INTO posts (title) VALUES('this is good')
+ Redirected to http://example.com/posts/5
+ Completed 302 Found in 221ms (Views: 215ms | ActiveRecord: 0.6ms)
+
+ You specify a logger through a class method, such as:
+
+ ActionController::Base.logger = Logger.new("Application Log")
+ ActionController::Base.logger = Log4r::Logger.new("Application Log")
+
+
+* Caching at three levels of granularity (page, action, fragment)
+
+ class WeblogController < ActionController::Base
+ caches_page :show
+ caches_action :account
+
+ def show
+ # the output of the method will be cached as
+ # ActionController::Base.page_cache_directory + "/weblog/show/n.html"
+ # and the web server will pick it up without even hitting Rails
+ end
+
+ def account
+ # the output of the method will be cached in the fragment store
+ # but Rails is hit to retrieve it, so filters are run
+ end
+
+ def update
+ List.update(params[:list][:id], params[:list])
+ expire_page :action => "show", :id => params[:list][:id]
+ expire_action :action => "account"
+ redirect_to :action => "show", :id => params[:list][:id]
+ end
+ end
+
+ {Learn more}[link:classes/ActionController/Caching.html]
+
+
+* Powerful debugging mechanism for local requests
+
+ All exceptions raised on actions performed on the request of a local user
+ will be presented with a tailored debugging screen that includes exception
+ message, stack trace, request parameters, session contents, and the
+ half-finished response.
+
+ {Learn more}[link:classes/ActionController/Rescue.html]
+
+
+* Scaffolding for Active Record model objects
+
+ class AccountController < ActionController::Base
+ scaffold :account
+ end
+
+ The AccountController now has the full CRUD range of actions and default
+ templates: list, show, destroy, new, create, edit, update
+
+ {Learn more}[link:classes/ActionController/Scaffolding/ClassMethods.html]
+
+
+* Form building for Active Record model objects
+
+ The post object has a title (varchar), content (text), and
+ written_on (date)
+
+ <%= form "post" %>
+
+ ...will generate something like (the selects will have more options, of
+ course):
+
+ <form action="create" method="POST">
+ <p>
+ <b>Title:</b><br/>
+ <input type="text" name="post[title]" value="<%= @post.title %>" />
+ </p>
+ <p>
+ <b>Content:</b><br/>
+ <textarea name="post[content]"><%= @post.title %></textarea>
+ </p>
+ <p>
+ <b>Written on:</b><br/>
+ <select name='post[written_on(3i)]'><option>18</option></select>
+ <select name='post[written_on(2i)]'><option value='7'>July</option></select>
+ <select name='post[written_on(1i)]'><option>2004</option></select>
+ </p>
+
+ <input type="submit" value="Create">
+ </form>
+
+ This form generates a params[:post] array that can be used directly in a save action:
+
+ class WeblogController < ActionController::Base
+ def create
+ post = Post.create(params[:post])
+ redirect_to :action => "show", :id => post.id
+ end
+ end
+
+ {Learn more}[link:classes/ActionView/Helpers/ActiveRecordHelper.html]
+
+
+* Runs on top of WEBrick, Mongrel, CGI, FCGI, and mod_ruby
+
+
+== Simple example (from outside of Rails)
+
+This example will implement a simple weblog system using inline templates and
+an Active Record model. So let's build that WeblogController with just a few
+methods:
+
+ require 'action_controller'
+ require 'post'
+
+ class WeblogController < ActionController::Base
+ layout "weblog/layout"
+
+ def index
+ @posts = Post.find(:all)
+ end
+
+ def show
+ @post = Post.find(params[:id])
+ end
+
+ def new
+ @post = Post.new
+ end
+
+ def create
+ @post = Post.create(params[:post])
+ redirect_to :action => "show", :id => @post.id
+ end
+ end
+
+ WeblogController::Base.view_paths = [ File.dirname(__FILE__) ]
+ WeblogController.process_cgi if $0 == __FILE__
+
+The last two lines are responsible for telling ActionController where the
+template files are located and actually running the controller on a new
+request from the web-server (like to be Apache).
+
+And the templates look like this:
+
+ weblog/layout.html.erb:
+ <html><body>
+ <%= yield %>
+ </body></html>
+
+ weblog/index.html.erb:
+ <% for post in @posts %>
+ <p><%= link_to(post.title, :action => "show", :id => post.id) %></p>
+ <% end %>
+
+ weblog/show.html.erb:
+ <p>
+ <b><%= @post.title %></b><br/>
+ <b><%= @post.content %></b>
+ </p>
+
+ weblog/new.html.erb:
+ <%= form "post" %>
+
+This simple setup will list all the posts in the system on the index page,
+which is called by accessing /weblog/. It uses the form builder for the Active
+Record model to make the new screen, which in turn hands everything over to
+the create action (that's the default target for the form builder when given a
+new model). After creating the post, it'll redirect to the show page using
+an URL such as /weblog/5 (where 5 is the id of the post).
+
+
+== Download
+
+The latest version of Action Pack can be installed with Rubygems:
+
+* gem install actionpack
+
+Documentation can be found at
+
+* http://api.rubyonrails.org
+
+
+== License
+
+Action Pack is released under the MIT license.
+
+
+== Support
+
+The Action Pack homepage is http://www.rubyonrails.org. You can find
+the Action Pack RubyForge page at http://rubyforge.org/projects/actionpack.
+And as Jim from Rake says:
+
+ Feel free to submit commits or feature requests. If you send a patch,
+ remember to update the corresponding unit tests. If fact, I prefer
+ new feature to be submitted in the form of new unit tests.