In order to run a consistent development environment across multiple machines it is necessary to use a virtual machine as the app’s server. This is just a operating system sandboxed within your own operating system (Ubuntu running inside of OSX in my case). Luckily VirtualBox provide a free solution for running virtual machines. You can download the latest version for your operating system here:
Follow the provided instructions for installing and then continue below.
Vagrant is a stellar piece of tech that allows for easy to setup, manage and copy interaction instructions for VirtualBox virtual machine. Basically by using Vagrant to setup your virtual machine you can make duplicates of said environment at the click of a button and then share it across all your computers and servers or with your colleagues and co-contributors. You will need to be familiar with using the command line to feel comfortable with vagrant. In any case even if this is all new to you simply copy the instructions I have provided word for word and everything should work as planned.
Now it’s time to download the correct version of Vagrant for your computer (OSX for me as I am doing this on a mac) and install it:
Once Vagrant has successfully installed it’s time to start setting up the development environment.
Setting Up Ubuntu
The team at Vagrant has kindly provided a few preconfigured Ubuntu images for use with Vagrant. You can find a full list here:
Select the one you would like to use from the list and make a note of it’s name (eg ‘ubuntu/trusty64’ or ‘hashicorp/precise64’).
Next, in the terminal, go to the folder where you wish to build your Rails app (for me it’s a folder called ‘Sites’ where I store all the files and assets of the apps that I work on) and type (be sure to replace hashicorp/precise32 with whatever box you chose from the list of available boxes):
$ vagrant init hashicorp/precise32
Once you have hit enter you will see that a
Vagrantfile was created in the folder inside which you typed the command in the terminal. Next we need to make sure that your app will be accessible on the localhost forwarding port
3000 as is the norm with Rails apps:
Vagrantfile in a text editor such as Sublime and insert the following at line 23:
config.vm.network "forwarded_port", guest: 3000, host: 3000
You will notice that there is another commented out line around line 23 that contains similar information but forwards to another port. You can safely remove this line from the
Vagrantfile. Once you have made the alterations save the file and exit the text editor.
Now it’s time to launch the virtual machine for the first time. Simply go to the terminal and type the following command:
$ vagrant up
The first time you run
vagrant up it will look for the operating system image that you have created the
Vagrantfile for and try launch the desired virtual machine. As you have not installed the virtual machine operating system yet it will then initiate the download and installation of the operating system first. In my case it will download and install Ubuntu 12.04 "Precise Pangolin" as my virtual machine operating system.
Let the download and installation proceed. Now would be a good time to make yourself a coffee or even have a bite to eat. Depending on your internet speed this process could take some time.
Working inside the virtual machine
Ok so your download is finished and the virtual machine is installed and up and running. In order to enter the virtual machine you can simply SSH in with the following command:
$ vagrant ssh
This command will enter you into the virtual machine as the user vagrant. This is very important to know for later when we setup the PostgreSQL database as we will use the vagrant user with no password to connect to the database from our Rails app.
Synced Folders between host OS and Virtual Machine OS
Once you have this setup you can work between the host OS and the virtual machine OS using the predesignated synced folder. The synced folder is the folder where the Vagrantfile is located (the same folder where your Rails app will reside). This is great as it means you can edit code in your host OS (OSX for me) and it will be readily accessible to be interpreted in your virtual machine. To access the synced folder inside the vagrant ssh session simply type the following in the ssh session terminal:
$ cd /vagrant
*NOTE: Unless otherwise stated the rest of the Terminal commands are always inside the SSH session that is logged into your virtual machine. This will install or otherwise manipulate the operating system in your virtual machine, leaving your host OS untouched. *
As you will be working in a team it is most likely you will be using Git as a distributed revision control system (and even if you aren't working in a team you should still be using Git or something similar). You will need to install this on the virtual machine. Inside the already running SSH session in the terminal type the following:
$ sudo apt-get $ updatesudo apt-get install git
Respond Yes or ‘Y’ to any prompts and that’s it, you should be good to go with Git.
First let’s setup the language and encoding defaults for the system which Postgres will use as it’s default setting too.
$ sudo /usr/sbin/update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
Next let’s install PostgreSQL:
$ sudo apt-get install postgresql libpq-dev
Once Postgres has successfully installed we will create a new database instance. Again within the SSH session:
$ sudo mkdir -p /usr/local/pgsql/datasudo $ chown postgres:postgres /usr/local/pgsql/datasudo su $ postgres/usr/lib/postgresql/9.1/bin/initdb -D $ /usr/local/pgsql/data
Now we have to create a admin user for the database. We will call this user vagrant because as mentioned previously it will simplify much of the connection issues between your Rails app and Postgres. The user called vagrant will not need to provide the Rails app database.yml file a password in order to connect to the database.
$ createuser vagrant
Type ‘Y’ and hit enter when asked “Shall the new role be a superuser?”
Now we can exit the su subshell to go back to the vagrant user SSH session:
Next we have to enter the Postgres console to add the user we just created as a verified user for the database instance and then quit out of Postgres console back to the vagrant user SSH session again.
$ psql postgres=> ALTER ROLE vagrant CREATEDB postgres=> \q
Testing Postgres is setup correctly
Now, back in the vagrant ssh session prompt we can login to the Postgres console as the
Postgres user to make the development and test databases for your app (please replace
<yourappname> with the actual name of the app you will build once you have your development environment setup correctly):
$ sudo su postgres $ psql postgres=# CREATE DATABASE <yourappname>_development postgres=# CREATE DATABASE <yourappname>_test postgres=# \list
\list command will list all databases. You should see the two databases you just created in this list. You can now close terminal tab and open a new terminal window and log back into the virtual machine using
Also popular for managing Ruby versions is rbenv but we will go with RVM for now. If you know what you are doing and prefer to use rbenv or another options please feel free to deviate from the tutorial for this section and once you have finished jump back in at the next section ‘Installing Bundler’.
Before installing RVM we need to install curl to help us with fetching files. Then we can install RVM and load it into our current environment.
$ sudo apt-get install curl\curl $ -sSL https://get.rvm.io | bash $ source /home/vagrant/.rvm/scripts/rvm
To test if RVM was successfully loaded type the following:
$ which rvm/home/vagrant/.rvm/bin/rvm
Next we need to install all the requirements for building Ruby. Luckily with RVM this is trivial (without RVM it would take a long time):
$ rvm requirements
Next we will install our desired version of Ruby (I’ll be going for Ruby 2.1 but you may want another one). We can see all the available versions of Ruby with this terminal command:
$ rvm list known
To install Ruby 2.1 I used the following command (you can substitute in any number for the version your wish to install):
$ rvm install 2.1
Wait awhile, while it compiles (tick tock tick tock… hmmm tea and biscuits) and then set the default Ruby version to the version you just installed:
$ rvm use 2.1 --default
You can verify the changes were made by typing the following into terminal (both commands should give you easily readable output that confirms the Ruby version set as default):
$ which ruby $ ruby -v
We are of course going to need Bundler installed in order to work with Rails gems.
$ gem install bundler
$ sudo apt-get install nodejs
And that’s it. We can move onto Rails!
Rails Installation Options
First we can check for the current version of Rails. Rails 4.1.8 was the stable release when this was written.
If you install Rails now you will install it into the global gemset but it’s considered best practice to make a gemset just for the current stable release (so you can use different versions for different projects). After creating our gemset we will set it to the default gemset.
$ rvm use email@example.com --create $ rvm use firstname.lastname@example.org --default
We’re then going to install most recent stable release of Rails:
$ gem install rails $ rails -v
The rails -v command is to confirm that the correct version was installed.
If you need to get a specific version of rails you can use the following tags (just substitute in the correct version number) with the install command:
$ gem install rails --version=2.1.1
Next we need to run bundle install to install missing dependencies.
$ bundle install
Finally we can create our new rails app. To show that the folder sync / sharing is working we will do this in our host OS (OSX for me). Open a new terminal window in your host OS and navigate to the folder where the
Vagrantfile was created. Now create a new rails app as you always would but make sure to add the database tag for Postgres.
$ rails new <yourappname> --database=postgresql
After your new app has been generated you can replace the
test contents of the config/database.yml file of the app with the following using your favourite text editor. Be sure to enter the names of the two databases you created earlier in the
development: adapter: postgresql database: <yourappname>_development encoding: utf8 pool: 5 timeout: 5000 test: adapter: postgresql database: <yourappname>_test encoding: utf8 pool: 5 timeout: 5000
If you left off the
--database=postgresql when you created the app replace gem ‘sqlite’ with gem ‘pg’ in the app's gemfile.
Now run bundle update in the vagrant ssh terminal session to install missing dependencies.
$ bundle update
You can now test the rails installation to make sure everything is working as it should. Still inside the vagrant ssh session, in the folder where the app resides:
$ cd /vagrant $ cd <yourappname> $ rails server
Now navigate to the local host in your host OS browser (Chrome in OSX for me) and you should see the Rails welcome page.
Congratulations you've got a great shareable development setup and ready to go!..... buuuuut there is one more step you need to know
Cloning your new setup on another machine
To share the virtual machine you have just created you need to back it up by creating an image of it.
In the same folder as the
$ vagrant package
This will shut down the VM and export an image named package.box (this will come in at about 700mb).
With this image you can now install it on any other machine that has Virtual Box and Vagrant installed.
On your new machine where you want to install the box all you have to do is (in the folder where the package.box is installed...probably a flash drive, Dropbox folder or wherever you stored the package.box file):
$ vagrant box add package.box --name <yourappname>_box
Next navigate (in the terminal of the new machine still) to the directory where your app will live and type:
$ vagrant init <yourappname>_box $ vagrant up
Boooooom! All you need to do is
vagrant ssh into the virtual machine and you’ve got the exact same environment as in your other computer. This will work across any machine so if you’ve got a Github repository for an app that you want others to work on stick a download link to the box in the Readme along with the instructions in this section and you will be laughing!