Monthly Archives: May 2015

Rails – Output Current Environment, rake tasks and db methods

Start rails command line

rails c

From rails c

Rails.configuration.database_configuration[Rails.env]

As a method

namespace :db_utils do
 
    desc "db_utils"

    # POSTGRES - options - notes
    # -C Begin the output with a command to create the database itself and reconnect to the created database. 
    #    If --clean is also specified, the script drops and recreates the target database before reconnecting to it.
    # -h hostname
    # -U username

    # file_provided? is not in use but may be helpful moving forward
    def file_provided?(file)
        unless file
            puts "Please specify an export file name."
            return false        
        end
        return true
    end

    def db_provided?(db)
        unless db
            puts "Please specify a db to export."
            return false        
        end
        return true
    end

    def db_exists?(db)
        # system and backticks issue sh commands not bash commands
        # add "bash", "-c" before cmd to use bash
        return system "bash", "-c", "psql -lqt | cut -f 1 -d \\| | grep -w #{db} | wc -l"
        puts "db_exists? #{exists}"
    end

    def create_time_stamp() 
        return Time.now.strftime("%Y%m%d%H%M%S")
    end

    def set_file(file)
        if (file.nil?)
            file = create_time_stamp()
        end
        if ("#{file}".include? ".sql")
            return file
        else
            return "#{file}.sql"
        end
    end

    def default_file()
        app = Rails.application.class.parent_name.underscore    
        return "#{Rails.root}/db/#{app}.sql"
    end

    # returns -h host
    def set_host(host)
        if (host.nil?)
            host = "localhost"
        end
        return "-h #{host}"
    end

    # confirms db provided and db exists 
    # returns -d dbname
    def set_db(db)
        if (db_provided?(db) && db_exists?(db))
            return "-d #{db}"
        end
    end
        
    # returns -U with env username or current user from whoami
    def set_user(user)
        if (user.nil?)
            # Strip trailing whitespace
            user = `whoami`.strip
        end     
        return "-U #{user}"
    end

    def create_db(db)
        system "createdb '#{db}'"
    end

    def backup_to_file(host, user, db, file)
        if db_provided?(db) && db_exists?(db)
            host = set_host(host)
            user = set_user(user)
            db = set_db(db)
            file = set_file(file)

            # --clean       Output commands to clean (drop) database objects prior to (the commands for) creating them.
            # --verbose     output detailed object comments
            # --no-owner    Do not output commands to set ownership of objects to match the original database.
            # --no-acl      Prevent dumping of access privileges (grant/revoke commands).
            # -Fc           The most flexible output file format is the "custom" format (-Fc)
            # --format=t    Output a tar-format archive suitable for input into pg_restore!
            cmd = "pg_dump #{host} #{user} --clean --verbose --no-owner --no-acl -Fc --format=t #{db} > #{file}"
            puts cmd
            system cmd
        end
    end

    def restore_from_file(host, user, db, file)
        if db_provided?(db)
            host = set_host(host)
            user = set_user(user)
            db = set_db(db)
            file = set_file(file)

            # --verbose     output detailed object comments
            # --no-owner    Do not output commands to set ownership of objects to match the original database.
            # --no-acl      Prevent dumping of access privileges (grant/revoke commands).

            cmd = "pg_restore --verbose #{host} #{user} --no-owner --no-acl #{db} < #{file}"
            puts cmd
            system cmd
        end 
    end

    def killDB(db)
        # old attempt
        #cmd = "psql #{user} postgres; REVOKE CONNECT ON DATABASE #{db} FROM public; ALTER DATABASE #{db} CONNECTION LIMIT 0; SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE pid <> pg_backend_pid() AND datname='#{db}'; DROP DATABASE #{db};"

        # Fix This?
        # boot connected db users to drop db
        # this is the only way to remove the lock on the db
        # I've found that works
        killDB = "ps xa | grep postgres: | grep #{db} | grep -v grep | awk '{print $1}' | sudo xargs kill"
        system killDB
    end

    # pg uses current user as default
    # to do - add host
    def drop_db(user, db)
        user = set_user(user)
        if (!db.nil? && db_exists?(db))
            killDB(db)
            cmd = "dropdb #{db}"
            puts cmd
        end
    end

    def backup_env(originStr)
        origin = get_environment_config(originStr)
        puts "backup_env"
        backup_to_file(origin["host"], origin["username"], origin["database"], nil)
    end

    def get_environment_config(env = Rails.env)
        return Rails.configuration.database_configuration[env]
    end


    def migrate_db_env(originStr, destStr)

        # environment vars
        origin = get_environment_config(originStr)
        dest = get_environment_config(destStr)

        # database.yml doesn't always have username for development
        # current user is the likely owner of the pg db
        dest_username = (dest["username"].nil?) ? `whoami`.strip : '#{dest["username"]}'

        killDB(dest["database"])
        drop_db(dest_username, dest["database"])

        # FIX THIS - NOT WORKING / Too many vars
        migrateDb(origin["host"], origin["username"], origin["database"], dest["host"], dest_username, dest["database"])

    end


    # FIX THIS - Too many vars
    # complex manual setup
    # set up to use set_user etc..
    def migrateDb(originHost, originUser, originDB, destHost, destUser, destDB)
        system "migrateDb"
        # should be split into syntax builders and use |
        cmd = "pg_dump -h #{originHost} -U #{originUser} --clean --verbose --no-owner --no-acl -Fc --format=t -d #{originDB} | pg_restore -h #{destHost} -U #{destUser} -d #{destDB} --clean --create --verbose"
        puts cmd
        system cmd
    end


    # TASKS

    task :backup, [:db, :file] => :environment do |task, args|
        puts "backup db #{args.host} #{args.user} #{args.db}"
        backup_to_file(nil, nil, args.db, args.file)
    end

    task :drop, [:db] => :environment do |task, args|
        puts "drop db"
        drop_db(nil, args.db)
    end

    task :restore, [:db, :file] => :environment do |task, args|
        puts "restore db #{args.db} #{args.file}"
        restore_from_file(nil, nil, args.db, args.file)
    end

    task :backup_drop_restore, [:fromdb, :todb, :file] => :environment do |task, args|
        puts "backup_drop_restore db"
        backup_to_file(args.fromdb, args.file)
        drop_db(nil, args.todb)
        restore_from_file(nil, nil, args.todb, args.file)
    end

    task :migrate_db_env, [:fromdb, :todb] => :environment do |task, args|
        puts "migrate_db_env db"
        migrate_db_env(args.fromdb, args.todb)
    end
    
    task :backup_env, [:db] => :environment do |task, args|
        puts "backup_env db"
        backup_env(args.db)
    end

    task :dumpDB, [:env] =>:environment do |task, args|
        
        cmd = nil
        dbEnv = get_environment_config(args.env)

        backup_to_file(dbEnv["host"], dbEnv["username"], dbEnv["database"], default_file())
    end

    task :restoreDB, [:env] =>:environment do |task, args|
        
        cmd = nil
        dbEnv = get_environment_config(args.env)

        # Fix This?
        # disconnect connected db users to drop db
        # this is the only way to remove the lock on the db I've found that works
        killDB(dbEnv["database"])

        drop_db(nil, dbEnv["database"])
        Rake::Task["db:drop"].invoke

        create_db(dbEnv["database"])
        Rake::Task["db:create"].invoke

        Rake::Task["db:migrate"].invoke

        restore_from_file(dbEnv["host"], dbEnv["username"], dbEnv["database"], default_file())
    end

    # http://www.tutorialspoint.com/ruby-on-rails/rails-and-rake.htm
    # rake db:schema:dump
    # rake db:schema:load

    # Order of events
    # rake db:drop
    # createdb ats_development
    # rake ats_api:db:v2:migrate
    # rake db_utils:backup_env[staging]
    # rake db_utils:restore[db_name,20150512151540.sql]
    # OR
    # rake db_utils:migrate_db_env[staging,development]
    
    # API Server must be down during rake
    #
    # Examples 
    
    # output db with structure and create commands using datetimestamp.sql as file name
    # rake db_utils:backup[db_name]

    # output db with structure and create commands using    
    # rake db_utils:backup[db_name, 'backup.sql']
    
    # drop a db
    # rake db_utils:drop[db_name]

    # restore db from file
    # rake db_utils:restore[db_name,20150506153637.sql]

    # migrate directly from one db to another db as described in database.yml
    # rake db_utils:migrate_db_env[staging,development]

