Using Vim as a Complete Ruby on Rails IDE

vi traced with an optical mouse

NOTE: If you are experiencing segmentation faults with vim and rails.vim, see this post.

When coding in Ruby on Rails, you’ll usually be switching between files and running scripts a lot. It can be time-consuming and frustrating coding Rails using a traditional text editor designed for working on big files individually. Vim lets you hop around within a file with enough speed to activate the cosmic treadmill – but without a plethora of hacks and custom key mappings, it’s weak as a Rails IDE. Fortunately, for those of us who are reluctant to kick the vim habit, Tim Pope comes to the rescue with rails.vim; A plugin that makes working with Rails in vim painless and efficient. In this guide, I will explain how to install and use rails.vim, along with a few other plugins you’ll find useful when writing Rails applications.

Vim would certainly fail the mom test, and it’s not something you can learn in one sitting. Learning vim is a lifelong process, and there are many sites and books that go over it extensively, therefore I won’t do that here. This guide assumes that you at least know what vim is and can open, edit and save files. Rails.vim works for vim, gvim and Cream, so vim in this article is referring to any of these three, unless otherwise stated.

For those who prefer Emacs, check out Effective Emacs by Steve Yegge and the official Wiki’s HowTouseEmacsWithRails.

Configuring vim/gvim
Rails.vim and Other Helpful Plugins
Usage and Examples
    Starting a New Project and Setting Up The Database
        Database.yml Setup
    Generating Models
    Migrations and :Rake
        :Rmigration pattern
        Related Files and The Command :R and its Mapping ]f
    A Glimpse of the Vim Database Extension Plugin
    Controllers, Views and Interfile Navigation
        :R or ]f
        :Rview [[controller/]view]
        :Rfind [name]
        gf ("goto file")
    Views and Partials
    We've Got You Surrounded
        Adding Surroundings
        Replacing Surroundings
        Removing Surroundings
        Rails.vim and Custom Surroundings
But Wait, There's More

Configuring Vim/gvim

Open your vim configuration file or create one if it doesn’t exist (i.e., new installation):

  • $HOME/.vimrc in Linux and Mac OS X (might be ~/.gvimrc instead)
  • $HOME\_vimrc (or $HOME\_gvimrc) in Windows

If you’re having trouble finding out where the config file goes, type “:version” and hit enter in vim for a list of compile flags, options and directories vim is using.

Add the following to the file and save it (if you must worry about what they do, see the vimdoc)

filetype on  " Automatically detect file types.
set nocompatible  " We don't want vi compatibility.

" Add recently accessed projects menu (project plugin)
set viminfo^=!

" Minibuffer Explorer Settings
let g:miniBufExplMapWindowNavVim = 1
let g:miniBufExplMapWindowNavArrows = 1
let g:miniBufExplMapCTabSwitchBufs = 1
let g:miniBufExplModSelTarget = 1

" alt+n or alt+p to navigate between entries in QuickFix
map   :cp 
map   :cn 

" Change which file opens after executing :Rails command
let g:rails_default_file='config/database.yml'

syntax enable

Before installing rails.vim, you may want to glance over some additional (g)vim options I use. Otherwise, skip this optional step and jump directly to the installation.

The following settings in my config are worth looking over. These can be appended to the same vimrc file as above:

set cf  " Enable error files & error jumping.
set clipboard+=unnamed  " Yanks go on clipboard instead.
set history=256  " Number of things to remember in history.
set autowrite  " Writes on make/shell commands
set ruler  " Ruler on
set nu  " Line numbers on
set nowrap  " Line wrapping off
set timeoutlen=250  " Time to wait after ESC (default causes an annoying delay)
" colorscheme vividchalk  " Uncomment this to set a default theme

" Formatting (some of these are for coding in C and C++)
set ts=2  " Tabs are 2 spaces
set bs=2  " Backspace over everything in insert mode
set shiftwidth=2  " Tabs under smart indent
set nocp incsearch
set cinoptions=:0,p0,t0
set cinwords=if,else,while,do,for,switch,case
set formatoptions=tcqr
set cindent
set autoindent
set smarttab
set expandtab

