Ruby & Rails best practices

Saturday, February 27, 2010

Rails Best Practices



• Concept: What’s good code?
• Move Code from Controller to Model
• RESTful best practices
• Model best practices
• Controller best practices
• View best practices


1. Move Code from Controller to Model
Before

class PostsController < Application controller
def index
public_posts =" Post.find(:all," conditions =""> { :state => 'public' }, :limit => 10, :order => 'created_at desc')
@draft_posts = Post.find(:all, :conditions => { :state => 'draft' }, :limit => 10, :order => 'created_at desc')
end
end

After

class UsersController < ApplicationController
def index
@published_post = Post.published
@draft_post = Post.draft
end
end

class Post < ActiveRecord::Base
named_scope :published, :conditions => { :state => 'published' }, :limit => 10, :order => 'created_at desc')
named_scope :draft, :conditions => { :state => 'draft' }, :limit => 10, :order => 'created_at desc')
end

2. Use model association
Before

class PostsController < ApplicationController
def create
@post = Post.new(params[:post])
@post.user_id = current_user.id
@post.save
end
end

After

class PostsController < ApplicationController
def create @post = current_user.posts.build(params[:post])
@post.save
end
end

class User < ActiveRecord::Base
has_many :posts
end

3. Use scope access
Before
 
class PostsController < ApplicationController
def edit
@post = Post.find(params[:id)
if @post.current_user != current_user
flash[:warning] = 'Access denied'
redirect_to posts_url
end
end
end

After

class PostsController < ApplicationController
def edit
# raise RecordNotFound exception (404 error) if not found
@post = current_user.posts.find(params[:id)
end
end

4. Add model virtual attribute
Before
  
<% form_for @user do |f| %>
<%= text_filed_tag :full_name %>
<% end %>

class UsersController < ApplicationController
def create
@user = User.new(params[:user)
@user.first_name = params[:full_name].split(' ', 2).first
@user.last_name = params[:full_name].split(' ', 2).last
@user.save
end
end

After

class User < ActiveRecord::Base
def full_name
[first_name, last_name].join(' ')
end
def full_name=(name)
split = name.split(' ', 2)
self.first_name = split.first
self.last_name = split.last
end
end

<% form_for @user do |f| %>
<%= f.text_field :full_name %>
<% end %>

class UsersController < ApplicationController
def create
@user = User.create(params[:user)
end
end

5. Use model callback
Before

<% form_for @post do |f| %>
<%= f.text_field :content %>
<%= check_box_tag 'auto_tagging' %>
<% end %>

class PostController < ApplicationController
def create
@post = Post.new(params[:post])
if params[:auto_tagging] == '1'
@post.tags = AsiaSearch.generate_tags(@post.content)
else
@post.tags = ""
end
@post.save
end
end

After

class Post < ActiveRecord::Base
attr_accessor :auto_tagging
before_save :generate_taggings
private
def generate_taggings
return unless auto_tagging == '1'
self.tags = Asia.search(self.content)
end
end

<% form_for :note, ... do |f| %>
<%= f.text_field :content %>
<%= f.check_box :auto_tagging %>
<% end %>

class PostController < ApplicationController
def create
@post = Post.new(params[:post])
@post.save
end
end

6. Replace Complex Creation
Before with Factory Method

class InvoiceController < ApplicationController
def create
@invoice = Invoice.new(params[:invoice])
@invoice.address = current_user.address
@invoice.phone = current_user.phone
@invoice.vip = ( @invoice.amount > 1000 )
if Time.now.day > 15
@invoice.delivery_time = Time.now + 2.month
else
@invoice.delivery_time = Time.now + 1.month
end
@invoice.save
end
end

After with Factory Method

class Invoice < ActiveRecord::Base
def self.new_by_user(params, user)
invoice = self.new(params)
invoice.address = user.address
invoice.phone = user.phone
invoice.vip = ( invoice.amount > 1000 )
if Time.now.day > 15
invoice.delivery_time = Time.now + 2.month
else
invoice.delivery_time = Time.now + 1.month
end
end
end

class InvoiceController < ApplicationController
def create
@invoice = Invoice.new_by_user(params[:invoice], current_user)
@invoice.save
end
end

7. Move Model Logic into the
Before Model

class PostController < ApplicationController
def publish @post = Post.find(params[:id])
@post.update_attribute(:is_published, true)
@post.approved_by = current_user
if @post.create_at > Time.now - 7.days
@post.popular = 100
else
@post.popular = 0
end
redirect_to post_url(@post)
end
end

After Model

class Post < ActiveRecord::Base
def publish
self.is_published = true
self.approved_by = current_user
if self.create_at > Time.now-7.days
self.popular = 100
else
self.popular = 0
end
end
end

class PostController < ApplicationController
def publish @post = Post.find(params[:id])
@post.publish
redirect_to post_url(@post)
end
end

Pairworks Released

Monday, February 22, 2010

Release Notes

Home page:
1.Re-designed
2.Video for pairworks overview
3.Ten reasons why you need pairworks
4.Tour page re-designed

Graphical reports:
1. Velocity chart
2. Product release burndown chart
3. Project history


and much more..
Please give us your comments.

Save a restaurant from its competitor - Mind Map exercise

Monday, February 15, 2010


When you foster right environment, creative juices flow immensely, thereby producing lot of great, funny ideas. Last week's team meeting was one such environment, which produced this great looking mind map. Our exercise was to develop a plan/mind map to save a restaurant whose revenue is threatened by a competitor, planning to open a branch nearby. Our team started on a big white board with spoon and fork in the middle (representing the restaurant). Mind map slowly started unfolding right in front of our eyes with every one's involvement, which was the sight to watch. Attached is the completed mind map.