Thank you for following this series, this will be the last part of the series where we actually bring our development app to our remote server. Learning Rails has been a tremendous journey for me, the learning curve is not steep at all and it allows me to experiment and also to learn how to set up my own server to house it. Thanks to all the people that wrote tutorials and made railscasts out there I have learnt so much but this is just the beginning. This would not have been possible if I wasn’t introduced to the language itself by the_empty from webdevrefinery.

Deploying Rails to Centos 5

Right, before deploying with Capistrano we should make sure our application is fully prepared for deployment. The first thing we should do is strengthen our local’s .gitignore file. It should have the following lines :

log/*.log
*.log
tmp/**/*
tmp/*
doc/api
doc/app
config/database.yml.sample

Next, we should rename the database.yml file so that it doesn’t clash with other developer’s copy since they might differ from yours. Renaming it to database.yml.sample ensures that the production’s copy remain intact and the file doesnt clashes with other developers on your team. There is a great post by Simone Carletti about this issue that you should definitely check out.

You should also make sure that you have a root path pointing to some controller, meaning your index page should be properly routed and the public folder’s index.html is removed.

If you are on a shared host, you should mind your gems cuz they might upgrade their pack of gems without notifying you. To prevent anything from breaking you should unpack each gem to the vendor folder.

local $ cd vendor
local $ gem unpack money

To enable the gems to have version control, you just need to copy the contents of the lib folder to vendor

$ cp -R money-1.5.9/lib/* .
$ cp money-1.5.9/MIT-LICENSE LICENSE-money
$ rm -Rf money-1.5.9/
$ ls

Make sure you copy in the license depending on the gem’s license agreements.

In the future when you have upgraded your gems you can follow the same procedure again :

$ gem unpack money
Unpacked gem: 'money-1.7.1'
$ cp -Rf money-1.7.1/lib/* .
$ cp -f money-1.7.1/MIT-LICENSE LICENSE-money
$ rm -Rf money-1.7.1 

Remember to update your database.yml file to include your remote server’s database for the production database and make sure that it is using the mysql2 for the production database.

There are also some things you can tighten up when it comes to security. You can read more about it in this book. Important things to note are the following:

  • Never evaluate user input
  • Never evaluate SQL input

One last thing to check is to make sure you have eager associations for all your active records so that you can have the best optimal database performance.

If your remote server is using mySQL but your local machine is running SQLite for your app, you might also want a copy of the mySQL gem in your local machine.

gem install mysql2

Remember to include all this in the Gemfile

group :development, :test do
gem 'sqlite3-ruby', '1.2.5', :require => 'sqlite3'
end
group :production do
gem 'mysql2'
end

Run one last time after you are done.

 bundle install

When you are done, remember to push your changes up to the gitosis server.

 git commit -am "for deploy"
git push origin master

Alright. Capistrano. Yay!

First thing to do is to install Capistrano locally in your development machine. Capistrano only runs in the local machine and it uses SSH or SFTP to connect to your remote server. You do not need to install Capistrano in your remote server.

 local $ gem install capistrano

Check if it is working by doing :

 cap

If it shows you an error of not being able to find your Ruby Gems, then you need to install the <code>echoe</code> gem.

gem install echoe

Then you can see a list of capistrano tasks.

 cap -T

Now that it’s installed and working we can start. ๐Ÿ™‚ Finally. CD into your working directory.

 capify .

Remember the dot after capify.

This will create a <code>Capify</code> file in your working directory and a deploy.rb in your config folder. To deploy, we just need to ammed the deploy.rb file.

require 'bundler/capistrano'
set :application, "demoappname"
set :deploy_to,  "/home/#{application}"

server "yourdomain.com", :app, :web, :db, :primary => true

default_run_options[:ptr] = true # Ensure password prompt is prompt true
set :repository, 'git@yourdomain.com:demoappname.git' # your private/public url and user

set :scm, 'git' #scm utility name
set :branch, 'master' #remote branch to push
set :deploy_via, :copy # If you have public like github.com then use :remote_cache
set :user, 'root'
set :admin_runner, 'root'
#set :use_sudo, false #to avoid tty error

And also add the following lines for Passenger to work.

 namespace :deploy do
desc 'Restart Application'
task :restart, :roles => :app do
run "#{current_path}/tmp/restart.txt" #tells passenger to restart app
end
desc 'Start Application -- not needed for Passenger'
task :start, :roles => :app do
#empty since using passenger
end
end

Now you can prepare your server for deployment.

cap deploy:setup

You may need to enter your password and if you get a tty error just uncomment this line from yourdeploy.rb

set :use_sudo, false #to avoid tty error

If all goes well, your application directory in your remote server should have 2 new folders, releases and current Now, go back and edit your apache config file in your remote server in the VirtualHosts chunk section. This is your current chunk

DocumentRoot /home/demoapp/public

Change it to this and you should be all set to go after you restart your apache server. ๐Ÿ™‚

DocumentRoot /home/demoapp/current/public

Check your deployment dependencies.

cap deploy:check

Ok. Time for deployment. For the first deployment, you can do this.

cap deploy:update

Now, errors may pop up now an then.. for my first deploy, I spent the whole night figuring out what I did wrong only to realize I forgot to push my app to gitosis first. lol.

Another error would be the bundle install error where they say that I changed my Gemfile without adding Gemfile.lock to git. Hmm. I couldn’t fix it but a fresh deploy on an empty folder fixed it. I cleared out my demo app and deleted the demoapp folder.

After that, ssh into your remote server and CD into your app’s directory.

rake RAILS_ENV=production db:schema:load

This will create all the nessecary tables for your application. The reason why the deployment is separated into this 2 steps, update and rake is to enable you to debug errors faster instead of doing one whole chunk of deploying to realize that the last step does not work and you have to redo the whole thing.

If you run into errors saying that you do not have mysql2 gem then you probably installed the wrong gem. It should be mysql2 gem not mysql gem, the mysql gem is now stale and no longer supported. You need to install this gem and also define it in Gemfile PLUS ensure that database.yml uses mysql2, not mysql.

If all goes well, all tables would be created, then you can run a test of whether anything works or not by doing

 rails console [production]
>> app.get("/")

If it returns 200 or 302 (or any other 2xx or 3xx code, or even 4xx if you havenโ€™t configured the โ€/โ€ url for your application), youโ€™re probably set. If it returns something in the 500โ€™s, youโ€™ll want to check your log/production.log and see why it blew up.

Next, try to access any static asset in your public folder by pointing your browser to http://yourdomain.com/javascripts/prototype.js
It should display the javascript file. If it doesn’t you probably have some issues with apache. Make sure your VirtualHosts is pointing to demoapp/current/public folder

When it works, it is time to start the magic.

 cap deploy:start

I need to cry now. Thanks for reading. Peace out.

After that, for every subsequent release you can just issue this command.

 cap deploy