There are a lot of ways to deploy an app to a server, here is a simple one that I often use. This can be a bit confusing if you are not familiar with Git but I promise it’s the easiest way!

It works like this: you create an empty git repository on the server and you push the branch you want to this reposity from your development machine. The repository on the server has a little script (hook) that puts the files in the right directory (‘rails_project’) and runs all the bundle commands. You end up with 2 directories: the bare repository and the ‘checkout’ with the project.

1. Create the bare repository on the server

Login to the server with the user account you want to use to run the application and create the bare repository in the home directory.

mkdir bare-repository 

cd bare-repository

git init --bare

or as a oneliner:

mkdir bare-repository && cd $_ && git init --bare

You can’t really interact with a bare repository the way you do with a normal repository. But you can push to it and let it automatically run hooks on the server. That’s enough for this setup.

We also need a directory for the checkout, let’s create that as well. I use a generic name for the checkout so I don’t have to change my scripts on every server. I like ‘rails_project’ or just ‘checkout’.

mkdir ~/rails_project

2. Install the commit hook (script)

The application will not run out of the bare repository directory. That’s just where we push the code to. The post-receive hook will check out the code from the bare repository to the ‘rails_project’ directory.

Go back to your home directory with ‘cd’ and edit the post-receive hook:

nano bare-repository/hooks/post-receive

We need to add a command to do the checkout and run bundle install for us. We’ll add more functionality later.

GIT_WORK_TREE=~/rails_project git checkout -f
cd ~/rails_project
bundle install --without development test

This will check out the code in the bare repository to the directory ‘rails_project’ and run bundle install in it. Your git client on your machine will show you the output generated by this script after the usual notifications.

And give this post-receive hook enough permissions to run:

chmod a+x bare-repository/hooks/post-receive

 

3. Let’s add the remote and push something

To add the bare-repository on the server as a remote to your local git repository use:

git remote add newserver rails@test.runrails.com:bare-repository

You have to run this command on your development machine, not the server. The ‘newserver’ is just the name of the remote, you can call it whatever you like. I often have ‘staging’ or ‘production’.

And push the master branch to the server. Again, newserver is the name of the remote and master is the name of the branch you want to push to it.

git push newserver master

You will see the output of the post-receive hook in your terminal or Git client. To push the same code again if something was wrong on the server create an empty commit and push again.

git commit --allow-empty
git push newserver master

4. Improvements and troubleshooting

If you use RVM the bundle install part won’t work. You have to use the rvm bundle wrapper like this:

/usr/local/rvm/gems/ruby-2.4.0/wrappers/bundle install --without development test

There is no rollback option like with capistrano in with this deployment method but it’s easy to add a database backup to the script with:

pg_dump your_db_production > ~/pgdump_before_deploy.sql

And you can login with ssh and migrate your database by hand, but it’s much easier to add it to the post-receive hook. Same for assets:precompile

bundle exec rake db:migrate
bundle exec rake assets:precompile

Touch restart.txt to automatically restart your rails app if you use Passenger:

touch ~/rails_project/tmp/restart.txt

And if your script generates a lot of output, you might want to add an error notification in case something goes wrong. Add this block to the top of the hook:

#!/bin/bash
exit_with_error() {
  echo "[DEPLOY] !!!!!!!!!!!!!!!!!!!! An error has occurred !!!!!!!!!!!!!!!!!!!!!!!"
  exit 1
}
and add  **   ** exit_with_error after each command you want to be notified about. For example:
bundle exec rake assets:precompile || exit_with_error

 

That’s all. Let me know if you have any questions about this method or found any mistakes. You can email me on info@runrails.com or Tweet to me at @runrails.com