Capistrano recipe: update your remote shared assets and database to your local application
Posted: April 15th, 2009 | Author: Nick | Filed under: rails | Tags: capistrano, deploy, rails | 2 Comments »When working on a production site there is often a need to get the latest data from the database or the latest shared assets onto your local development machine.
Shared Assets are typically items that users uploads through some interface that you don’t want to store in your git repository but don’t want to overwrite on deploy. For example you have a user model and people can upload their avatar. We don’t want that image file in the repository but we do want to keep it on the live site.
When I talk about shared assets I mean specifically items in the public directory. These items should be in your .gitignore file as well as a symlink that is setup in your deploy recipe. A directory like public/uploads or public/images/photos. You shouldn’t be using this for javascript files, css, regular images, etc.
The live database often contains data that modifies either the content or display of your site. Various items such as blog posts, recent messages, and many other items.
Wouldn’t it be nice if you could have an easy way to make your local development site look just like the production site?
Assuming you already have a functioning deploy recipe the following is an additional namespace you can add to have this functionality. Also, make sure that you have your keys on your remote server so it doesn’t prompt you to login.
First lets setup the shared host that we want to pull this information from. We could probably pull from one of the roles but for now we are just going to use a single shared host. Modify this recipe as you see fit, this is just more of a base for people to work off of.
Specify the shared host to pull your remote assets and database from
set :shared_host, "nickhammond.com"
Now lets setup the namespace and recipe for the two tasks that we want to accomplish.
namespace :update do desc "Mirrors the remote shared public directory with your local copy, doesn't download symlinks" task :shared_assets do if shared_host # Used friendly options so it's easier to read # I'm using rsync so that it only copies what it needs # Windows users you can use the download method within capistrano and pass recursive => true run_locally("rsync --recursive --times --rsh=ssh --compress --human-readable --progress #{user}@#{shared_host}:#{shared_path}/public/ public/") else puts "Ummmm. You should define a shared_host variable so I know where to get the files from." end end desc "Dump remote production database into tmp/, rsync file to local machine, import into local development database" task :database do # First lets get the remote database config file so that we can read in the database settings get("#{shared_path}/config/database.yml", "tmp/database.yml") # load the production settings within the database file remote_settings = YAML::load_file("tmp/database.yml")["production"] # we also need the local settings so that we can import the fresh database properly local_settings = YAML::load_file("config/database.yml")["development"] # dump the production database and store it in the current path's tmp directory. I chose to use the same filename everytime so that it would just overwrite the same file rather than creating a timestamped file. If you want to use this to create backups then I would recommend putting something like Time.now in the filename and not storing it in the tmp directory run "mysqldump -u'#{remote_settings["username"]}' -p'#{remote_settings["password"]}' -h'#{remote_settings["host"]}' '#{remote_settings["database"]}' > #{current_path}/tmp/production-#{remote_settings["database"]}-dump.sql" # If your database is large you might want to bzip it up and then extract it later # run_locally is a method provided by capistrano to run commands on your local machine. Here we are just rsyncing the remote database dump with the local copy of the dump run_locally("rsync --times --rsh=ssh --compress --human-readable --progress #{user}@#{shared_host}:#{current_path}/tmp/production-#{remote_settings["database"]}-dump.sql tmp/production-#{remote_settings["database"]}-dump.sql") # now that we have the upated production dump file we should use the local settings to import this db. run_locally("mysql -u#{local_settings["username"]} #{"-p#{local_settings["password"]}" if local_settings["password"]} #{local_settings["database"]} < tmp/production-#{remote_settings["database"]}-dump.sql") end end
Follow me on Twitter