News

Welcome to End Point’s blog

Ongoing observations by End Point people

Ruby on Rails versus CakePHP: A Syntax Comparison Guide

My time is typically split between Interchange and Spree development, but in a recent project for JackThreads, I jumped back into CakePHP code. CakePHP is one of the more popular PHP MVC frameworks and is inspired by Rails. I decided to put together a quick syntax comparison guide between CakePHP and Rails since I occasionally have to look up how to do some Rails-y thing in CakePHP.

Basic

Ruby on Rails CakePHP
MVC Code Inclusion Rails is typically installed as a gem and source code lives in the user's gem library. In theory, a modified version of the Rails source code can be "frozen" to your application, but I would guess this is pretty rare. CakePHP is typically installed in the application directory in a "cake/" directory. The "app/" directory contains application specific code. From my experience, this organization has allowed me to easily debug CakePHP objects, but didn't do much more for me.
Application Directory Structure
app/
  controllers/ models/ views/ helpers/ 
lib/
config/
public
  javascripts/ images/ stylesheets/
vendors/
  plugins/ extensions/
controllers/
models/
views/
  layouts/ elements/ ...
config/
webroot/
tmp/
plugins/
vendors/
Notes: In Rails, layouts live in app/views/layouts/. In CakePHP, layouts live in views/layouts/ and helpers lie in views/helpers/.
Creating an Application
rails new my_app # Rails 3 after gem installation
rails my_app # Rails <3
Download the compressed source code and create an application with the recommended directory structure.

Models

Ruby on Rails CakePHP
Validation
class Zone < ActiveRecord::Base
  validates_presence_of :name
  validates_uniqueness_of :name
end
class User extends AppModel {
  var $name = 'User';
  var $validate = array(
    'email' => array(
      'email-create' => array(
        'rule' => 'email',
        'message' => 'Invalid e-mail.',
        'required' => true,
        'on' => 'create'
      )
    )
  );
}
Relationships
class Order < ActiveRecord::Base
  belongs_to :user
  has_many :line_items
end
class Invite extends AppModel {
  var $name = 'Invite';
  var $belongsTo = 'User';
  var $hasMany = 'Campaigns';
}
Special Relationships
class Address < ActiveRecord::Base
  has_many :billing_checkouts,
    :foreign_key => "bill_address_id",
    :class_name => "Checkout"
end
class Foo extends AppModel {
  var $name = 'Foo';
  var $hasMany = array(
    'SpecialEntity' => array(
      'className' => 'SpecialEntity',
      'foreignKey' => 'entity_id',
      'conditions' =>
  array('Special.entity_class' => 'Foo'),
      'dependent' => true
    ),
  );
}

Controllers

Ruby on Rails CakePHP
Basic Syntax
class FoosController < ActionController::Base
  helper :taxons
  actions :show, :index

  include Spree::Search

  layout 'special'
end
class FooController extends AppController {
  var $name = 'Foo';
  var $helpers = array('Server', 'Cart');
  var $uses = array('SpecialEntity','User');
  var $components = array('Thing1', 'Thing2');
  var $layout = 'standard';
}
Notes: CakePHP and Rails use similar helper and layout declarations. In CakePHP, the $uses array initiates required models to be used in the controller, while in Rails all application models are available without an explicit include. In CakePHP, the $components array initiates required classes to be used in the controller, while in Rails you will use "include ClassName" to include a module.
Filters
class FoosController < ActionController::Base
  before_filter :load_data, :only => :show
end
class FooController extends AppController {
  var $name = 'Foo';

  function beforeFilter() {
    parent::beforeFilter();
    //do stuff
  } 
}
Setting View Variables
class FoosController < ActionController::Base
  def index
    @special_title = 'This is the Special Title!'
  end
end
class FooController extends AppController {
  var $name = 'Foo';

  function index() {
    $this->set('title',
      'This is the Special Title!');
  }
}

Views

Ruby on Rails CakePHP
Variable Display
<%= @special_title %>
<?= $special_title ?>
Looping
<% @foos.each do |foo| -%>
<%= foo.name %>
<% end -%>
<?php foreach($items as $item): ?>
<?= $item['name']; ?>
<?php endforeach; ?>
Partial Views or Elements
<%= render :partial => 'shared/view_name',
  :locals => { :b => "abc" } %>
<?php echo $this->element('account_menu',
  array('page_type' => 'contact')); ?>