" Visual
set showmatch  " Show matching brackets.
set mat=5  " Bracket blinking.
set list
" Show $ at end of line and trailing space as ~
set lcs=tab:\ \ ,eol:$,trail:~,extends:>,precedes:<
set novisualbell  " No blinking .
set noerrorbells  " No noise.
set laststatus=2  " Always show status line.

" gvim specific
set mousehide  " Hide mouse after chars typed
set mouse=a  " Mouse in all modes

The following optional commands are helpful but require explicit creation of directories and files:

" Backups & Files
set backup                     " Enable creation of backup file.
set backupdir=~/.vim/backups " Where backups will go.
set directory=~/.vim/tmp     " Where temporary files will go.

Run vim to make sure it doesn't halt to display any warnings or error messages. If it does, check that the specific folders (~/.vim/skeletons and ~/.vim/backups etc) exist and vim has write permission on them.

Rails.vim and Other Helpful Plugins

Installing vim plugins just requires putting files where they belong in vim's root directory. We will be installing rails.vim along with some dependency plugins and a few others that make coding Rails in vim much simpler.

Below is a list of all the plugins you need to download and install. If they are .vim files, move them into your plugin folder, probably $HOME/.vim/plugin or $VIM\vimfiles\plugin (probably C:\vim\vimfiles\plugin). Doc files (.txt) go in $HOME/.vim/doc or vimfiles\doc\. Do the same with the contents of compressed files after you've extracted them. Again, if you're having trouble locating where these files should go, type ":version" in vim and hit enter.

  • rails.vim: This is the magic. The file contains plugin/rails.vim and doc/rails.txt. Both should be moved into their proper location in your root vim directory ($VIM).
  • Project: This adds a list of frequently used files to the lefthand side of vim. Rails.vim utilizes this script to create a directory tree of your Rails application. You're probably familiar with this feature already, as is a basic feature of most modern IDEs.
  • genutils 1.20 (NOT 2.x): Adds many useful functions
  • multvals.vim: genutils depends on this.
  • minibufexpl.vim: This adds (ugly, but functional) tabs to vim, making it much easier to keep track of the many files you'll be working on simultaneously.
  • dbext.vim: Adds database support to vim. This integrates seemlessly with rails.vim. More on it below.
  • surround: Surround.vim adds mappings to let you easily work with "surroundings" in pairs. Such as { }, " " and < >. More on it below.

To get the help files working, Rails needs to generate help tags from the txt files you placed in the doc directory. Open vim and in normal (command) mode type the following and hit enter:
Linux: :helptags $HOME/.vim/doc
Windows: :helptags $VIM\vimfiles\doc

Your directory might differ from the above. In which case, again, check ":version"

Make sure it worked:

:help rails

For more information on vim's help feature, use :help help or read about it in your browser. For help about a specific command, use :help command. Command can be a vim, rails.vim or other plugin command. For example :help rails or :help rgenerate.

Usage and Examples

Usage might seem intimidating at first because the plugins have-on top of vim's already rich set of functions-added so much more functionality and commands to memorize, but you'll quickly realize that getting used to rails.vim is easy due to the natural command names (and tab completion). Let's begin by creating a dummy rails project.

Starting a New Project and Setting Up The Database

In Cream or gvim, you can create projects using the menu Plugin -> Rails -> Projects -> New. Alternatively, you can use the :Rails command in normal mode. Both the menu option and the :Rails command are wrappers for the native rails application, making it possible to pass them what you would normally pass rails in the console.

If you do not specify an absolute path when passing :Rails your project name, the rails application will be generated in the current working directory, usually the directory you were in when you started vim.

Let's create a new framework named dummy. This command is typed in vim while in command mode (not the mode you type content in) and followed with the Enter key. Change /tmp/ to where ever you want this to reside (I.e., C:\Windows\Temp\):

