Skip to content

Merb to Rails cheatsheet

chrismear edited this page Nov 5, 2010 · 1 revision

Bundler

In Merb, dependencies are handled by built-in dependency-checker tasks, along with the thor command-line utility.

In Rails 3, gem dependencies are handled by the ‘bundler’ gem. This should be the only gem you need to install manually to your system gems:

$ sudo gem install bundler

Then, from the application directory, you can run:

$ bundle install

which (assuming your system gem directory is not writeable by your user) will install the necessary gems (the ‘bundle’) for the app in ~/.bundle.

Rails will preload the app’s bundle environment automatically, but if you want to load the app’s bundle environment in your shell (e.g. in order to run the specs), you can use the ‘bundle exec’ command, e.g.:

$ bundle exec rake spec

Or you can spawn an entire subshell in which the gem bundle is accessible, e.g.:

$ bundle exec bash

Server and console

Merb Rails
Server $ bin/merb $ bundle exec rails server
Console $ bin/merb -i $ bundle exec rails

Generating application files

You can generate files for models, controllers, mailers, etc., using the rails generate command, e.g.:

$ bundle exec rails generate model Person name:string email:string

For usage documentation, run

$ bundle exec rails generate

URLs, routes, redirecting, messages/flashes

  • Rails methods that take a URL parameter expect one of:
    • a string containing the URL;
    • a hash including at least :controller and :action; or
    • a _path method (AKA a ‘named route’).
  • If you just want to generate a URL as a string, you can use the url_for method, or a named route method, e.g.:
    url_for(:controller => 'induction', :action => 'founding_meeting')
    members_path(@member)
    proposals_url(@proposal)