Notes: In Rails, partial views typically can live anywhere in the app/views directory. A shared view will typically be seen in the app/views/shared/ directory and a model specific partial view will be seen in the app/views/model_name/ directory. In CakePHP, partial views are referred to as elements and live in the views/elements directory.
CSS and JS
<%= javascript_include_tag
  'my_javascript',
  'my_javascript2' %>
<%= stylesheet_link_tag
  'my_style' %>
<?php
  $html->css(array('my_style.css'),
    null, array(), false);
  $javascript->link(array('my_javascript.js'),
    false);
?>

Routing

Ruby on Rails CakePHP
Basic
# Rails 3
match '/cart',
  :to => 'orders#edit',
  :via => :get,
  :as => :cart
# Rails <3
map.login '/login',
  :controller => 'user_sessions',
  :action => 'new'
Router::connect('/refer',
  array('controller' => 'invites',
        'action' => 'refer'));
Router::connect('/sales/:sale_id',
  array('controller' => 'sale',
        'action' => 'show'),
  array('sale_id' => '[0-9]+')); 
Nested or Namespace Routing
# Rails 3
namespace :admin do
  resources :foos do
    collection do
      get :revenue
      get :profit
    end
  end
end

# Rails <3
map.namespace :admin do |admin|
  admin.resources :foos, :collection => {
    :revenue            => :get,
    :profit             => :get,
  }
end
-

Logging

Ruby on Rails CakePHP
Where to? tmp/log/production.log or tmp/log/debug.log tmp/logs/debug.log or tmp/logs/error.log
Logging Syntax
Rails.logger.warn "steph!" # Rails 3
logger.warn "steph!" # Rails <3
or
RAILS_DEFAULT_LOGGER.warn "steph!"
$this->log('steph!', LOG_DEBUG);

If you are looking for guidance on choosing one of these technologies, below are common arguments. In End Point's case, we choose whatever technology makes the most sense for the client. We implemented a nifty solution for JackThreads to avoid a complete rewrite, described here in detail. We also work with existing open source ecommerce platforms such as Interchange and Spree and try to choose the best fit for each client.

Pick Me!

Ruby on Rails CakePHP
  • Ruby is prettier than PHP.
  • Rails Object Oriented Programming implementation is more elegant than in CakePHP.
  • Rails routing is far superior to CakePHP routing.
  • Deployment and writing migrations are simpler with built in or peripheral tools.
  • Documentation of Rails is better than CakePHP.
  • CakePHP has better performance than Rails. UPDATE: This appears to be a rumor. Benchmark data suggests that Rails performs better than CakePHP.
  • PHP is supported on hosting providers better than Rails.
  • PHP developers are typically less expensive than Ruby/Rails developers.

8 comments:

Bryan said...

this is awesome. i'd love to see you add some more comparisons - django, asp.net mvc, etc...

glenngillen said...

Where are the benchmarks showing Cake if faster than Rails?

As for PHP devs being cheaper: Coming from a PHP background myself I can say that the PHP devs that have impressed me (i.e., that I'd want to work with or would happily employ) charge the same daily rate as the Ruby devs I've been impressed by. You get what you pay for.

As you've mentioned the biggest problem for most businesses is probably the support on the server side. If you want easy deployments you either need to set it all up yourself or go with a Ruby focussed hosting provider.

Steph Skardal said...

I hadn't seen any specific CakePHP versus Rails benchmark tests when I wrote this article but was merely just stating the common arguments made for CakePHP over Rails.

However, I found some benchmark data here - these numbers show CakePHP to be slower than Rails.

glenngillen said...

Sorry Steph, was a bit flippant in my initial reply. I've not done any benchmarks myself, but most I've seen have pointed out that ruby has been faster than PHP for about 3 years now. If Rails was indeed slower than Cake, it wouldn't have been able to use ruby as an excuse any more.

Just didn't want an otherwise great comparison to continue persisting a myth.

Steph Skardal said...

No worries. I've updated the original content to clarify this myth. Thanks for pointing it out!

Mihai Târnovan said...

Regarding loops in Rails:

# Rails 3
<%= @foos.each do |foo| -%>
<%= foo.name %>
<% end -%>

This is definitely not what you'd want for looping, as the extra = on the loop line will output the return value of the block, which is @foos. So with @foos = [1,2,3] this will output:

1 2 3 123

or something similar.

kaushalrajiv said...

Excellent comparison. Easy to understand. Anyone can learn quickly how both language are used. Many thanks for such a great article on comparison.

Anonymous said...

Very neat and nice comparison. Love to see more comparison between these two