:Rails /tmp/dummy

Database.yml Setup
The usual rails output will scroll across the screen and you will be dumped at the default file you specified in the vimrc file (g:rails_default_file). This will be README by default. If you haven't changed it to database.yml like in my config above, you can jump to the database config file by typing :Rfind database.yml.

Put your database information under dummy_development and save as usual (:w). Now creating our dummy_development database is as easy as one short command:


(You can use a database frontend (like the excellent PHPMyAdmin) or the mysql command in a console to create your dummy_development database if you did not install dbext.)

Note: This issues a CREATE DATABASE command on the Rails environment in $RAILS_ENV, which is development by default, but you can have it create the test and production environments as well:

:Rdbext! test
:Rdbext! production

The last loaded environment configuration is what will be used throughout the Rails application. To change the environment, just provide the desired one as a parameter to the :Rdbext command (notice lack of bang: !). If you've created three environments and want to switch to the test environment:

:Rdbext test

This commands opens up a Results tab and displays the results on the bottom of the screen in a new window. Sometimes, this window can be intrusive and downright annoying. To close it, click it and hit ctrl+w, let go of both and quickly hit c.

For more information, check :help Rdbext. More on DBExt later.

Generating Models

If you wish to run something in the application's script directory, you can use :Rscript:

:Rscript about
:Rscript console
:Rscript breakpointer

but you will probably never need to, as Rails.vim provides wrappers for most of Rails' scripts and functions. The names of these will usually be :R followed by the name of the script. For example, :Rgenerate, :Rserver, :Rconsole, etcetra...

:Rgenerate takes the same parameters as Rails' generate script. Let's generate a model named Thing:

:Rgenerate model Thing

The model file is automatically loaded and given focus after its creation. Notice that you can still access database.yml via its tab on top of the vim window. Double click a tab to open it, and click it once to give it focus, then hit d to close it. Try that now on database.yml (and Results if it's still open). More on tabs and the minibufexpl later.

Migrations and :Rake

Let's edit the model's migration file, which is created automatically for each generated model. You have a number of choices for jumping to this file:

:Rmigration pattern
The optional pattern can be any part of the migration's filename (in this case, 001_create_things.rb). You can use things (notice it's plural) because it matches the filename:

:Rmigration things

The migration number with or without the zeros. All three examples open the same migration:

:Rmigration 1
:Rmigration 01
:Rmigration 001

or any string of characters that match part of that migration's filename without causing an ambiguity, like 001_create_things.rb:

:Rmigration te_t

Rmigration is context aware. It will default to opening the related migration file if executed without a parameter while the model file is open:


More on related files below.

Related files and the command :R and its mapping ]f
The :R command or its mapping ]f open up the related file of whatever is currently open. A related file is something that is usually associated with the file you are opening. This is a construct in rails.vim, and that's where the rules are defined. For example, a model's related file is its migration. Even though both can be independent (you can have migrations without models and vice versa). Don't think about this too much.

Below is an excerpt from :help rails-related. It shows a list of what file will be open when :R is issued while the Current File is open:

Current File            Related File
model            related migration
controller (in method)    template (view)
template (view)            controller (jump to method)
migration            next migration
config/routes.rb        config/environment.rb

Open the migration file and add the following to the create_table block in the self.up method:

t.column :description, :text
t.column :weight, :integer

After writing your self.up, you can use :Rinvert to have self.down automatically generated. You don't have to do this here because self.down is already filled in (drop_table), but let's try it anyway by creating a test table called "test" and using :Rinvert to update self.down. Your self.up should now look like this:

  def self.up
    create_table :things do |t|
      t.column :description, :text
      t.column :weight, :integer
    create_table :test do |t|
      t.column :hi

and after running :Rinvert, your self.down will be:

  def self.down
    drop_table :test
    drop_table :things

:Rinvert works great for most commands, even some complex queries, but it can't reverse everything. A low level SQL query or a blank self.up might produce an IrreversableMigration error. Let's apply our migration to the database by running :Rake. It defaults to db:migrate when run in the context of our migration file.


