Ruby on Rails Cheat Sheet
by Geoffrey Grosenbach
(a work in progress)
Array String Hash
Ruby
Variables
'string' :symbol Your basic string Lightweight string local_variable Accessible only within a block or method @instance_variable Accessible to methods in a specific object @@class_variable Sets a value for all objects of the same class CONSTANT $global Set it only one time Available to the whole program (use sparingly...or never)
Data Structures
"#{a_string} variable here is interpolated" %(#{a_string} is also inserted here) 'but not here!' %q(or here, either) cheeses = ['stilton', 'cheddar', 'brie']
You can start with a few values...
sports = %w(cricket football archery)
...or split a space-delimited string.
people[42]
Retrieve values with square brackets.
options = { :url => 'http://topfunky.com', 3.14 => '!', Time.now => 'a special day' }
Any object can be used as a Hash key or value.
keys_array = options.keys
You can get all the keys from a Hash.
options = defaults.merge(options)
Keys in options take priority over keys in defaults.
options[:url]
Retrieve values with square brackets, just like an Array.
Methods
Methods can return any Object: an Array, a Hash, an Integer, or nothing at all. Methods can also include punctuation. bank_account.is_empty? By convention, methods with a question mark return a boolean value. marbles.sort! Methods with an exclamation point destructively modify their object. marbles.sort Un-punctuated methods return values and leave their object intact.
This is a class method and will be called on a bare, uninstantiated object: Visit.count_hits('/')
Required argument Optional, with default Optional, must be a Hash
Parentheses are optional when calling a method, but are usually omitted unless needed to clarify ambiguity
def self.count_hits(url, minimum_hits=100, options={}) defaults = {:since_date => (Date.today - 14)} options = defaults.merge(options) count ['url = ? AND hits > ? AND created_at > ?', url, minimum_hits, options[:since_date]] end
number_of_hits = Visit.count_hits 'index.html', 20, :since_date => (Date.today - 1)
Arguments can be split across multiple lines for readability
Loops
Objects and blocks make loops easier!
An array A single element, updated for each iteration of the loop. The name doesn't matter...choose something relevant.
rockets.each do |rocket| rocket.launch! end
do end { }
Must be on separate lines, unless separated by ; Can be used on a single line, but you must use parentheses around any method arguments.
Any object with an each() method can include Enumerable and get all these methods for free.
The same idea, but we get an integer that counts up with the array Will automatically count upwards: 0, 1, 2, 3... The name is arbitrary. You choose it.
Enumerable
fruits.include? 'kiwi'
Returns true if any elements match the argument.
pockets.each_with_index do |pocket, index| pocket.pick!("#{5 * index} pounds") end
Sets the initial value of i. Hashes and Arrays are often used, too. The final value of i will be returned
At the end of each iteration, i is set to the value returned by the block.
results = items.map { |item| ... }
Runs a block on each item and returns the new array.
sum = wallet.inject(0) { |i, money| i + money }
Classes
This class inherits from Animal and gets all its class variables, instance variables, public methods, and protected methods. An explicit return is not required. The last value in a method is automatically returned. Variables don't have to be pre-declared as a specific type. The first value assigned to a variable determines its type.
class Fox < Animal attr_accessor :health def self.breeds ['snow fox', 'desert fox', 'sea fox'] end def initialize super # Let the parent do its thing @health = 5 end def eat(food) if likes_food?(food) @health += 5 else @health += 1 end end def bark puts 'arrf' if @health > 0 @health -= 1 end private def likes_food?(food) food == 'chunky bacon' end end
Metaprogramming! A @health instance variable is created along with a health() getter and a health= setter. initialize() takes over when Fox.new is called. This is an instance method and is called on an instantiated object. Think of a specific fox you find in the desert (an instance) vs. the general idea of fox (a class).
All methods after here are only accessible to this object (not to subclasses). You can alternate back to protected or public by marking a section with one of those keywords.
Rails Basics
Convention over configuration
If you use the built-in generators and name your tables consistently, Rails will handle many tasks without further configuration. • Plural table names: books •!Singular foreign key names: vendor_id • Primary keys named id • View folders with the controller name: blog • View templates with the action name: show.rhtml • Partials start with an underscore • Other magic field names (see Model Magic Fields page)
Creating a basic Rails application from the terminal:
tf$ rails my_web_app
Creates all the necessary files and folders. You must also • Edit config/database.yml with your connection info • Create some tables, or use a migration to make tables
Further tasks:
tf$ cd my_web_app tf$ ./script/generate scaffold Article tf$ ./script/server
Don't repeat yourself
Write helper methods and use models to consolidate code.
Test-driven development
Use the built-in test files to insure the future operation of your code.
A word about Rails scaffolding
Scaffolding is a one-time starter that generates inital code. The point of scaffolding is • A shortcut for creating Controllers, Models, Views, and tests • A temporary placeholder until you write the real code Scaffolding is passive code generation. It does it one time and expects you to edit and maintain the code afterward. Active code generation happens when code is generated on the fly and is not edited, like the SQL generated by ActiveRecord models or the HTML generated by view helpers.
Models
Keeping your data in order.
The singular name of a table in your database Registers a callback method (see next page) The record won't be created or saved unless this condition is satisfied A class method. Returns an array of Article objects. Models inherit from this or from one of its children
class Article < ActiveRecord::Base before_create :generate_permalink has_many :comments validates_presence_of :subject def self.newest find_all_by_created_on Date.today end def generate_permalink @permalink = @subject.gsub(/[^A-z0-9]/, '_') end end
Defines a relationship. Will create methods for drilling down into related tables.
Model files
app/models/ All models are stored here. Models can also be in a sub-folder for organization. test/unit Model tests are kept here. Write tests to keep your models working the way the rest of the application expects them to. test/fixtures Fixtures are sample data used for testing models.
Pluralization
Pluralization can be tricky and is sometimes confusing. The general rule is to write the code the way you would say a sentence. "An article has many comments." "A comment belongs to an article."
Tables are always plural. Models are singular. Foreign keys are generally singular, but there are odd cases. See http://nubyonrails.com/tools/pluralize
Magic Fields
Rails will automatically do extra tasks for you if you use these special field names.
Callbacks
Define any of the blue methods in your model to hook-in to the saving process. The save process begins... Is this record valid? before_validation or before_validation_on_create Now we validate or validate_on_create after_validation or after_validation_on_create before_save or before_create Finally we can create after_create or after_save
Datetime
created_at created_on updated_at updated_on Updated with the current date and time
Integer
lock_version Performs optimistic locking. Will throw a StaleObjectError if an object in memory is older than the last saved version. One field must use validates_uniqueness_of #{plural_table_name}_count Keeps a tally of the number of associated objects. Requires a belongs_to association on the class to be counted. parent_id lft rgt Creates methods for maintaining a tree structure with acts_as_tree or acts_as_nested_set position Creates methods for maintaining a list structure with acts_as_list
String
type Allows inheritance within a table. Stores the name of the child class. To use, create a new model that inherits from another model instead of from ActiveRecord. Example: class Photo < Asset ... end
Model Relationships
Relationships are defined with Ruby code and work together with the rest of Rails to do validation and protect access. books id description Book has_one :cover Book has_many :chapters Book has_and_belongs_to_many :authors
covers id title book_id Cover belongs_to :book
belongs_to goes on the table with the foreign key field (book_id in this case). This creates methods for selecting and updating the book through an instance of Cover: # Get the corresponding Book my_cover.book
Join relationships work well for simple join tables: # Add authors c_lang.authors << kernighan c_lang.authors << ritchie # Get the authors as an array @authors = c_lang.authors
authors_books book_id author_id
authors_books doesn't have a
# Set it my_cover.book = my_book
corresponding model file...it is handled transparently via has_and_belongs_to_many. authors id name The joined names must be in alphabetical order.
chapters id title body book_id Chapter belongs_to :book
Author has_and_belongs_to_many :books
Views
The last step! Makes HTML, XML, and other content for the browser.
File names matter!
Rails uses file names to match actions and the templates that are rendered. app/views/ All your view templates are stored in subdirectories here. layouts/ The bread of the template sandwich goes here. Other views will be slipped inside these templates (see next page). application.rhtml This is the master template. It is used for all pages unless... blog.rhtml If this file exists, the BlogController will use it instead of application.rhtml blog/ The BlogController looks here for files that match the names of actions (like show.rhtml or edit.rhtml). This is the roast beef in the template sandwich.
.rhtml
Generates HTML (can also be used for plain text)
Prints a value to the template
<%=h @title %>
Escapes HTML content for safety (optional)
Omits this line's whitespace from the final output (optional)
<% if authorized? -%>
Non-printing. For loops and conditionals only.
Code comment (won't be printed)
<%# TODO Drunk...fix later %> Sample rhtml:
And here are some comments:
<% @comments.each do |comment| -%> <% end -%>
File names still matter!
Actual template filenames show whether it is a major or minor template. list.rhtml A normal template. Sandwich templates from layouts will be used around this (if one exists). _form.rhtml A partial. By convention, signifies a template that is used by several other templates, or multiple times in the same template. For example, a form that is used both for creating a new item and for editing an existing one.
application.rhtml <%= @title %> Blog-o-Rama
<%= @content_for_layout %>
The main application.rhtml is used when no other layout template matches the name of the current controller. The result of the relevant action template will populate the @content_for_layout variable.
list.rhtml Today's Posts
<%= render :collection => @posts, :partial => 'post' %>
Most of the work is done by the template for a specific action. The template matching the name of the current action will be used by default, but you can call another template with the render method.
The _post partial will be rendered once for every item in the @posts array. A local variable will be created with the same name as the partial.
_post.rhtml <%= post.title %>
<%= post.body %>
Standard View Template Libraries
There are two built-in template systems and several other third-party template systems.
.rhtml
Create (hopefully valid) HTML. Looks like a PHP template.
xml.channel do xml.title @feed_title xml.link @link xml.language "en-us" xml.ttl "40" xml.description @subtitle end
.rxml
For making RSS feeds or other XML-based data output.
Other Template Systems
The plugin system makes it easy to download and use other template systems.
.mab
Markaby. Generate HTML with pure Ruby code. No angle brackets needed!
.rjs
Creates Javascript for sending back in response to Ajax requests. Included in Rails 1.1.
.rtex
Write LaTeX which is converted to PDF.
page.hide "spinner#{@task.id}" page.call 'Element.remove', "task_form#{@task.id}" page.insert_html :bottom, 'tasks_today', :partial => 'task', :locals => {:task => @task}
Controllers
Connects the database and the view.
Filters call a method before or after actions. They can also be limited to certain actions only. All instance variables in the controller will be available to the view template.
The controller name. Matches part of the URL. (see below)
params is a hash of arguments sent in the URL or in a form POST. Form params have sub-hashes: params[:article][:subject]
class BlogController < ApplicationController before_filter :login_required def update @article = Article.find(params[:id]) if @article.update_attributes(params[:article]) flash[:notice] = 'Success!' redirect_to :action => 'show', :id => @article else render :action => 'edit' end end end
The flash is a special hash that lives for only one request after it is set. Even though the parameter is called 'action', this renders the 'edit' template.
Controller methods are not available to the view template. Methods in the corresponding helper can be used from the view.
Pretty URL's
URL's for specific controllers can be specified in routes.rb. The default route interprets the URL as controller, action, id.
Specifies the Controller that will handle this request params[:id]
http://topfunky.com/blog/show/1?order=reverse
Extra parameters not specified in routes.rb params[:order]
The action. Matches the name of a method in the controller.
to be continued...
Consult http://nubyonrails.com