Francis's Octopress Blog

A blogging framework for hackers.

My Five Favorite “hidden” Features in Rails 3.2

My five favorite “hidden” features in Rails 3.2

Rails 3.2 is out with great features on spotlight: faster development reloading, faster router and explain queries. However, every Rails release ships with minor features that do not get that much attention but still would be a great fit to your application. This blog post is about my five favorites “hidden” features of Rails 3.2.

1) Smarter content_tag_for

This feature written by Prem Sichanugrist provides a very simple but welcome clean up to your views. Both content_tag_for and div_for now accepts an array of records and automatically loop over each record. Therefore, instead of writing this:

  @posts.each do |post|
    content_tag_for(:li, post) do
      ...
    end
  end

You can simply write:

  content_tag_for(:li, @posts) do |post|
    ...
  end

2) Smarter migration generators

It is funny how some parts of Rails as old as the migration generators continue receiving improvements day after day. Rails 3.1 already added a feature that automatically generate indexes for associations, by simply invoking:

 

rails g scaffold Comment post:references title:string body:text

 

With the above, Rails will detect that post is a reference and it will automatically 1) add a post_idinteger column, 2) add an association to your model and 3) add an index to that column.

Right after 3.1 came out, I have pushed another small feature to the migration generator that simply makes the type attribute default to string. Therefore, you no longer need to write:

 

rails g scaffold Person name:string email:string

 

You could simply write:

 

rails g scaffold Person name email

 

Oddly enough, the idea for this feature came when I was preparing a presentation and the scaffold command could not fit in a slide (the so-called Presentation Driven Development). Anyhow, this small addition would not be enough to make to the best five “hidden” features of Rails 3.2. That’s when Dmitrii Samoilov comes in.

Dmitrii sent a pull request that allows you to specify which columns should have an (unique) index. So one could write:

 

rails g scaffold Person name:index email:uniq

 

And the generator will automatically generate an index for name and an unique index for e-mail. There are other features there as well, so don’t forget to checkout the CHANGELOG.

3) Flexible exception handling

When Rails 3.0 came out, one of the features that people suddenly missed was the ability to better handle exceptions. The issue was: since Rails 3 became a lot more Rack “fluent”, we had to move some features to the middleware stack and this forced us to move the whole exceptions handling as well. Rails 3.2 attempts to bring some customization back to the game by allowing you to set your own exceptions rack application that is invoked when a failure happens. For instance, you could set the exceptions application to your own router in yourconfig/application.rb:

config.exceptions_app = self.routes

Now, every time there is an exception, your router is going to be invoked. Therefore, to render custom 404 pages, you could simply add to your router:

match "/404", :to => "errors#not_found"

And implement the logic in the controller as you wish! However, there are a few things to keep in mind if you go down this road:

  1. You need to use match in your routes and not get/post/put/delete because such exceptions can happen in any HTTP request;
  2. You won’t be able to see your custom exceptions in development unless you setconfig.consider_all_requests_local to false in your config/environments/development.rb. The reason is, if the request is considered local, Rails will always favor to show the debug exceptions page;
  3. You can always access the original exception in the controller atenv["action_dispatch.exception"];
  4. It is not possible to set cookies, the session nor the flash after an exception happens. They all were already serialized back to the client;
  5. Finally, the default exceptions application used by Rails that simply renders a page inpublic/STATUS.html is available here: action_dispatch/middleware/public_exceptions.rb

Remember that whatever you do in the errors controller, it should not be anything “fancy”. Keep it simple because something already went wrong with your application!

4) Custom partial paths

In order to render a partial for a given model, Rails 3.0 retrieved the partial name by calling:model.class.model_name.partial_pathGrant Hutchins & Peter Jaros noticed that this was not very flexible because the class was responsible to define the partial path and therefore they decided to move this responsibility to the instance. In order to better understand how you can use this feature, let’s consider the following practical example.

Imagine your application have an activity feed and each activity in the feed has a certain type. Usually, each type is rendered differently. For example, if you consider a to-do-list application, activities could be both “marking a list as favorite” or “marking a task as done”. Usually, applications solve this by looping for each item and rendering its respective partial, something like this:

@activities.each do |activity|
  render :partial => "activities/#{activity.kind}",
    :locals => { :activity =>  activity }
end

Now, you can solve this problem by defining to_partial_path in the model (the methodto_partial_path is part of the ActiveModel API and can be implemented in any object. The example above implements it in the model for convenience, but it could be a presenter, another ORM, etc):

class Activity < ActiveRecord::Base
  def to_partial_path() "activities/#{kind}" end
end

And then invoking:

render :partial => @activities, :as => :activity

This will now work on Rails 3.2 because even though all activities are of the same class, each instance is actually responsible for telling Rails which partial should be rendered.

The difference here is not only in brevity, but also in performance. Although the first snippet works fine, it is slow. In the scenario where only one kind of activity happened, the first snippet will go through the render stack 30 times and lookup the same template in your filesystem 30 times. If you read Crafting Rails Applications you know that this lookup is cached, but even though it would certainly be faster if we didn’t have to do this 30 times, but once.

That’s where render :collection or render :partial with an array comes in. In such cases Rails will retrieve all templates up front skipping duplicates, and this new feature allows us to take advantage of it even if the partial lookup is dynamic. So, in the scenario where all the activities are of the same kind, the template lookup will happen just once and no longer 30 times. In other words, best case scenario becomes O(1), worst case scenario is still O(n).

5) Filtered chain logging is back

Another very small change that will make development more pleasant is that Rails will now log “Filter chain halted as CALLBACK_NAME rendered or redirected” every time a before/around/after filter in your controller halts the request. This was the case in Rails 2.3 but somehow got lost when Rails 3 came out. It is one of those small things you don’t know how much you missed until you see it again!

And what is your favorite Rails 3.2 “hidden” feature? Don’t forget to take a good look at the CHANGELOGs and check out many others improvements!

 