A Glimpse of the Vim Database Extension Plugin

DBExt is powerful and deserves its own paper, but before getting derailed from our main topic, here are some useful DBExt commands:

:DBDescribeTable table outputs a table's columns and their data types. Run it now on the things table:

:DBDescribeTable things

Connection: T(MYSQL)  D(bic_development)  U(username)
Field    Type    Null    Key        Default        Extra
id    int(11)    NO        PRI        NULL        auto_increment
description    text    YES        NULL
weight    int(11)    YES        NULL

:DBExecSQL query executes low level SQL queries that are either under the cursor, or passed as parameters. Let's use it to populate our table:

:DBExecSQL INSERT INTO things VALUES (1, 'Worlds fattest man', 1200);
:DBExecSQL INSERT INTO things VALUES (2, 'Four quarter pounders', 1);

Let's view the contents of the things table:

:DBSelectFromTable things

If the results window on the bottom gets stuck, click it and then hit ctrl+w the c to close it.

Read the extensive help file using :help DBExt.

Let's create a controller and a skeleton for a method named index:

:Rgenerate controller Things index

We want to display all the records from our Thing table in our index view. Let's add some code this controller's index method:

def index
    @people = Thing.find(:all)

For test purposes later, add the following method to ThingsController, under the index method:

def viewless
    @cast = "Cloud Strife"

Since we passed a method name (index) to :Rgenerate, Rails has automatically generated a view for that method. We have a number of ways to navigate to that view:

:R or ]f
The Related command was discussed above under Migrations and :Rake. A controller can have many views, so :R looks at the current method the cursor resides in to look up what view to open. Place the cursor anywhere in the index method and type :R (or hit ]f) to open up index.rhtml.

This command only works if the related file exists. If the view doesn't exist, you'll get an "E345: Can't find file ... in path" error. Try this by putting the cursor on the viewless method before running the :R command again.

You can use :RS to split (what the S stands for) the current window into two, allowing you to view and edit both the controller and view simultaneously.

:Rview [[controller/]view]
Typed with no arguments, this command behaves the same as :R. If that view doesn't exist, you can specify a name, either by the full path or just the view name and extension, and that view will be created.

For example, let's create a view on the fly for the viewless method (extension is mandatory):

:Rview viewless.rhtml

We haven't defined a controller above, so by default, :Rview assumes it is for the current controller. It will go into app/views/things/. We could specify a controller by using :Rview controller/view_name.extension.

Note that the file is only generated in memory and must be saved to disk explicitly (:w).

Alternating between files

A lot of times, you'll be working exclusively on two files, back and forth. To alternate between the current file and the last file you were editing, use CTRL+^ (although in practice, you're actually just hitting CTRL+6).