Merb Rails
Redirects, URLs redirect(url(:controller => 'induction', :action => 'founding_meeting)) redirect_to(:controller => 'induction', :action => 'founding_meeting)
redirect(resource(@members)) redirect_to(members_path)
redirect(resource(@member)) redirect_to(member_path(@member))
Flash messages redirect(url(...), :message => {:error => "You must fill in the objectives."}) redirect_to_(..., :flash => {:error => "You must fill in the objectives."})
message[:error] = "You must fill in the objectives." flash[:error] = "You must fill in the objectives."

Controllers

  • Explicit call to ‘render’ at the end of the action is not required in Rails; action will render its own template by default unless a ‘redirect_to’ or ‘render’ is called.
Merb Rails
Before filters before :ensure_member_inducted before_filter :ensure_member_inducted
skip_before :ensure_organisation_active skip_before_filter :ensure_organisation_active
Halting the controller in a before filter requires :halt to be thrown:
throw :halt, redirect(url(:controller => 'induction', :action => 'founder))
Halting the controller in a before filter just requires redirect_to or a render to be called:
redirect_to(:controller => 'induction', :action => 'founder')
Responding to requested data format
provides :xml, :yaml, :js
display @member
respond_to :xml, :yaml, :js
respond_with @member

ORM finders

ActiveRecord in Rails 3 uses a relational delayed-query syntax, so you can build up a query like this:

@decisions = Decision.where(["id = ?", id]).order("name ASC")

which will return a ‘relation’. The DB query is only actually executed when you try to access members of that relation:

@decisions.each{|decision| ...}
@decisions.first
@decisions.count

This also applies to our custom ‘scopes’, so you can do things like:

@proposals = Proposal.currently_open.limit(5).order('id DESC')

WHERE clauses are given as SQL snippets into which variables are interpolated (ActiveRecord does the escaping for you). There are a couple of syntaxes for this:

Proposal.where(['name = ? AND id > ?', the_name, the_id])
Proposal.where(['name = :name AND id => :id, {:name => the_name, :id => the_id}])

There is also a simplified hash syntax for WHERE clauses that only contain ‘=’ comparisons (i.e. no ‘>’, ‘<’, ‘!=’, etc.):

Proposal.where(:name => the_name, :id => the_id)

Merb Rails
@decision = Decision.get!(id) @decision = Decision.find(id)
@decisions = Decision.all(:limit => 5, :order => [:id.desc]) @decisions = Decision.order("id DESC").limit(5)
Clause.all(:name => name, :ended_at => nil, :id.not => self.id).update!(:ended_at => Time.now.utc) Clause.where(["name = ? AND ended_at IS NULL and id != ?", name, self.id]).update_all(:ended_at => Time.now.utc)
Vote.first(:member_id => self.id, :proposal_id => proposal_id) Vote.where(:member_id => self.id, :proposal_id => proposal_id).first
Vote.count(:proposal_id => self.id, :for => false) Vote.where(:proposal_id => self.id, :for => false).count

Models

In ActiveRecord, a model’s attributes are entirely defined by the database schema. To add or remove attributes, create a database migration (e.g. rails generate migration AddSurnameToMembers), run it (rake db:migrate), and the models will pick up the change.

Boolean attributes must be queried using the ‘?’ version of the method, otherwise the integer will not be coerced into a boolean value e.g.:

Merb/DataMapper: @proposal.accepted
Rails/ActiveRecord: @proposal.accepted?

Merb Rails
has n, :votes has_many :votes
has 1, :decision has_one :decision
belongs_to :proposer, :class_name => 'Member', :child_key => [:proposer_member_id] belongs_to :proposer, :class_name => 'Member', :foreign_key => 'proposer_member_id'
after :create, :send_email after_create :send_email
validates_present :proposer_member_id validates_presence_of :proposer_member_id

Mailers

Merb Rails
DecisionMailer.dispatch_and_deliver(:notify_new_decision, {}, {:member => @member, :decision => @decision}) DecisionMailer.notify_new_decision(:member => @member, :decision => @decision).deliver

Views

  • Strings that you build by yourself (i.e. not using the built-in helpers like submit_tag, etc.) are HTML-escaped by default. To output raw HTML, use the raw helper.

Basic form

Merb:

= form(:action => url(:controller => 'induction', :action => 'create_founding_meeting_details')) do
  = text_field(:name => 'date', :value => @founding_meeting_date, :label => "Date")
  = submit("Save details and move on")

Rails:

= form_tag(:controller => 'induction', :action => 'create_founding_meeting_details') do
  = label_tag(:date)
  = text_field_tag(:date, @founding_meeting_date)
  = submit_tag("Save details and move on")

Form for a model

Merb:

= form_for(@founder, :action => url(:controller => 'induction', :action => 'create_founder')) do
  = text_field :email, :label => "Email Address"
  = submit "Save"

Rails:

= form_for(@founder, :url => {:controller => 'induction', :action => 'create_founder}) do |f|
  = f.label :email, "Email Address"
  = f.text_field :email
  = submit_tag "Save"
Merb Rails
= partial 'common/constitution', :allow_changes => false = render :partial => 'shared/constitution', :locals => {:allow_changes => false}
@datetime.formatted(:long) @datetime.to_s(:long)
time_to_go_in_words(proposal.end_date) distance_of_time_in_words_to_now(proposal.end_date)

RSpec

Testing GET request

Merb:

@response = request('/one_click')
@response.should redirect_to(url(:controller => 'induction', :action => 'founding_meeting'))

Rails:

get('/one_click')
@response.should redirect_to(:controller => 'induction', :action => 'founding_meeting')

Testing POST request

Merb:

@response = request(url(:controller=>'one_click', 
  :action=>'propose_voting_system_amendment'),
  :method=>'POST', :params=>{:membership_voting_system=>'Veto'})

Rails:

post(url_for(:controller=>'one_click', :action=>'propose_voting_system_amendment'),
  {:membership_voting_system=>'Veto'})

OCO-specific changes

  • User authentication is handled by new methods in Member, and MemberSessionsController.
Merb Rails
session.user current_user
Organisation.name Organisation.organisation_name
Member.all.active Member.active
Proposal.all_open Proposal.currently_open
Proposal.all_failed Proposal.failed

Miscellaneous syntax

Merb Rails
Merb.logger.info Rails.logger.info
JSON.parse(json_string) ActiveSupport::JSON.decode(json_string)