July 19, 2010

10 Steps to Capistrano and Plesk Subdomains Deployment

Filed under: Designer Showcase, TDS Developer's Corner — Dawn @ 12:56 pm

We’ve adopted a standard convention for deploying Rails apps that places the files in a subdomain of our clients’ domains. Since we use Plesk, there are some steps we have to take to get Capistrano deploys working. Since we deploy a lot of apps, I decided to write this guide as much for the office as for anyone who may find it useful. Let’s go through the steps:

  1. Create your subdomain in Plesk (ie. myrailsapp)
  2. Navigate to the /domain.com/subdomains/myrailsapp/conf directory
  3. Create a vhost.conf file. Again, we use a convention that creates a new directory within /myrailsapp that holds our rails code. Fittingly, we name the directory /rails. The DocumentRoot points to the public directory of our application. Enter the following into the vhost.conf file:
  4. DocumentRoot /var/www/vhosts/domain.com/subdomains/myrailsapp/rails/current/public 
    RailsEnv production
    
    
  5. If you haven’t already installed the capistrano and capistrano-ext (for multistage environments such as testing and production deploys), you’ll need to get them. The Capistrano tutorials will walk you through that process.
  6. With the gems installed, now we want to capify our code. In your root rails app directory, enter the following command. (You may have to sudo the command depending on your directory permissions.)
  7. capify .
    

    This will create two files: Capfile and deploy.rb in your /config directory.

  8. Open up your deploy.rb file and enter your configuration variables. Again, you can refer to the Capistrano tutorials for help.
  9. If you are only planning to deploy to a single environment, you’re work is done. If you plan a multi-stage environment, you’ll want to set the stages in your deploy.rb file and require the capistrano-ext gem like this:
    set :stages, %w(testing, production)
    set :default_stage, "testing"
    require "capistrano/ext/multistage"
    
    
  10. Within the /config directory, create a new /deploy directory and two new files, testing.rb and production.rb. These files will provide the deploy details for each environment.
  11. Open up your new .rb files and enter the following for each environment:
    
    #############################################################
    #   Application
    #############################################################
    
    set :application, "myrailsapp"
    set :deploy_to, "/var/www/vhosts/domain.com/subdomains/myrailsapp/rails"
    
    #############################################################
    #   Settings
    #############################################################
    
    default_run_options[:pty] = true
    ssh_options[:forward_agent] = true
    set :use_sudo, true
    set :scm_verbose, true
    set :rails_env, "testing" 
    
    #############################################################
    #   Servers
    #############################################################
    
    set :user, "username"
    set :password, "user_password"
    set :domain, "myrailsapp.domain.com"
    server domain, :app, :web
    role :db, domain, :primary => true
    
    #############################################################
    #   Passenger
    #############################################################
    
    namespace :deploy do
      desc "Create the database yaml file"
      task :after_update_code do
        db_config = <<-EOF
        production:    
          adapter: mysql
          encoding: utf8
          username: database_username
          password: database_password
          database: database
          host: localhost
        EOF
        
        put db_config, "#{release_path}/config/database.yml"
    
      end
        
      # Restart passenger on deploy
      desc "Restarting mod_rails with restart.txt"
      task :restart, :roles => :app, :except => { :no_release => true } do
        run "touch #{current_path}/tmp/restart.txt"
      end
      
      [:start, :stop].each do |t|
        desc "#{t} task is a no-op with mod_rails"
        task t, :roles => :app do ; end
      end
      
    end
    
    
    Then add the details of your repository for either subversion or git.
    
    
    #############################################################
    #   GIT
    #############################################################
    
    set :scm, :git
    set :branch, "master"
    set :repository, "git@github.com:your_github_path/MYRAILSAPP.git"
    set :deploy_via, :remote_cache
    ssh_options[:forward_agent] = true
    
    #############################################################
    #   SVN
    #############################################################
    
    set :scm, :svn
    set :branch, "trunk"
    set :scm_user, 'username'
    set :scm_password, "user_password"
    set :repository, Proc.new { "--username #{scm_user} --password '#{scm_password}' --no-auth-cache http://doman.com/path/to/your/subversion/repository/#{application}/trunk" } 
    
    set :deploy_via, :remote_cache
    ssh_options[:forward_agent] = true
    
    
  12. That’s it; you’re ready to deploy. Back at your terminal window, you’ll type the respective environment to which you’re deploy:
cap testing deploy

A final note: make sure the user specified in your deploy files has permission to create directories on the server, otherwise your /releases directories will not be created.

Feel free to ask any questions if you’re having trouble with your Plesk subdomain and Capistrano deployment. Good luck!

January 7, 2010

Rails validation error not displaying - validates_presence_of, error_message_for

Filed under: TDS Developer's Corner — Dawn @ 4:26 pm

I hit a wall recently as I tried to track down the reason validates_presence_of was not displaying errors. Rails validations normally go off without a hitch, so I was a bit stumped when my attempts to save blank fields were not triggering the appropriate messages. After ensuring my model and view were correct, I fired up the console to make sure my validations were working in the first place. After loading an object and attempting a save, I checked to see if the errors object returned false. Sure enough, all of the validations were enforced.


>> @contact = Contact.find_by_id(9)
=> #
>> @contact.save
=> false
>> @contact.errors.empty?
=> false
>> @contact.errors.count
=> 6
>> @contact.errors.each_full { |msg| puts msg }
   City No blanks
   Zip No blanks
   First name No blanks
   Address No blanks
   Last name No blanks
   State No blanks

After more head banging, I was ready to give up with a simple notification workaround on the update method.


if !@contact.errors.empty?
  flash[:error] = "You are missing required fields."
  redirect_to edit_contact_url(@contact.user)
else
  flash[:notice] = "Successfully saved."
  redirect_to contact_url(@contact.user)
end

That works, but it doesn’t take advantage of the Rails’ error_messages_for helper to display helpful messages and highlight problem fields. Then I realized the initial error. During redirects, the object’s data isn’t passed, so while the validations were enforced (the form data would not save upon submission), no errors were being output to the screen. My new code rendered the page along with the error messages:


if !@contact.errors.empty?
  render :action => 'edit'
else
  flash[:notice] = "Successfully saved."
  redirect_to contact_url(@contact.user)
end