David Heinemeier Hanson extracted this framework from his work on 37signals’ Basecamp (a hosted project collaboration tool) Makes Web development easy through simple conventions (rather than extensive configuration), and the “Don’t Repeat Yourself” principle (localize change): Examples: order records are known to be stored in an Orders table, no mapping required (in numerous .xml configuration files) http://localhost/order/list/100 is pointing to an Order processing component, and its list() method will be called with a value = 100 View partials contain reusable snippets to be reused over many web pages. Makes maintenance and deployment easy through enforced code structure and built-in plumbing: MVC, ORM, testing.
Controller: accepts HTTP requests, parses URL, extracts parameters, forwards to specific Action (bridge between Controller and Model) Model: retrieves/persists data encapsulating access and domain logic View: render and present the model in an HTML (or XML) format
Controller (DispatchServlet) orchestrates the application: extracts parameters from request and interacts with the model through a specific action (ActionController subclass) based solely on the URL pattern: Example: http://localhost/order/list/100 directs to OrderController (defined in order_controller.rb) and passes to the method list() the value 100. That would display row with id=100. Change list with delete and the same row gets deleted invokes the view providing the presentation and rendering of the model ActionController along with ActionView (the Action Pack) form the core processing of incoming requests and generating responses.
View: a combination of templates, partials and layouts all using plain Ruby code tag libraries It presents the user with various ways to display/input data but it never handles incoming data ActionView module encapsulates required functionality to render templates (i.e. generate HTML or XML) in response to user requests Writing a view = writing a template associated with an action result (i.e. HTML fragments interwoven with Ruby code statements placed between &lt;% %&gt;) Controller instance variables are also available in templates (actions communicating data to templates), and a template can also call any public methods on the controller .rxml templates render XML pages, while .rhtml templates render HTML pages
Model: ActiveRecord wrapping framework An ActiveRecord subclass wraps a row in a database table/view and encapsulates access and domain logic, and acts as the gatekeeper of the datastore. Starts with the database table, as opposed to starting with the object model as mapping frameworks usually do (i.e. Hibernate) Wraps class hierarchies to relational tables through single table inheritance: adding a string column ‘TYPE’ to the table persisting the hierarchy. Note: column name can be overridden using inheritance_column() Wraps the following table relationships (one-to-one, one-to-many, many-to-many) through declarations in the model (belongs-to, has-one, has-many, has-and-belongs-to-many), and also supports: acts_as_tree, acts_as_list Differs from other ORM implementations through its “convention over configuration” principle which implies a sensible set of defaults
A one-to-many aggregation representing a collection: a given order’s line item rows contain a foreign key column referring back to order. In Rails one just needs to add the has_many declaration in the parent object (logically containing the collection of child objects) showing its relationship to the child table declaring the belongs_to for its parent:
An act-as-tree structure can often be found in Category listings where entries have subentries, and those subentries may have their own subentries.
create_table :parents, :force =&gt; true do |t| end create_table :children, :force =&gt; true do |t| t.column :parent_id, :integer t.column :name, :string t.column :position, :integer end
Wrapping an object view of some data to certain tables in a relational database: wraps tables to classes, rows to objects, and columns to object attributes implicit conventions (customizable): Active Record expects the table name to be the plural form for the class name Active Record reflects on the database schema to configure the classes that wrap tables Active Record instance attributes generally correspond to the data in the corresponding database table row each table associated with a class has an integer primary key column named id Active Record abstracts the concept of a database connection, delegating the details to a set of database-specific adapters
Rails encourages an agile, iterative style of development in a Rails application the database schema constantly evolves (i.e. adding a new class/table, renaming an attribute/column), while in sync with the application’s code. ActiveRecord::Migration abstracts the data manipulation in a database table and allows reversible actions: creation: up() method removal: down() method A migration is simply a Ruby source file placed under version control alongside all our other application files. Each migration file’s name starts with (by default) three digits and an underscore, the version which defines the sequence in which the migrations are applied. Warning: migrations do not currently feature transactional support (i.e. an atomic failure inside up() may not allow the migration to be reapplied or even rolled back)
Scaffold, the ActionController feature providing a series of standardized actions for listing, showing, creating, updating, and destroying objects of a class/table. Static scaffold: $ ruby script/generate scaffold product admin Scaffold generator takes the model and controller names and renders standardized actions containing both controller logic and default templates (introspection provides the fields to display and types) Scaffold generator automatically creates code that will respond appropriate to requests for HTML or XML content. Scaffold-generated applications use the scaffold.css stylesheet (public/stylesheets) which could be customized/replaced. Dynamic scaffold: scaffold :product declaration tells Rails to generate the application code at runtime for immediate use in testing of a newly added model and controller web_service_scaffold() :invoke provides a way to execute web service methods from a web browser while in development.
Applying “tough love” on our beloved applications even before they are written: Rails framework has the support for testing baked right in from the start of every project (i.e. any top-level project directory created contains a subdirectory called test), plus a special database just for test (see database.yml) By convention, Rails calls things testing models: unit tests things testing a single action in a controller: functional tests things testing the flow through controllers: integration tests Rails even creates the files to hold the unit tests for the models and the functional tests for the controllers created with the generate script The testing starts from the data (unit test the models) and moves up closer to where the user interaction (functional and integration)
Assertion: a method call stating the expectations (i.e. the simplest assertion is the method assert(), expecting its argument to be true). Unit Tests: collection of assertions that validate a model Functional Tests: collection of assertions that validate a controller’s action (example: test_delete_item) Fixtures: simply a specification of the initial contents of a model(s) under test (test/fixtures directory). Mocks: a simple replacement for a known object that frees the tests from needing some sort of resource (network connection) while ensuring more consistent and repeatable results.
Webrick is sufficient in development for the single-threaded Rails Highly concurrent production environments require a front-end server (i.e. Apache, Lighttpd, or Zeus), and a proxy to distribute requests to Rails processes running on any number of back-end machines: FastCGI with its long-running processes can handle multiple sequential requests, therefore Ruby interpreter and Rails framework is loaded once per process and turn around requests for the host web server quickly. Mongrel (Ruby-based web-server) could be HTTP proxied by the front-end directly and makes for a better solution that is considered future proof and extensible It’s better to start doing deployment: early (as soon as few views already display) in order to identify any deployment issues often (after any major commit) in order to have early feedback from management and customers Capistrano, a RubyGem utility, provides reliable and repeatable deployment for Rails applications on remote servers.