Tags: 

Rails Date_select Fields Hidden And

Rails date_select fields hidden and

Another 2 hours wasted. Today I was trying to use the date_select helper, but I could not figure out why the fields kept showing up as hidden inputs instead of select boxes.

Poked around for a long long long time, before catching this tidbit

: order – Set to an array containing :day, :month and :year do customize the order in which the select fields are shown. If you leave out any of the symbols, the respective select will not be shown (like when you set :discard_xxx => true. Defaults to the order defined in the respective locale (e.g. [:year, :month, :day] in the en locale that ships with Rails).

For some god forsaken reason, the “order” on the date_select field in my app was not set, or is defaulted to something else. I have no idea where this happens, or how it happens. But adding and order param fixed my problem

f.datetime_select :start_time, :order => [:year, :month, :day]
  • :discard_day - Set to true if you don’t want to show a day select. This includes the day as a hidden field instead of showing a select field. Also note that this implicitly sets the day to be the first of the given month in order to not create invalid dates like 31 February.
  • :discard_month - Set to true if you don’t want to show a month select. This includes the month as a hidden field instead of showing a select field. Also note that this implicitly sets :discard_day to true.
  • :discard_year - Set to true if you don’t want to show a year select. This includes the year as a hidden field instead of showing a select field.
  • :order - Set to an array containing :day:month and :year to customize the order in which the select fields are shown. If you leave out any of the symbols, the respective select will not be shown (like when you set :discard_xxx => true. Defaults to the order defined in the respective locale (e.g. [:year, :month, :day] in the en locale that ships with Rails).

Simple CRUD With MongoDB

Simple CRUD with MongoDB

When I meet a new technology, I like to experience it “just as it comes”. I’m happy at the command line and I like to type actual commands and see man pages before I use any wrappers or helper tools. So when I met MongoDB for the first time, I did exactly that. This post shows those first steps of creating a database, and inserting, reading, deleting and updating data.

Before we begin, you should install mongo. This is painless and for me, on ubuntu, sudo aptitude install mongodb did the trick.

Some Terminology

Here are some translations from the RDBMS equivalent wording:

  • “database” is still “database”
  • “table” becomes “collection”
  • “row” becomes “record”
  • try to forget the word “column”, we don’t have those

Let’s Begin

Creating a Database

You don’t really create a database with mongo, you just kind of start using it. Once you put something in there, it exists. I’m going to name my new database pets.

use pets

Adding Data

To do anything in mongo, you start your command with db which refers to the database you’re using. The different parts of the command are separated by dots. To insert data you use a command like db.[collection].save() and feed in the data to save. The format of the data is JSON-esque – I read JSON but I don’t really write it, however I found it became familiar pretty quickly. To insert some data, you can do:

> db.animals.save({'animal':'cat', 'name':'fluffy', 'type':'long-haired', 'owner':'Anna'});
> db.animals.save({'animal':'dog', 'type':'spaniel', 'name':'toffee', 'colour':'toffee', 'owner':'Ben'});
> db.animals.save({'owner':'Ben', 'animal':'cat', 'name':'ginger', 'collar':true});

Fetching Data

Did anything happen? We can check, using db.[collection].find() - this will give us everything in the collection, a bit like select * from [table] does in SQL.

> db.animals.find();
{ "_id" : ObjectId("4ebb8fd68f7aaffc5d287383"), "animal" : "cat", "name" : "fluffy", "type" : "long-haired", "owner" : "Anna" }
{ "_id" : ObjectId("4ebb90048f7aaffc5d287384"), "animal" : "dog", "type" : "spaniel", "name" : "toffee", "colour" : "toffee", "owner" : "Ben" }
{ "_id" : ObjectId("4ebb90768f7aaffc5d287385"), "owner" : "Ben", "animal" : "cat", "name" : "ginger", "collar" : true }

We definitely have data! We can also filter this down, the equivalent of adding a “where” clause, for example, let’s only see cats:

> db.animals.find({'animal':'cat'});
{ "_id" : ObjectId("4ebb8fd68f7aaffc5d287383"), "animal" : "cat", "name" : "fluffy", "type" : "long-haired", "owner" : "Anna" }
{ "_id" : ObjectId("4ebb90768f7aaffc5d287385"), "owner" : "Ben", "animal" : "cat", "name" : "ginger", "collar" : true }

You can add multiple constraints here, how about cats belonging to Ben?

> db.animals.find({'animal':'cat', 'owner':'Ben'});
{ "_id" : ObjectId("4ebb90768f7aaffc5d287385"), "owner" : "Ben", "animal" : "cat", "name" : "ginger", "collar" : true }

If any of the records don’t have the field you’re searching on, they won’t appear in the results. We’re not tied to a rigid structure of columns so you can just throw in whichever data seems useful at the time, and search on whatever is there. We can also search on whether we have the field at all, for example, animals where we know what colour they are:

> db.animals.find({colour: {$exists: true}});
{ "_id" : ObjectId("4ebb90048f7aaffc5d287384"), "animal" : "dog", "type" : "spaniel", "name" : "toffee", "colour" : "toffee", "owner" : "Ben" }

Updating Data

This confused me for a long time, as mongo does have an update() function, which you can use to update one or many records in a particular way. What I found I really wanted though was to use the save() method again, because if the record has an identifier that exists, mongo will update it, otherwise it will insert it as we saw above. So we can just grab a record and change it, then save it:

> db.animals.find({'animal':'dog'});
{ "_id" : ObjectId("4ebb90048f7aaffc5d287384"), "animal" : "dog", "type" : "spaniel", "name" : "toffee", "colour" : "toffee", "owner" : "Ben" }
db.animals.save({ "_id" : ObjectId("4ebb90048f7aaffc5d287384"), "animal" : "dog", "breed" : "spaniel", "name" : "toffee", "colour" : "toffee", "owner" : "Ben" });

I realised that calling a spaniel a “type” of dog would be better expressed as being a “breed”, so I simply changed that record and mongo updated it for me. The update() statement is better for working on sets of records – for example if we decide Ben should be using his Sunday name:

> db.animals.update({'owner':'Ben'}, {$set: {'owner':'Benjamin'}}, false, true);

There’s a lot going on here, so let’s look at the pieces step-by-step. The documentation describes the update function as:

db.collection.update( criteria, objNew, upsert, multi )

The first part, the criteria is the same as we would use for the find() method. The next argument is what we’re changing. I’m just setting one field to a given value, so I used the $set modifier (modifiers are an art in themselves, this post is rambling on already so I’ll write about those another day if you’re interested). The next argument is the upsert, which is whether to insert a new record if we didn’t find any matches – I want to update existing records, not insert anything, so I set this to false. Finally the multi flag tells mongo to update ALL the records it can find that match thecriteria, if this is false it will stop after one (lazy thing!).

Deleting Data

If you’ve come this far then I’m impressed, and deleting is the easy part so we’re almost there! Exactly like the find()and update() commands, we just supply a criteria to the remove() command. This could be either one of the fields, as we used already, or the object ID itself, like this:

> db.animals.remove({_id: ObjectId("4ebb90768f7aaffc5d287385")});

As with all things mongo, you won’t get any feedback about whether it worked, since most of the time we’re using this on systems so fast there isn’t time for niceties, but if you try to find() this record now, you won’t be able to.

MongoDB

There’s so much that’s exciting about mongo, the sheer size and speed of this data store, the support for map reduce, the sharding support … I could go on. However you still need to be able to have a quick word with your database and check what data it has, maybe tweak something, and I hope that these mongo examples will serve as a quick reference for anyone who needs them, including me of course! I like databases, APIs and command line, so working with mongo is kind of magical for me, are you working with it? I’d love to hear how others are getting on and what other tips I need to know, so leave a comment and share, please!

3 招实用Asset Pipeline 加速 –by Xdite

3 招实用Asset Pipeline 加速 —by xdite

Asset Pipeline 最让人诟病的就是deploy 时花费速度过久。 在社群聚会时发现大家都对这个主题非常不熟。 所以把最近累积了的这方面技巧整理出来分享给大家。

1. Capistrano deployment speedup

使用capistrano 内建task 执行assets:precompie

capistrano内建了‘deploy/assets’这个task。 只要在Capfile里面

 

Capfile
  1
 load 'deploy/assets'

 

deploy 就会自动执行assets precompile 的动作。 由原始档可以看到这个task实际执行的是

“cd /home/apps/APP_NAME/releases/20120708184757 && bundle exec rake RAILS_ENV=production RAILS_GROUPS=assets assets:precompile”

而执行的时机是

after ‘deploy:update_code’, ‘deploy:assets:precompile’

许多开发者不知道有这一个task 可以用。 手动写task 去compile,造成了两个问题:

  1. 时机执行错误。 Compile 时机错误会造成站上出现空白css。
  2. 执行compile 机器负担太重。 如果是手写的task 通常会是load 整个production 的环境去compile。与只load assets 这个group 所吃的系统资源「有可能」差得非常多。

如果没有变更到assets 时,就不compile

请把这里面的内容贴到你的deploy.rb 档里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# -*- encoding : utf-8 -*-
set :assets_dependencies, %w(app/assets lib/assets vendor/assets Gemfile.lock config/routes.rb)
namespace :deploy do
  namespace :assets do
    desc <<-DESC
      Run the asset precompilation rake task. You can specify the full path \
      to the rake executable by setting the rake variable. You can also \
      specify additional environment variables to pass to rake via the \
      asset_env variable. The defaults are:
        set :rake, “rake”
        set :rails_env, “production”
        set :asset_env, “RAILS_GROUPS=assets”
        set :assets_dependencies, fetch(:assets_dependencies) + %w(config/locales/js)
    DESC
    task :precompile, :roles => :web, :except => { :no_release => true } do
      from = source.next_revision(current_revision)
      if capture(“cd #{latest_release} && #{source.local.log(from)} #{assets_dependencies.join ’ ‘} | wc -l”).to_i > 0
        run %Q{cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:precompile}
      else
        logger.info “Skipping asset pre-compilation because there were no asset changes”
      end
    end
  end
end

这是在Railsconf 2012的Stack Smashing上学到的一招。

如果你的assets 档案没有变动的话,只要执行copy 上一版本的assets 就好了。 这段task 会侦测

  • app/assets
  • lib/assets
  • vendor/assets
  • Gemfile.lock
  • confir/routes.rb

是否有变动。 基本上已经含了所有可能assets 会变动的可能性。 有变动才会重新compile。

整体上会加速非常非常的多 。

2. use @import carefully

避免使用@import “compass”; 这种写法

compass是大家很爱用的SCSS framework。 大家写gradiant 或者css spriate 很常直接开下去。

但是你知道

 

  1
 @import "compass" ;

 

 

  1
 @import "compass/typography/links/link-colors" ;

 

这两种写法。

前者compile 的速度可能比后者慢到9 倍以上吗?

会这么慢的原因,是因为compass本身即是懒人包 , @import “compass”;会把

  • “compass/utilities”;
  • “compass/typography”;
  • “compass/css3”;

下面的东西通通都挂起来(还跑directory recursive)。

所以自然慢到爆炸。 如果要用什么helper,请直接挂它单支的CSS 就好了,不要整包都挂上来。

全挂其慢无比是正常的。

避免使用partial

我知道partial 是SCSS 整理术的大绝招。 但是若非必要,也尽量避免一直单档一路@import 到底。

 

common.css.scss
  1
 2
 3
 @import "reset" ; @import "base" ; @import "product" ;
common.css.scss
  1
 2
 3
 //= require "reset" //= require "base" //= require "product"

 

这两个在asset pipeline 输出结果是一样的。 但后者会比前者快。

如果真的需要用到非得使用partial 的技巧(如需读变数用require 读​​不到,@import 才读得到)再使用即可,因为只要一牵涉到directory recursive compile 就会慢…

3. don’t require .scss & .coffee for no reason

避免使用require_tree

使用generator 产生controller 时,rails 会自动帮忙产生

  • product.css.scss
  • product.js.coffee

然后application.css 与application.js 会利用

 

application.css
  1
 //= require_tree

 

这种技巧来把这些档案挂上去。

但是你知道吗? 就算这些档案里面只写了这几行注解:

 

  1
 2
 3
 # Place all the behaviors and hooks related to the matching controller here. # All this logic will automatically be available in application.js. # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

 

而且实际执行结果也等于空输出。 compile 一支大概也要250ms。 你可以想想,多compile 10 支,就是2.5 秒了。 难怪超耗时。

可以使用.js 或.css 解决的不要用.scss 与.coffee 当结尾

 

  1
 2
 3
 4
 5
 Compiled jquery-ui-1.8.16.custom.css (0ms) (pid 19108) Compiled jquery.ui.1.8.16.ie.css (0ms) (pid 19108) Compiled jquery.js (5ms) (pid 19108) Compiled jquery_ujs.js (0ms) (pid 19108) Compiled custom.css (14ms) (pid 19108)

 

其中custom.css 的档名是custom.css.scss

这样应该知道为什么不要乱用scss 当档名了吧?

小结

为了方便大家调整,我把具体加速assets precompile 过程的步骤罗列在下面。

1. 换掉deploy.rb 的assets precompile tasks

2. 观察logs/product.log。

  1. 找出慢的assets。
  2. 拿掉直接使用import “comppass”; 的SCSS,改用功能针对性写法。
  3. 不需要使用@import 写法的改用require
  4. 拿掉require_tree,改用//=require 一行一行挂上去
  5. 删掉空的scss 与coffeescript
  6. 单纯只是CSS 的不要自作聪明帮忙加上.scss 档名。

====

如果有什么问题,欢迎各位在底下留言讨论。

也欢迎大家有空来Rails Tuesday坐坐。 我很乐意帮大家解答问题。

PS如果你是要问Rails 101书上的问题,请找小蟹。

Creating Nested Resources in Ruby on Rails 3 and Updating Scaffolding Links and Redirection

Creating nested resources in ruby on rails 3 and updating scaffolding links and redirection

In this article, I’ll walk through a basic Rails (3.2.x) setup for creating a nested resource for two models. Nested resources work well when you want to build out URL structure between two related models, and still maintain a RESTful convention. This code assumes you are running RVM to manage Ruby/Gem versions, and Git for version control.

Creating a new Rails project $ mkdir family # create rvm gemset $ echo “rvm use —create ruby-1.9.2@family” > family/.rvmrc $ cd family # install rails $ gem install rails # create new rails project $ rails new . # version control $ git init $ git add . $ git commit -am “new rails project” Create two models (Parent & Child)

Parent model

$ rails generate scaffold Parent name:string $ git add . $ git commit -am “rails generate scaffold Parent name:string”

Child model

$ rails generate scaffold Child name:string parent_id:integer $ git add . $ git commit -am “rails generate scaffold Child name:string parent_id:integer”

Create db (defaults to SQLite3)

$ rake db:migrate

version control

$ git add db/schema.rb $ git commit db/schema.rb -m “created database schema” Review un-nested routes $ rake routes children GET /children(.:format) children#index

        POST   /children(.:format)          children#create

new_child GET /children/new(.:format) children#new edit_child GET /children/:id/edit(.:format) children#edit

  child GET    /children/:id(.:format)      children#show
        PUT    /children/:id(.:format)      children#update
        DELETE /children/:id(.:format)      children#destroy
parents GET    /parents(.:format)           parents#index
        POST   /parents(.:format)           parents#create

new_parent GET /parents/new(.:format) parents#new edit_parent GET /parents/:id/edit(.:format) parents#edit

 parent GET    /parents/:id(.:format)       parents#show
        PUT    /parents/:id(.:format)       parents#update
        DELETE /parents/:id(.:format)       parents#destroy

Adding model relationships

file: app/models/parent.rb

class Parent < ActiveRecord::Base attr_accessible :name has_many :children end

file: app/models/child.rb

class Child < ActiveRecord::Base attr_accessible :name, :parent_id belongs_to :parent end

version control

$ git commit app/models -m “added relationships to models” Nesting the routes $ rake routes parent_children GET /parents/:parent_id/children(.:format) children#index

              POST   /parents/:parent_id/children(.:format)          children#create

new_parent_child GET /parents/:parent_id/children/new(.:format) children#new edit_parent_child GET /parents/:parent_id/children/:id/edit(.:format) children#edit

 parent_child GET    /parents/:parent_id/children/:id(.:format)      children#show
              PUT    /parents/:parent_id/children/:id(.:format)      children#update
              DELETE /parents/:parent_id/children/:id(.:format)      children#destroy
      parents GET    /parents(.:format)                              parents#index
              POST   /parents(.:format)                              parents#create
   new_parent GET    /parents/new(.:format)                          parents#new
  edit_parent GET    /parents/:id/edit(.:format)                     parents#edit
       parent GET    /parents/:id(.:format)                          parents#show
              PUT    /parents/:id(.:format)                          parents#update
              DELETE /parents/:id(.:format)                          parents#destroy

Adding test data via Rails console $ rails c

dad = Parent.new(:name => ‘Paul’) => #

dad.save (0.1ms) begin transaction SQL (20.0ms) INSERT INTO “parents” (“created_at”, “name”, “updated_at”) VALUES (?, ?, ?) [[“created_at”, Fri, 06 Apr 2012 16:13:17 UTC +00:00], [“name”, “Paul”], [“updated_at”, Fri, 06 Apr 2012 16:13:17 UTC +00:00]] (2.4ms) commit transaction => true

son = dad.children.new(:name => ‘Eric’) => #

daughter = dad.children.new(:name => ‘Mara’) => #

exit Adding a private controller method to load the Parent object for each method

file: app/controllers/children_controller.rb

@@ -1,4 +1,7 @@ class ChildrenController < ApplicationController + + before_filter :load_parent + # GET /children # GET /children.json def index @@ -80,4 +83,11 @@ class ChildrenController < ApplicationController

   format.json { head :no_content }
 end

end + + private + + def load_parent + @parent = Parent.find(params[:parent_id]) + end + end At this point, each controller and view for the Child class model needs to be adjusted (links, redirection, form, etc)

Method: children#index

file: app/controllers/children_controller.rb

def index – @children = Child.all + @children = @parent.children.all

file: app/views/children/index.html.erb

  • <%= link_to ‘Show’, child %>
  • <%= link_to ‘Edit’, edit_child_path(child) %>
  • <%= link_to ‘Destroy’, child, confirm: ‘Are you sure?’, method: :delete %>
  • <%= link_to ‘Show’, parent_child_path(@parent, child) %>
  • <%= link_to ‘Edit’, edit_parent_child_path(@parent, child) %>
  • <%= link_to ‘Destroy’, [@parent, child], confirm: ‘Are you sure?’, method: :delete %>

–<%= link_to ‘New Child’, new_child_path %> +<%= link_to ‘New Child’, new_parent_child_path(@parent) %> Method: children#new

file: app/controllers/children_controller.rb

def new – @child = Child.new + @child = @parent.children.new

file: app/views/children/_form.html.erb

–<%= form_for(@child) do |f| %> +<%= form_for([@parent, @child]) do |f| %>

file: app/views/children/new.html.erb

–<%= link_to ‘Back’, children_path %> +<%= link_to ‘Back’, parent_children_path(@parent) %> Method: children#create

file: app/controllers/children_controller.rb

def create – @child = Child.new(params[:child]) + @child = @parent.children.new(params[:child])

 respond_to do |format|
   if @child.save
  •  format.html { redirect_to @child, notice: 'Child was successfully created.' }
    
  •  format.html { redirect_to [@parent, @child], notice: 'Child was successfully created.' }
    

    Method: children#show

file: app/controllers/children_controller.rb

def show – @child = Child.find(params[:id]) + @child = @parent.children.find(params[:id])

file: app/views/children/show.html.erb

–<%= link_to ‘Edit’, edit_child_path(@child) %> | –<%= link_to ‘Back’, children_path %> +<%= link_to ‘Edit’, edit_parent_child_path(@parent, @child) %> | +<%= link_to ‘Back’, parent_children_path(@parent) %> Method: children#edit

file: app/controllers/children_controller.rb

def edit – @child = Child.find(params[:id]) + @child = @parent.children.find(params[:id])

file: app/views/children/edit.html.erb

–<%= link_to ‘Show’, @child %> | –<%= link_to ‘Back’, children_path %> +<%= link_to ‘Show’, parent_child_path(@parent, @child) %> | +<%= link_to ‘Back’, parent_children_path(@parent) %> Method: children#update

file: app/controllers/children_controller.rb

def update – @child = Child.find(params[:id]) + @child = @parent.children.find(params[:id])

 respond_to do |format|
   if @child.update_attributes(params[:child])
  •  format.html { redirect_to @child, notice: 'Child was successfully updated.' }
    
  •  format.html { redirect_to [@parent, @child], notice: 'Child was successfully updated.' }
    

    Method: children#destroy

file: app/controllers/children_controller.rb

def destroy – @child = Child.find(params[:id]) + @child = @parent.children.find(params[:id])

 @child.destroy

 respond_to do |format|
  • format.html { redirect_to children_url }
  • format.html { redirect_to parent_children_path(@parent) } At this point, the default scaffolding’s links and redirection have been updated to work with the nested routes.

ActionDispatch::RequestId < Object

ActionDispatch::RequestId < Object

Makes a unique request id available to the action_dispatch.request_id env variable (which is then accessible through ActionDispatch::Request#uuid) and sends the same id to the client via the X-Request-Id header.

The unique request id is either based off the X-Request-Id header in the request, which would typically be generated by a firewall, load balancer, or the web server, or, if this header is not available, a random uuid. If the header is accepted from the outside world, we sanitize it to a max of 255 chars and alphanumeric and dashes only.

The unique request id can be used to trace a request end-to-end and would typically end up being part of log files from multiple pieces of the stack.

http://api.rubyonrails.org/classes/ActionDispatch/RequestId.html

http://stackoverflow.com/search?q=rails+RequestId

Single Table Inheritance (单表继承)

Single table inheritance (单表继承)

Active Record allows inheritance by storing the name of the class in a column that by default is named “type” (can be changed by overwriting Base.inheritance_column). This means that an inheritance looking like this:

class Company < ActiveRecord::Base; end
class Firm < Company; end
class Client < Company; end
class PriorityClient < Client; end

When you do Firm.create(:name => “37signals”), this record will be saved in the companies table with type = “Firm”. You can then fetch this row again using Company.where(:name => ‘37signals’).first and it will return a Firm object.

If you don’t have a type column defined in your table, single-table inheritance won’t be triggered. In that case, it’ll work just like normal subclasses with no special magic for differentiating between them or reloading the right type with find.

Note, all the attributes for all the cases are kept in the same table. Read more: www.martinfowler.com/eaaCatalog/singleTableInheritance.html

15 Things for a Ruby Beginner

15 Things for a Ruby Beginner

The following is a post I had recently sent the Bangalore Ruby User Group. It has been slightly modified to address a larger audience.

There were many Ruby beginners in last week’s meetup, and the common question we heard was ‘after the very basics, what next?’

The best way to learn Ruby best practices is to pair with an experienced dev; the way I learned was by inheriting a reasonably small, but well-written codebase from an amazing colleague. In the absence of either, here is a checklist of 15 things (since ‘N things that you need to know about X’ is the in-thing these days!) that I’d recommend a Ruby beginner to consider:

1. The very basics

Our very own rubymonk.com has a Ruby primer which was written for exactly this purpose; we open our inbox everyday to gushing feedback from people who’ve found it to be a great way to learn Ruby. Try it and let us know how it goes!

tryruby.org also has a basic introduction to Ruby, and has been around longer. Edgecase’s Ruby Koan is an interesting concept, and covers the language both in breadth and depth, and is a very strong recommendation. It should take you anywhere between 5-10 hours to finish all of the Koans. Do try it!

 

I have heard good things about Learn Ruby the Hardway, but haven’t tried it out myself. Okay, I just skimmed through portions of it and I’m not really happy – LRTH seems to be mostly a line-to-line translation of Python code to Ruby. It uses  ‘while’ loop in places where equivalent Ruby idioms (Enumerables) would have made more sense. Also there is no mention of blocks, metaprogramming and duck-typing, which pretty much is a deal-breaker for me. But to be fair, the target audience for LRTH seem to be non-programmers for whom the concept of loops and objects would be new, and for them it does the job very well.

Wait, have you read Why’s Poignant Guide to Ruby? If this is the first time you’re hearing about why the lucky stiff, read this amazing piece on why by the Smashing Magazine. And definitely read The Poignant Guide: http://mislav.uniqpath.com/poignant-guide/. It is full of cats, foxes, chunky bacon, cartoons that doesn’t always make much sense, space travel and what not. This was one of my first introductions to the Ruby community, and the guide lent the language and the community a fun, quirky and happy aura. You may or may not take away much Ruby knowledge from the guide – I couldn’t when I read it for the first time. However you’ll definitely understand some of the quirkiness and philosophies that influence the Ruby community. I’m a huge fan of why, and here is my favourite quote:

 

when you don’t create things, you become defined by your tastes rather than ability. your tastes only narrow & exclude people. so create.

 

2. The ecosystem - RVM/rbenv, RubyGems, Bundler, Git and Github

I think all of these tools are mandatory for being a productive Ruby programmer. You’ll encounter them soon enough:

  • RVM/rbenv: these are tools used to manage multiple Ruby versions on the same machine. I’ve been using RVM without complaint for quite a while, though there are people who will go up in arms against RVM for various reasons. As a beginner, you should be comfortable with either.

  • RubyGems: a gem for anything, a gem for everything. If you are using RVM, it will install RubyGems by default for you. http://docs.rubygems.org/read/chapter/4

  • Bundler: You’ll learn it easy enough if you are using Rails. But even for non-Rails projects, Bundler is now the de-facto tool to handle gems and dependencies. It is one of those tools that when you see for the first time you would wonder how you ever lived without it.

  • Git: You are a git if you don’t use git yet. If you are not even using any version control at all, good for you – there aren’t bad practices that you need to unlearn. If you are on SVN, or God forbid CVS, jump now.http://git-scm.com/book/en/Getting-Started-About-Version-Control

  • Github: You have a Github handle, right? ‘nuff said.

3. Editor

I don’t care. Pick one, use it well. If you’re on Vim and is on Insert mode all the time, then use Notepad instead. It would be more productive. Learn your editor.

Here is a list of editors/IDEs people generally use for Ruby development:

  • Sublime Text
  • Textmate
  • RubyMine (My favourite, but needs a lot of memory and CPU)
  • Vim
  • emacs
  • Aptana RadRails (recently saw a couple of people using it. don’t know how good it is)
  • Redcar (I’ve used it very occassionaly, am yet to see someone using it as a primary editor)

If you are using Sublime Text, install and use its corresponding Ruby package. Ditto for Textmate.

If you are on Vim, using the right set of plugins is a requisite to be productive. There is the popularhttps://github.com/carlhuda/janus and Srushti’s https://github.com/srushti/vim-get which I use when I work with Vim. Even if you don’t go for these plugin distributions, spend enough time to find the right plugins for Ruby development.

I don’t know about the best plugins for emacs, but there are people who use emacs to develop in Ruby. Even Matz uses emacs; search and you shall find.

4. Ditch ‘while’, ‘for’ and array accumulation

Read this: http://martinfowler.com/bliki/CollectionClosureMethod.html

An apparent sign of a programmer who does not Ruby well is code that uses ‘for’ and ‘while’ loops for iteration and accumulation. I’m hardpressed to remember occasions where I had to use them instead of the Enumerable methods #each, #map, #select, #inject, #reject and #detect. Learn these methods, chew on them, and use it everywhere!

(infinite loops are almost always written using the loop do..end construct though. but how often do you write infinite loops anyway?)

5. Hash

At the time when I started writing Ruby, the languages that I had written in for a reasonable period of time before were CA-Clipper, Borland Turbo C and some VB 6.

The first two did not have a hash, associative array or dictionary – whichever you prefer to call it. As to VB6, the only thing I can remember is DataGrid and ADODB. Ah, the failed promises of drag and drop programming!

So Hash was a revelation and I started using it anywhere and everywhere. Do you want to build a CRUD app to manage customer info? Forget databases, I’ll build a Hash and serialize to and deserialize from a YAML file. There were even more crimes committed using Hash that I dare not mention here. You would have gone through enough exercises that uses Hash when working through RubyMonk or Ruby Koans. But if you haven’t, make sure you understand Hashes well enough. Specifically:

  • iterating over a hash
  • assigning default values for undefined keys in a hash
  • Hash#keys and Hash#values for extracting just the keys and values
  • In Ruby 1.8 Hashes are un-ordered: ie, you can’t rely on the ordering of the hash to be same as the order in which you added elements. In Ruby 1.9, a Hash is sorted on the basis of order of insertion.

6. JSON and YAML

These are not Ruby specific concepts, but find great use in the ecosystem. Know them well, they’ll come in handy.

7. Understand Immutability and how Ruby passes object references around

This has slightly got to do with the above point – all the Enumerable methods are immutable, and it is a good introduction to how functional Ruby veer towards immutability.  Immutability is more of a good programming practice than a Ruby specific idea – it helps you write clean predictable code, leave aside concurrent programming and race conditions. A method that mutates its parameter is a vile creature, don’t bring it forth into existence.

If you come from a C programming background, building new objects willy-nilly would be a little hard to digest. So much memory put to waste! I remember reading somewhere that programmers who use high level languages leave a higher carbon footprint because their code is inefficient. I leave you to ponder over it.

For understanding some quirks around Ruby’s immutability and interesting effects of how Ruby passes object references around, figure out where Array#clone is used. I remember wasting many a debugger breakpoint during my early days of Ruby because I didn’t realize this. Don’t let that happen to you! Understand the difference between a shallow clone and a deep clone. Even better, go write your own deep_clone routine! (limit yourselves to objects that can have strings, numbers, arrays and hashes)

Also read: http://ruby-doc.org/docs/Newcomers/ruby.html#objects

8. Ruby’s Object Hierarchy

 

# All objects are instances of the class Object. 
"a string".is_a? BasicObject         # true

# All classes are instances of the class Class.
String.is_a? Class                   # true

# Class is a subclass of BasicObject.
Class.is_a? BasicObject              # true

# Class is not an instance of BasicObject
Class.instance_of? BasicObject       # false

# BasicObject is an instance and a sub-class of Class
BasicObject.is_a? Class              # true
BasicObject.instance_of? Class       # true

 

Okay, I lost it. It is pretty crazy: http://stackoverflow.com/questions/4967556/ruby-craziness-class-vs-object. As a beginner, you wouldn’t need to understand the nitty-gritties. I’ve been programming in Ruby for about three years now, and it still confuses the heck out of me.

For now it is safe to understand that BasicObject is usually the root object of all objects in Ruby. And everything in Ruby is an object. This has a very useful side-effect (try this in IRB):

"some random string".methods - Object.methods

Also,

Array.new.methods - Object.methods

 

The above commands will show you methods that are specific to just strings and arrays, excluding all methods that are always present in any Ruby object (inherited from Object -like instance_of, is_a? etc.).

Tip:You might have noticed that the ‘–’ operator gives you the difference between two arrays. Whenever you need a general purpose method and wonder whether Ruby comes with it, just try some plausible syntax in IRB. You might be surprised at what you find.

Even though Ruby lets you Object Oriented and procedural code, the language leans toward OO. Ruby treats even methods as objects:

"some string".method(:length) # gives you an object of the Method class.

The method object can be asked to run by invoking the ‘call’ method on it.

 

9. Creating your own Objects

Did you notice that the title wasn’t ‘Creating Classes’. That was one of the most useful advices I’ve ever received: Always think in terms of objects – not classes. Thinking in terms of Classes can subtly make you evolve your design upfront. Don’t. Let your objects guide you in how your class definition should look. As a rough analogy, when building a home, the blueprint is valuable only as a reference for building the actual home. You imagine what your home should look like and draw a blueprint accordingly, not the other way round.

Start with sparse classes, add methods and attributes as your objects demand it. Srushti puts it better: Imagine you’re an instance, and think about what you want to do and how you want to do it. You don’t want to give up your secrets (encapsulation). You don’t ask other people for information so you can do their work for them, you just tell them to do stuff for you (tell, don’t ask)

Ruby has a very simple syntax for defining classes and building objects. If you come from a Java/C# background, it’d be the first thing you look for. But even if you are a die-hard procedural ninja, trust me, thinking in terms of objects will help you write better programs, tackle complexity and be a more capable programmer.

So, what are the things that are specific to Ruby that you need to be aware of?

 

  • Message Passing. “abcd”.length is in fact “abcd”.send(:length).
  • Module vs Classes (hint: they’re very similar, but you can’t instantiate a Module)
  • Mixins (Ruby’s answer to multiple inheritance and the greatest thing before sliced bread)
  • attr_reader, attr_writer, attr_accessor.
  • instance methods and class methods
  • instance variables and class variables.

And we all know that you don’t use class variables unless you have a very good reason. Class methods aren’t that bad, but are usually a smell. Whenever you find yourselves writing a class method, take a step back and make sure it can’t be rephrased as an instance method, perhaps in a child object?

There is a lot more to OO, some less specific to Ruby. As you go deep into the rabbit hole, ponder over these blanket statements:

  • Primitives (Hash, Array etc.) are evil! Build objects.
  • Inheritance is evil! Use Composition.
  • Conditions (if..else, switch..case) are evil! Use Polymorphism.

10. Ruby is interpreted. It is malleable. Use that to your advantage.

Interpreted programs are almost always slower than native code (which includes JIT). By choosing to use such a language, you are accepting a compromise in the speed/efficiency of your programs. But this gives you a great advantage: the flexibility to change your code at runtime. Though we can’t claim ‘code is data, data is code’ like those hipster LISPers do, there is tremendous power in the dynamism (no reference to type systems) of Ruby. Learn it, use it, change the world!

I had briefly mentioned the ‘send’ method that is available for every object in Ruby:

   "abcd".send(:length)

is same as

   "abcd".length

That means you can do things like this:

 

puts "Hi, which method do you like to invoke on a string today?"
method_name = gets.strip
puts "a random string".send(method_name)

 

Did you see that? Unlike fully compiled languages like C/C++, Ruby lets you call arbitrary methods during runtime! (you can pass arguments to the method as parameters to the ‘send’ method)

Leave aside calling arbitrary methods, running arbitrary code during runtime is a breeze:

puts "What code do you want to run today, dear sir?"
arbitrary_code = STDIN.read         # press ctrl+d to stop input
eval(arbitrary_code)

Try it, type in some short valid Ruby code and see it in action.

 

Now that you know ‘eval’ exists, forget about it. It is too dangerous to be almost ever used. It is unsafe and unscoped, but there are better things to achieve similar and useful results. The point of this exercise though was to see Ruby’s dynamic nature in action. Since Ruby is interpreted, there is no limitation on what can be done during runtime. This can be used to great good as we will see in Metaprogramming.

11. Metaprogramming

Metaprogramming in Ruby more or less gives you ways to create/remove/redefine methods at runtime. If you have used Rails, you would have seen that you would write something like

class User < ActiveRecord::Base
end

and magically, the User class gives you methods like user.name, user.find_by_name, user.find_by_name_and_id. Depending on the fields in the database, Rails defines methods for you to use. This uses Metaprogramming where Rails defines the methods at runtime after consulting the table schema.

(talking about ‘magic’, usually when someone complain about ‘magic’ in Ruby code, she is most probably referring to some sort of metaprogramming in the code)

Metaprogramming is one of Ruby’s most powerful concepts (anything borrowed from FP is yummy!), but it is open to use and abuse. They say that someone who knows metaprogramming well enough, but not enough to know where not to use it, is a danger to himself and society. The internet is rife with discussions around it and you’ll find no shortage of flame wars, opinions and thankfully, documentation.

These are the methods you would want to look up to get a decent overview of metaprogramming in Ruby:

  • define_method
  • method_missing
  • instance_eval
  • class_eval

I would also recommend Yehuda Katz’s excellent explanation of Metaprogramming by relating it to the context of ‘self’: http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/

Metaprogramming is a bit advanced, and if you don’t understand all or any of it the first time, don’t worry. Come back and take a look again later. Rinse and repeat. It is an acquired taste, give it time!

12. Closures (Blocks, Lambdas et al.)

Blocks are my favourite. They move mountains. Rather, they let you write beautiful DSLs when coupled with the right dose of metaprogramming. Have you seen factory_girl’s syntax? It is an unholy mix of method_missing and ‘yield’.

Factory :user, aliases: [:author, :commenter] do first_name "John" last_name "Doe" date_of_birth { 18.years.ago } end

It is not really hard to build a DSL that reads like this, and there is no better resource to learn all of this than http://rubysource.com/functional-programming-techniques-with-ruby-part-ii/. The first part of that series looks into the functional and immutable aspects of Ruby, and is also a recommended read:http://rubysource.com/functional-programming-techniques-with-ruby-part-i/

13. Styleguides

Whenever you are in doubt, or the self becomes too much with you, go read the Ruby style guides.

Github’s simpler style guide: https://github.com/styleguide/ruby

The comprehensive one: https://github.com/bbatsov/ruby-style-guide

14. Simplicity is virtue

Knowing what constructs to use where is a matter of knowledge and experience. Every approach has trade-offs in terms of readability, maintainability and efficiency. The battle between these have been the recurring theme in the battles programmers fight in their heads for years. Knowing the the trade-offs will help you make more informed decisions, but it might not always be enough. Some things need to be tried, tested and failed, and that is fine.

But be vary of Premature Optimization. When you have a choice between clever, short and maybe faster code Vs longer but readable code, go for readability.  Ruby makes it easy to write really bad code that people would fear to touch with a long pole. It also lets you write  beautiful and concise code. When you contemplate between the two, remember the joke about the psychopath who’ll inherit your codebase, knows where you live, and pings you from your local network! The choice is yours.

15. None of this matters

If you are overwhelmed by this document or any links referenced from here, just ignore it. Remember the10,000 hours rule. Happily go about writing code the way you know best! And write a bit more code. Try to pair with someone who knows things a bit more. Go read some well-written Ruby code from Github. Then come back and see what you’ve learned.

None of this is rocket science, but it takes time and practice for concepts to sink in, and that is just fine.


Have further questions? There are tons of resource on the internet to answer your questions!

Join one of your local Ruby Usergroups. The Ruby community is extremely helpful and accomodating towards newbies. Check this page to locate a usergroup near you: How To Find Ruby User Groups

Participate in the usergroups, ask your questions. Also hop on to Ruby’s IRC channel #ruby-lang on Freenode. Irrespective of the forum, just make sure that you give enough context about your question to help others understand your problem. If you haven’t read ESR’s “Ask questions the smart way” yet, this is the time. Go read it now and get enlightened on the ways of the interwebs!

And remember to have fun! In Matz’s own words:

 ”For me the purpose of life is partly to have joy. Programmers often feel joy when they can concentrate on the creative side of programming, So Ruby is designed to make programmers happy.”

Happy hacking!

Using Resque to Send Mail for Devise

Using Resque to send mail for Devise

Since sending email synchronously is not a good idea, you’ll probably want to have Devise enqueuing it’s notification emails for background processing. Although Devise doesn’t support this out of the box you can achieve it easily by using the devise-async gem. To do so, first add it to your Gemfile:
gem "devise-async"
Then tell Devise to use the proxy mailer in config/initializers/devise.rb:
# Configure the class responsible to send e-mails.
config.mailer = "Devise::Async::Proxy"
And last but not least, set your queuing backend by creating config/initializers/devise_async.rb:
# Supported options: :resque, :sidekiq, :delayed_job
Devise::Async.backend = :resque
Your notification emails should now be gracefully enqueued for background processing.

 

#!/usr/bin/env rake

Add your own tasks in files placed in lib/tasks ending in .rake,

for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require File.expand_path(‘../config/application’, FILE) require ‘resque/tasks’

Askjane::Application.load_tasks

task “resque:setup” => :environment do ENV[‘QUEUE’] ||= ‘*’

for redistogo on heroku http://stackoverflow.com/questions/2611747/rails-resque-workers-fail-with-pgerror-server-closed-the-connection-unexpectedl

Resque.before_fork = Proc.new { ActiveRecord::Base.establish_connection } end

run below command

QUEUE=* rake environment resque:work