end

Phantom Scraper – Node – PhantomJS

var phantom = require('phantom');

function writeFile(fileName, contents) {
    var fs = require('fs');
    fs.writeFile(fileName, contents, function (err) {
      if (err) return console.log(err);
      console.log('File:' + fileName + ' written');
    });
}

var url = "http://localhost:8080/#/agencies/new";
phantom.create(function (ph) {
  ph.createPage(function (page) {
    page.open(url, function (status) {
      page.evaluate(function () {
        return document.getElementsByTagName('form')[0].innerHTML; 
      }, function (result) {
        var fileName = url.split("#")[1].replace(/\//g, "_") + '.html';
        writeFile(fileName, result)
        console.log(result);
        ph.exit();
      });
    });
  });
});

Ruby – Parse Directory – Rename Files – Copy contents to another folder for additional processing

# split, pop and strip file_path to return file_name
def prepFileName(file_path, ext, ds = "/")
    path_array = file_path.split(ds)
    file_name = path_array.pop
    return file_name.sub(ext, '')
end

def createNewFilePath(file_path, new_location, ext)
    unless new_location.nil?
        file_path = new_location + prepFileName(file_path, ext)
    end
    return file_path
end

def writeFile(file_path, contents, new_location, ext)
    file_path = createNewFilePath(file_path, new_location, ext)
    File.open(file_path, 'w') { |file| file.write(contents) }
end

def readFile(file_path)
    return File.read(file_path)
end

def readDir(dir)
    return Dir[ File.join(dir, '**', '*') ].reject { |p| File.directory? p }
end

dir = nil
array_of_all_files = nil

# Should be a hash?

array_of_all_files = readDir(ARGV[0])

array_of_all_files.each do |file_path|
    contents = readFile(file_path)
    writeFile(file_path, contents, ARGV[1], ARGV[2])
end

puts array_of_all_files

use

ruby dir.rb ./templates/ ./ .hbs.hamlbars

Postgres SQL – Query Table Structure and metadata

// USING POSTGRES SQL

SELECT table_name
FROM information_schema.tables
WHERE table_type = ‘BASE TABLE’
AND table_schema NOT IN
(‘pg_catalog’, ‘information_schema’);

SELECT column_name
FROM information_schema.columns
WHERE table_name = ‘YourTablesName’;

SELECT table_schema, table_name, column_name, data_type
FROM information_schema.columns
WHERE table_schema = (‘public’) and table_name in (‘agencies’)

SELECT table_schema, table_name, column_name, data_type, udt_name, character_maximum_length, udt_catalog
FROM information_schema.columns
WHERE table_schema = (‘public’) and table_name not like ‘pg_%’ and table_name in (‘agencies’) and udt_catalog = ‘ats_development’

USING PSQL

echo ‘\d’ | psql ats_development > tables.sql

echo ‘\d users’ | psql ats_development > users.sql

for table in $(<listoftables); do
echo ‘\d’ | psql
done > $table.sql

Information on quering information_schema:

http://www.alberton.info/postgresql_meta_info.html

http://stackoverflow.com/questions/582657/how-do-i-discover-the-structure-of-a-postgresql-database

postgres=# \?
General
\copyright show PostgreSQL usage and distribution terms
\g [FILE] or ; execute query (and send results to file or |pipe)
\h [NAME] help on syntax of SQL commands, * for all commands
\q quit psql

Query Buffer
\e [FILE] [LINE] edit the query buffer (or file) with external editor
\ef [FUNCNAME [LINE]] edit function definition with external editor
\p show the contents of the query buffer
\r reset (clear) the query buffer
\s [FILE] display history or save it to file
\w FILE write query buffer to file

Input/Output
\copy … perform SQL COPY with data stream to the client host
\echo [STRING] write string to standard output
\i FILE execute commands from file
\o [FILE] send all query results to file or |pipe
\qecho [STRING] write string to query output stream (see \o)

Informational
(options: S = show system objects, + = additional detail)
\d[S+] list tables, views, and sequences
\d[S+] NAME describe table, view, sequence, or index
\da[S] [PATTERN] list aggregates
\db[+] [PATTERN] list tablespaces
\dc[S] [PATTERN] list conversions
\dC [PATTERN] list casts
\dd[S] [PATTERN] show comments on objects
\ddp [PATTERN] list default privileges
\dD[S] [PATTERN] list domains
\det[+] [PATTERN] list foreign tables
\des[+] [PATTERN] list foreign servers
\deu[+] [PATTERN] list user mappings
\dew[+] [PATTERN] list foreign-data wrappers
\df[antw][S+] [PATRN] list [only agg/normal/trigger/window] functions
\dF[+] [PATTERN] list text search configurations
\dFd[+] [PATTERN] list text search dictionaries
\dFp[+] [PATTERN] list text search parsers
\dFt[+] [PATTERN] list text search templates
\dg[+] [PATTERN] list roles
\di[S+] [PATTERN] list indexes
\dl list large objects, same as \lo_list
\dL[S+] [PATTERN] list procedural languages
\dn[S+] [PATTERN] list schemas
\do[S] [PATTERN] list operators
\dO[S+] [PATTERN] list collations
\dp [PATTERN] list table, view, and sequence access privileges
\drds [PATRN1 [PATRN2]] list per-database role settings
\ds[S+] [PATTERN] list sequences
\dt[S+] [PATTERN] list tables
\dT[S+] [PATTERN] list data types
\du[+] [PATTERN] list roles
\dv[S+] [PATTERN] list views
\dE[S+] [PATTERN] list foreign tables
\dx[+] [PATTERN] list extensions
\l[+] list all databases
\sf[+] FUNCNAME show a function’s definition
\z [PATTERN] same as \dp

Formatting
\a toggle between unaligned and aligned output mode
\C [STRING] set table title, or unset if none
\f [STRING] show or set field separator for unaligned query output
\H toggle HTML output mode (currently off)
\pset NAME [VALUE] set table output option
(NAME := {format|border|expanded|fieldsep|footer|null|
numericlocale|recordsep|tuples_only|title|tableattr|pager})
\t [on|off] show only rows (currently off)
\T [STRING] set HTML

<

table> tag attributes, or unset if none
\x [on|off] toggle expanded output (currently off)

Connection
\c[onnect] [DBNAME|- USER|- HOST|- PORT|-]
connect to new database (currently “postgres”)
\encoding [ENCODING] show or set client encoding
\password [USERNAME] securely change the password for a user
\conninfo display information about current connection

Operating System
\cd [DIR] change the current working directory
\timing [on|off] toggle timing of commands (currently off)
! [COMMAND] execute command in shell or start interactive shell

Variables
\prompt [TEXT] NAME prompt user to set internal variable
\set [NAME [VALUE]] set internal variable, or list all if no parameters
\unset NAME unset (delete) internal variable

Large Objects
\lo_export LOBOID FILE
\lo_import FILE [COMMENT]
\lo_list
\lo_unlink LOBOID large object operations

Rails Cheats

Set current version of ruby

rvm --default use 2.1.1

Use migrate from named origin / dest in database.yml

-C Begin the output with a command to create the database itself and reconnect to the created database.

If –clean is also specified, the script drops and recreates the target database before reconnecting to it.

-h hostname

-U username

def getEnvironmentConfig(env = Rails.env)
        return Rails.configuration.database_configuration[env]
    end

    # Use migrate from named origin / dest in database.yml
    def migrateDbEnv(originStr, destStr)
        origin = getEnvironmentConfig(originStr)
        dest = getEnvironmentConfig(destStr)
        system "pg_dump -C -h #{origin["host"]} -U #{origin["username"]} #{origin["database"]} | psql #{dest["host"]} -U #{dest["username"]} #{dest["database"]}"
    end

http://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-ruby.html

Mac Terminal – change default shell

Terminal -> Preferences -> General -> Shell opens with:

Update as needed, the following are available by default.

/bin/bash
/bin/sh
/bin/zsh
/bin/ksh
/bin/tcsh

These can also be set from the command line using the following commands.

chsh -s /bin/bash
chsh -s /bin/sh
chsh -s /bin/zsh
chsh -s /bin/ksh
chsh -s /bin/tcsh

Set up Sublime, Homebrew, Ruby, Rails, Postgres

New Installs for Mac 10.10 Yosemite

Install Sublime

open ~/.bash_profile

If the following is not there already, add

export PATH=/usr/local/bin:$PATH

Create softlink from app to bin to use sublime in terminal

! the softlink name determines the terminal command name

sublime .

opens current folder as project in Sublime

Note: Check the name of the app in Applications, update as needed

ln -s /Applications/Sublime\ Text.app/Contents/SharedSupport/bin/subl /usr/local/bin/sublime

Install homebrew

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Install Ruby 2.2 / rbenv

Install rbenv

brew install rbenv ruby-build

Add rbenv to bash so that it loads every time you open a terminal

echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bash_profile source ~/.bash_profile

Install Ruby

rbenv install 2.2.2 rbenv global 2.2.2 ruby -v

Install Rails

gem install rails -v 4.2.1

Update rbenv to see new rails

rbenv rehash

Install PostGres

brew install postgresql

Softlink Postgres to User LaunchAgents folder to start on signin

mkdir -p ~/Library/LaunchAgents ln -sfv /usr/local/opt/postgresql/*.plist ~/Library/LaunchAgents/

start postgres / restart or use the following

launchctl load ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist

Create a rails app to test

If you want to use Postgres

Note you will need to change config/database.yml’s username to be

the same as your OSX user account. (for example, mine is ‘chris’)

rails new myapp -d postgresql

Move into the application directory

cd myapp

Create the database

rake db:create

if you get the following error

connections on Unix domain socket “/tmp/.s.PGSQL.5432”?

remove the postgres gem and use bundle install to reinstall the correct version

gem uninstall 
pg bundle install 
rake db:create rails server

Use Puma as WebServer

gem install puma

Add this to the Gemfile

\#use puma webserver
gem 'puma'

Run Bundle install

bundle install

created via trail by fire and a handful of sites including

https://gorails.com/setup/osx/10.10-yosemite