Rails.vim also has an alternate command (:A or the [f mapping), similar in function to related. It usually takes you to the current file's test file.

From :help rails-alternate, this tells you what the alternate file will be for the Current File open:

Current file      Alternate file
model                               unit test
controller (in method)    functional test
template (view)              helper
migration                         previous migration
config/routes.rb               config/database.yml

:Rfind [name]
Like vim's :find command, this one also opens a file it finds either by the name you pass it or by whatever is under the cursor (behaves similarly to gf, more on that below). Rails.vim enhances the native command by giving it the ability to find files by controller and model name.

This opens the Thing model:

:Rfind thing

This opens the Things controller (case sensitive):

:Rfind ThingsController

This opens the index.rhtml view (you must be in the ThingsController):

:Rfind index

gf ("goto file")
In rails.vim, the gf mapping is used to jump to a file under the cursor taking context into account. The following is from :help rails-gf:
Example uses of gf, and where they might lead. (* indicates cursor position)

has_many :c*omments

link_to "Home", :controller => :bl*og

<%= render :partial => 'sh*ared/sidebar' %>

<%= stylesheet_link_tag :scaf*fold %>

class BlogController < Applica*tionController

class ApplicationController < ActionCont*roller::Base

fixtures :pos*ts

layout :pri*nt

# In the Blog controller
def li*st

<%= link_to "New", new_comme*nt_path %>
app/controllers/comments_controller.rb (jumps to def new)

In the last example, the controller and action for the named route are determined by evaluating routes.rb as Ruby and doing some introspection. This means code from the application is executed. Keep this in mind when navigating unfamiliar applications.

Add the following to the index.rhtml view file, overwriting the default code already in there:

All the things in our Thing table

<h1>All the things in our Thing table</h1>
    <% @stuff.each do |x| %>
  1. <%= x.description %> (weight: <%= x.weight %> pound(s))
  2. <% end %>

Views and Partials

The :Rextract command (:Rpartial is deprecated) makes creating partials a breeze. You choose a range of lines and supply the command a name you want for the new partial. The lines get replaced by a call to render the newly created partial, which now holds the lines that were extracted.

Let's try using this by delegating output code between the <li> and </li> tags in our index.rhtml view into a partial named "ppp" by explicitly defining the line numbers (your line numbers might not match. Alter it accordingly):

:5,5Rextract ppp

A new partial with the filename _ppp.rhtml is created containing line #5 from our index.rhtml view. Line #5 now is a call to render the newly created ppp view: <%= render :partial => 'ppp' %> - The new partial only exists in memory at this point, and must be saved to disk explicitly.

This could also have been done in visual mode, selecting the lines we want extracted visually instead of by line numbers. Place the cursor at the beginning of the line, press v to enter visual mode and hit '$' (shift+4) to jump to the end of the line, selecting the entire line along the way. Now hit : and type :Rextract ppp (it will come out as :'<,'>Rextract ppp) and hit enter. Same effect as above.

We've Got You Surrounded

Whether you're coding, writing, or editing, Tim Pope's surround plugin is very useful. It adds vim mappings to add, remove or edit "surroundings." A surrounding is a pair of parentheses, brackets, quotes, tags, etc.

Some mappings require that you press the first few keystrokes within a second. For full functionality, make sure you're using vim 7 or greater. Let's begin by making sure the plugin is installed and works properly by testing a command:

Type (hello world) into vim, and with your cursor anywhere in that phrase, hit ds(. If (hello world) turns to hello world, the plugin is working fine. If not, then make sure you're installed it correctly and are using Vim 7.0.

* The keystrokes need to be typed in succession very fast. The timeoutlen setting in the vim config file can impair the ys* functions. The smaller the value for timeoutlen, the less time you have in between keystrokes to ensure vim catches the command. I set timeoutlen to 200, but put 250 as the value in the example vimrc at the beginning of this tutorial. Delete this setting or use a higher value (300+) if you're having trouble using commands like yssa or yss.

* b, B, r, and a are aliases for ), }, ], and > respectively, and t represents a pair of HTML or XML tags.

* In the examples below, the cursor position is represented by an asterisk (*).

Adding Surroundings
You can add a pair of surroundings around a word, line, sentence, paragraph or a specific number of characters.

Adding quotes around a word:
Old text | Command | Result
H*eya world | ysiw" | "Heya" world

Adding a pair of tags around a word:
Old text | Command | Result
I*talic text | ysiw<i> | <i>Italic</i> text

Adding arrows around a sentence:
Old text | Command | Result
Clandestin*e operation | yssa | <Clandestine operation>

