According to the law of demeter, a model should only talk to its immediate association, don’t talk to the association’s association and association’s property, it is a case of loose coupling.

Bad Smell

class Invoice < ActiveRecord::Base
  belongs_to :user
end

<%= @invoice.user.name %>
<%= @invoice.user.address %>
<%= @invoice.user.cellphone %>

In this example, invoice model calls the association(user)’s property(name, address and cellphone), which violates the law of demeter. We should add some wrapper methods.

Read on →

Let’s say you have an application where a User can subscribe to a Magazine. With ActiveRecord associations, it would look something like this:

# app/models/subscription.rb
class Subscription < ActiveRecord::Base
  belongs_to :magazine
  belongs_to :user
end

# app/models/user.rb
class User < ActiveRecord::Base
  has_many :subscriptions
  has_many :users, through: :subscriptions
end

# app/models/magazine.rb
class Magazine < ActiveRecord::Base
  has_many :subscriptions
  has_many :users, through: :subscriptions
end

Unfortunately, someone forgot to add dependent: :destroy to the has_many :subscriptions. When a user or magazine was deleted, an orphaned subscription was left behind.

This issue was fixed by dependent: :destroy, but there was still a large number of orphaned records lingering around. There are two ways you can use to remove the orphaned records.

Read on →

If you find some methods whose definitions are more or less similar, only different by the method name, it may use meta programming to simplify the things to make your model more clean and DRY.

Consider this simple example where we have an article with three states.

Before

class Article < ActiveRecord::Base

  def self.all_published
    where("state = ?", "published")
  end

  def self.all_draft
    where("state = ?", "draft")
  end

  def self.all_spam
     where("state = ?", "spam")
  end

  def published?
    self.state == 'published'
  end

  def draft?
    self.state == 'draft'
  end

  def spam?
    self.state == 'spam'
  end
end

Now this code can be written as:

Read on →

Previously I wrote a post for saving image as progessive image, continuing the same, here is an another gem to reduce the size of the progressive image.

    gem "paperclip-compression","~> 0.1.1"

Usage

    class User < ActiveRecord::Base
             has_attached_file :avatar,
              :styles     => { :medium => "300x300>", :thumb => "100x100>" },
              :processors => [:thumbnail, :compression]
    end

From previous learnings we can optimize this code as:

       has_attached_file :attachment, {
        :styles => {
          :medium => ["654x500>", :jpg],
          :thumb =>["200x200#", :jpg]
        },
        :convert_options => {
          :medium => "-quality 80 -interlace Plane",
          :thumb => "-quality 80 -interlace Plane"
          }
        },
         :processors => [:thumbnail, :compression]

After using this optimization trick I am able to save approx 20% of image size in my projects. Pretty nice and clean.

Rubygems are best thing that happened in ruby on rails. So today here is my list of gems in development group that helps to make things faster or sometimes bring simplicity to the development process

    gem "better_errors"
    gem "binding_of_caller"
  gem 'annotate'
  gem 'bullet'
  gem 'debugger'
  gem 'flay'
  gem 'hirb'
  gem 'localtunnel'
  gem 'lol_dba'
  gem 'mailcatcher'
  gem 'meta_request','0.2.1'
  gem 'pry'
  gem 'pry-doc'
  gem 'quiet_assets'
  gem 'rack-mini-profiler'
  gem 'railroady'
  gem 'rails-footnotes', '>= 3.7.5.rc4'
  gem 'rails_best_practices'
  gem 'reek'
  gem 'request-log-analyzer'
  gem 'smusher'
  gem 'zeus' # don't add this in your gemfile.

What they do:

  • better_errors: Better Errors replaces the standard Rails error page with a much better and more useful error page. It is also usable outside of Rails in any Rack app as Rack middleware. If you would like to use Better Errors’ advanced features (REPL, local/instance variable inspection, pretty stack frame names), you need to add the binding_of_caller

Better errors Screenshot

Read on →

For Rails apps running on Heroku, by default Time.now and some_time.localtime will display in UTC. If you’d like to assign a timezone to your app, you can set the TZ config variable to a time zone (which must be in the tz database timezone format).

Personally I despise the tz database format, because it requires you to guess WHICH city is chosen to represent that time zone (for Pacific, it’s Los_Angeles, not Seattle, not San_Francisco). But that’s what Heroku uses, so to set your app to Pacific you simply run:

 heroku config:add TZ="America/Los_Angeles"

The allowed options are listed on the page linked above.

AESCrypt is a simple gem to encryption and decryption in ruby on rails. From the readme file.

Installation

Add this line to your application’s Gemfile:

gem 'aescrypt'

and run bundler

Usage

message = "top secret message"
password = "this_is_a_secret_key_that_you_and_only_you_should_know" 

Encrypting

encrypted_data = AESCrypt.encrypt(message, password)

Decrypting

message = AESCrypt.decrypt(encrypted_data, password)

Using the select parameter in Active Record association, you can speed up your application about 50% and more.

Before

class Patient < ActiveRecord::Base
  belongs_to :physician
end
class Physician < ActiveRecord::Base
  has_many :patients
end

After

class Patient < ActiveRecord::Base
  belongs_to :physician, :select => 'id,name, surname'
end

class Physician < ActiveRecord::Base
  has_many :patients, :select => 'id,name, physician_id'
end

If you populate database with some 10000 records each. Results show that it will reduce time upto 50% with respect to fetching all the records.

Before refactoring:

Physician Load (33.9ms)  SELECT `physicians`.* FROM `physicians`
Patient Load (66.5ms)  SELECT `patients`.* FROM `patients` WHERE `patients`.`physician_id` IN (1, 2, 3,...)

After refactoring:

Physician Load (31.8ms)  SELECT `physicians`.* FROM `physicians`
Patient Load (22.3ms)  SELECT name,physician_id,id FROM `patients` WHERE `patients`.`physician_id` IN (1, 2, 3,...)

Pulling all the columns from doesn’t make any sense. So pull only those columns which we actually need. If you need to specify things in respective queries then do it.

Solution 1: Apache config file:

One solution is apache config file like I have explained here.

NameVirtualHost my_server_ip:80
<VirtualHost *:80>
ServerName example.com
RewriteEngine On
Redirect permanent / http://www.example.com
</VirtualHost>

Solution 2: Use Some Type of Rack Middleware

Another common approach is to use some type of Rack middleware to achieve the redirection

    class CanonicalRedirect

      def initialize(app)
        @app = app
      end

      def call(env)    
        request = Rack::Request.new(env)
        if request.host.starts_with?("www.")
          [301, {"Location" => request.url.sub("//www.", "//")}, []]
        else
          @app.call(env)
        end
      end

      def each(&block)
      end

    end

You’ll also need to tweak the configuration in your application.rb file.

config.autoload_paths += %W(#{config.root}/lib) 
config.middleware.use "CanonicalRedirect"

Solution 3: A Better Way: Use Rails3 Routing

Rails 3.0 offers a lot of cool new improvements to routing. I will recommend to read this rails guides article

Foo::Application.routes.draw do 
constraints(:host => /example.com/) do 
    root :to => redirect("http://www.example.com") 
        match '/*path', :to => redirect {|params| "http://www.example.com/#{params[:path]}"} 
    end 
end
Uncopyright © 2013 Mohit Jain