An angry Kenny face:
Old text | Command | Result
*>< | yss)yss)yss( | ( ((><)) )
(notice usage of parantheses in the command. Using the opening bracket adds spaces between the target being surrounded.)

Replacing Surroundings
Replacing parentheses with quotes in a word:
Old text | Command | Result
(qu*ack) quack | cs(" | "quack" quack

Changing those double quotes to a pair of tags:
Old text | Command | Result
"q*uack" quack | cs" | quack quack

Changing those tags to brackets:
Old text | Command | Result
<qqqqq>q*uack</qqqqq> quack | cstr | [quack] quack

Removing Surroundings
Remove quotes around a word:
Old text | Command | Result
Hash "eater*" | ds" | Hash eater

Remove tags around a word:
Old text | Command | Result
<h1>h*ead</h1> | dst | head

Removing multiple surroundings around a sentence:
Old text | Command | Result
{"(iiight)"} | ds(ds"dsB | iiight

Rails.vim and Custom Surroundings
Rails.vim makes use of the surround plugin by adding a few useful surroundings. These only work when rails.vim is enabled (when RoR projects are open):

Old text | Command | Result
*end | yss= | <%= end %>

Old text | Command | Result
*end | yss- | <%= end -%>

Old text | Command | Result
*cat | yss# | <%# cat %>

You can create custom surroundings. Here's one example:
:let g:surround_65 = "<a href=\"\"> \r </a>"

65 is the ASCII decimal for the 'A' character. You can use an ascii table to find the decimal corresponding to the character you want to use.

Old text | Command | Result
I*Shot The Sheriff | yssA | <a href=""> I Shot The Sheriff </a>

Be sure to read the extensive help files :help surround and :help rails-surround. They provide details and examples.

But Wait, There's More

We've merely scratched the surface of rails.vim here. Be sure to check out the Official rails.vim Website, the author's site, and the external links I provided below. For those looking for a more user-friendly, "real" GUI-based (as opposed to a TUI) IDE based around vim, try out VimMate.

36 thoughts on “Using Vim as a Complete Ruby on Rails IDE”

  1. I, too, enjoy Vim as a complete Ruby on Rails IDE.

    In addition to the excellent rails.vim plugin, I would also recommended the Rubytest.vim plugin, Exuberant Ctags, the ack.vim plugin with the ack utility, the NERD Tree plugin, and the FuzzyFinder plugin. I go over these with setup tips, links, and screencasts in a blog article:

  2. Hi,

    What are the best dedicated server web hosting company?

    I’m trying to set up a web site for my supervisor.

    appreciate your feedback,


  3. Hi,

    I have been using Emacs for the most part of last 4-5 years. lately I decided to try vim for RoR development and this stuff is great! It works “out of the box”, it’s fast, and I must say that I really enjoy using “:” + commands much more then M-x + commands.

    Thank you for this article – it made things much simpler for me.


  4. Hi all, it’s a job offer. (Sorry if I post it in wrong place)

    Cyprus company is seeking a Campaign Executive to assist with fundraising, presentations, various administrative and sales management duties. If you have fundraising and sales experience, plus intermediate computer knowledge, this job is for you! Apply with us today!

    All applicants applying for U.S. job openings must be authorized to work in the United States. All applicants applying for European job openings must be authorized to work in European Union.

    We are growing advertising and consulting company offering job opportunities ranging from executive and administrative assistants to customer service representatives, receptionists and general support.

    NOTICE: we do not provide relocation, this position is online based, we are using progressive online administrative system. You will have to use a special online training program for free.

    Requirements and skills:
    1. Higher Education/College
    2. 1 + Sales/Management (desired but optional)
    3. Strong communicative skills
    4. Must have MS Office installed (MS Word)
    5. Must have citizenship or Work Permit
    6. Adult age

    Education and Experience:
    1. Internet/MS Office/Outlook
    2. Sales/Management/Marketing courses (desired)

    Mon-Fri; 9:30am – 12:30pm

    Apply for this job now or contact our online branch support for additional information:

    CV to e-mail

  5. Thanks, dotkam!

    I noticed this when I switched to Ubuntu. I’ve added a link to your post in the article.

    Speaking of which, article needs to be updated to account for some changes in Rails 2.1. (Migrations are no longer named incrementally for example, they’re timestamped). Updates throughout the site will happen when I get time this week.

  6. Hey!…I Googled for sing down the moon by scott o dell, but found your page about nnial 2007 – salvatore iaconesi – poetry…and have to say thanks. nice read.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>