ActiveRecord Schema Dump without rails - ruby

In rails you can setup a rails app, assign the right db driver (I need firebird/fb) and then do a rake db:schema:dump pretty much out of the box.
I'm trying to do a version control for my database schema. How can I just make a ruby script that requires activerecord and fb libraries and achieve the same thing. I dont' need an entire rails app. All I want is a consistent script to extract the schema.

Looking at the source of the db:schema:dump task, the following code should get you started:
require 'active_record'
require 'active_record/schema_dumper'
require 'activerecord-fb-adapter'
filename = './schema.rb'
ActiveRecord::Base.establish_connection(
adapter: 'fb',
database: 'db/development.fdb',
username: 'SYSDBA',
password: 'masterkey',
host: 'localhost',
encoding: 'UTF-8',
create: true
)
File.open(filename, "w:utf-8") do |file|
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
end

I just happen to have been working on something similar except for the firebird/fb part.
require "yaml"
require "active_record"
include ActiveRecord
include ActiveRecord::Tasks
ActiveRecord::Migrator.migrations_path='./db/migrate'
DatabaseTasks.db_dir = './db'
db_config_file = "./config/database.yml"
db_config = YAML.load_file(db_config_file)
db_type = 'development'
db_object = db_config[db_type]
#sldbtask = SQLiteDatabaseTasks.new(db_object, './')
unless File.exist?(db_object['database'])
#sldbtask.create
#sldbtask.connection
# try different migation versions
migration_version = 0
ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_path, migration_version)
end
unless File.exist?('./db/schema.rb')
#DatabaseTasks.check_schema_file('./db/schema.rb')
File.open('./db/schema.rb', "w:utf-8") do |file|
#sldbtask.establish_connection(db_object)
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
end
end
Of course my adapter is different but it could be modified and it's versatile with a Rails app so you could drop the code part into the root directory. But of course you can rake for that but this just shows that it works. Tou might nave problems with the migration version though. I haven't thoroughly tested it.

Related

I want to use ActiveRecord in a non Rails way. How can I get my code to put the db file in the right directory?

config/database.yml
default: &default
adapter: sqlite3
encoding: unicode
development:
<<: *default
database: development.sqlite3
username: admin
password: wsxqaz
server: localhost
# port:
ruby code:
require "yaml"
require "active_record"
# shorten lines with this namespace
include ActiveRecord::Tasks
# trying to use db folder
DatabaseTasks.db_dir = './db'
db_config_file = "./config/database.yml"
db_config = YAML.load_file(db_config_file)
db_type = db_config['development']
#sldbtask = SQLiteDatabaseTasks.new(db_type, root = './')
#sldbtask.create
I've tried changing the root argument but that doesn't make any difference either.
What do I need to get my db file into the db directory? It creates it okay and the table stuff is pending. First things first.
I believe that the database is supposed to be generated in the root directory. The db folder is used for activerecord's schema and migration files. Why is it so important that the database generates in the db directory?
EDIT
I just found an easier way to do this. After you require all of the files you want, then enter set :database, {database:"./db/myDatabase.db"}. If you already have the line set :database in your code, just add that to it. Good luck!

require ruby library in serverspec

I am a newbie in ruby and trying to get my hands dirty in chef. I have written a wrapper cookbook on postgresql community cookbook and wish to test it using test kitchen. Following is the spec.rb file I have written:
require 'serverspec'
require 'pg'
include Serverspec::Helper::Exec
include Serverspec::Helper::DetectOS
RSpec.configure do |c|
c.before :all do
c.path = '/sbin:/usr/sbin'
c.os = backend(Serverspec::Commands::Base).check_os
end
end
describe "Postgresql server" do
it "should connect to database" do
conn = PG::Connection.open(:dbname => "db",:user => "user1",:password => "password")
conn.status == "CONNECTION_OK"
end
end
Through this test I wish to check if the user and database have been created properly.
However this test is unable to resolve the dependency of "pg". Where do I mention this dependency in serverspec?
I have used kitchen verify [node name] to run the test.
Create the Ruby code necessary to install the gem prior to requiring it in your spec_helper.rb file (or on the top of the spec file if it makes more sense):
begin
Gem::Specification.find_by_name('pg')
rescue Gem::LoadError
require 'rubygems/dependency_installer'
Gem::DependencyInstaller.new(Gem::DependencyInstaller::DEFAULT_OPTIONS).install('pg')
end
require 'pg'

How can I load ActiveRecord database tasks on a Ruby project outside Rails?

ActiveRecord 3.2.14
I want to use ActiveRecord in a non-Rails Ruby project. I want to have available the rake tasks that are defined by ActiveRecord. How can I do that?
rake db:create # Create the database from DATABASE_URL or config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)
rake db:drop # Drops the database using DATABASE_URL or the current Rails.env (use db:drop:all to drop all databases)
rake db:fixtures:load # Load fixtures into the current environment's database
rake db:migrate # Migrate the database (options: VERSION=x, VERBOSE=false)
rake db:migrate:status # Display status of migrations
rake db:rollback # Rolls the schema back to the previous version (specify steps w/ STEP=n)
rake db:schema:dump # Create a db/schema.rb file that can be portably used against any DB supported by AR
rake db:schema:load # Load a schema.rb file into the database
rake db:seed # Load the seed data from db/seeds.rb
rake db:setup # Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)
rake db:structure:dump # Dump the database structure to db/structure.sql
rake db:version # Retrieves the current schema version number
The above list is the list of tasks that I want to be able to use on my non-Rails Ruby project that uses ActiveRecord. What do I have to write in my Rakefile?
Thanks in advance
The easiest thing to do is to load the tasks already defined in databases.rake. Here is a GIST of how it was done.
Inspired by this GIST by Drogus
Rakefile.rb
require 'yaml'
require 'logger'
require 'active_record'
include ActiveRecord::Tasks
class Seeder
def initialize(seed_file)
#seed_file = seed_file
end
def load_seed
raise "Seed file '#{#seed_file}' does not exist" unless File.file?(#seed_file)
load #seed_file
end
end
root = File.expand_path '..', __FILE__
DatabaseTasks.env = ENV['ENV'] || 'development'
DatabaseTasks.database_configuration = YAML.load(File.read(File.join(root, 'config/database.yml')))
DatabaseTasks.db_dir = File.join root, 'db'
DatabaseTasks.fixtures_path = File.join root, 'test/fixtures'
DatabaseTasks.migrations_paths = [File.join(root, 'db/migrate')]
DatabaseTasks.seed_loader = Seeder.new File.join root, 'db/seeds.rb'
DatabaseTasks.root = root
task :environment do
ActiveRecord::Base.configurations = DatabaseTasks.database_configuration
ActiveRecord::Base.establish_connection DatabaseTasks.env.to_sym
end
load 'active_record/railties/databases.rake'
You could try the standalone-migrations gem:
https://github.com/thuss/standalone-migrations
For Rails 3.x:
You need to manually create the tasks. As example here is how to add them (this example uses the environment variables like Rails):
namespace :db do
desc "Drop and create the current database"
task :recreate => :environment do
abcs = ActiveRecord::Base.configurations
ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
ActiveRecord::Base.connection.recreate_database(ActiveRecord::Base.connection.current_database)
end
end
and you'll have the task rake db:recreate available
For Rails 4.x:
If you want to have the ActiveRecord rake tasks available in your ruby app, take a look at the documentation.
Example usage of DatabaseTasks outside Rails could look as such:
include ActiveRecord::Tasks
DatabaseTasks.database_configuration = YAML.load(File.read('my_database_config.yml'))
DatabaseTasks.db_dir = 'db'
# other settings...
DatabaseTasks.create_current('production')
Also you have here an example on how to use ActiveRecord in your ruby aplication.
Create your own!
Reference the Rails one though:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/railties/databases.rake
Create a Rake Task file. To use Rake, generally you want a tasks folder filled with Rake task files. These files have the ".task" extension.
Study the file to link given.
Take parts of that file, or even the entire contents of the file, and add it to your new Rake task file.
Make sure your Rakefile loads those task files. Your Rakefile should have something like this
-
Dir[File.join(PROJECT_ROOT, 'tasks', '**', '*.rake')].each do |file|
load file
end
I believe you can use the sinatra-activerecord gem even if you're not using Sinatra. I just solved this problem by requiring that gem and then adding
require 'sinatra/activerecord/rake'
to my rakefile.
Once I added that require line the db tasks showed up in my rake -T!
If you are using Sinatra, you can use this gem:
https://github.com/janko-m/sinatra-activerecord
However, if you don't use it either, the source code inside provides a good example on how to implement AR rake tasks.

Using a rackup file to custom configure an application instance

tl;dr How can I get a single Sinatra app to start up very differently on different servers via customizations to config.ru?
Background
I have a single web application written using Sinatra that's run on different servers. Currently the codebase for these servers is forked because there are some non-trivial differences in the way (discrete) parts of them work. For example:
one server authenticates users via an intranet LDAP server, while another server uses a simpler local database table lookup.
one server uses an external cron job to periodically update some statistics, while another (Windows-based) server uses an internal sleepy Thread.
one server stores certain metadata in a local table, while another server pulls the metadata from an external Wiki via screen scraping (!).
…and so on.
I'd like to get these code bases completely shared (single Git repo). I envision that each server would have one slightly-differing configuration file that causes the app to be started up differently.
Abandoned Solutions
I could change the behavior of the app based on environment variables. As there are a not-tiny number of variations in behavior, I'd rather not hide the settings in environment variables.
I could create my own "server-settings.rb" file that is unique to each machine, require it in my app.rb, and then change the configuration there. However, this seems to possibly be re-inventing the wheel. I already have a file named config.ru for each server. Shouldn't I be using this?
The Current Code
My config.ru for the app currently is simply:
require ::File.join( ::File.dirname(__FILE__), 'app' )
run MyApp.new
And the app.rb that it requires is, in essence:
require 'sinatra'
require_relative 'helpers/login' # customized for LDAP lookup on this server
class MyApp < Sinatra::Application
use Rack::Session::Cookie, key:'foo.bar', path:'/', secret:'ohnoes'
set :protection, except: [:path_traversal, :session_hijacking]
configure :production do
# run various code that depends on server settings, e.g.
Snapshotter.start # there is no cron on this machine, so we do it ourselves
end
configure :development do
# run various code that depends on server settings
end
end
The Question
I'd like to make config.ru live up to its name, and have it look something like this:
require ::File.join( ::File.dirname(__FILE__), 'app' )
run MyApp.new( auth: :ldap, snapshot:false, metadata: :remote_wiki, … )
How can I modify my application to change its configuration behavior based on settings supplied via config.ru? Or is this an abuse of config.ru, trying to use it for totally the wrong thing?
As soon as I started reading the question the first answer to pop into my head was "environment variable" but you scotched that straight away :)
I'll go with a mixture of one of your coulds and the desired outcome code, as it's how I structure things…
Because I want to be able to test my applications more easily, I take most of the Ruby out of the config.ru and into a separate config.rb file and leave config.ru to be a bootstrap file. So my standard skel is:
config.ru
# encoding: UTF-8
require 'rubygems'
require 'bundler'
Bundler.setup
root = File.expand_path File.dirname(__FILE__)
require File.join( root , "./app/config.rb" )
# everything was moved into a separate module/file to make it easier to set up tests
map "/" do
run APP_NAME.app
end
app/config.rb
# encoding: utf-8
require_relative File.expand_path(File.join File.dirname(__FILE__), "../lib/ext/warn.rb")
require_relative "./init.rb" # config
require_relative "./main.rb" # routes and helpers
require 'encrypted_cookie'
# standard cookie settings
COOKIE_SETTINGS = {
:key => 'usr',
:path => "/",
:expire_after => 86400, # In seconds, 1 day
:secret => ENV["LLAVE"],
:httponly => true
}
module APP_NAME # overall name of the app
require 'rack/ssl' # force SSL
require 'rack/csrf'
if ENV["RACK_ENV"] == "development"
require 'pry'
require 'pry-nav'
end
# from http://devcenter.heroku.com/articles/ruby#logging
$stdout.sync = true
ONE_MONTH = 60 * 60 * 24 * 30
def self.app
Rack::Builder.app do
cookie_settings = COOKIE_SETTINGS
# more security if in production
cookie_settings.merge!( :secure => true ) if ENV["RACK_ENV"] == "production"
# AES encryption of cookies
use Rack::Session::EncryptedCookie, cookie_settings
if ENV["RACK_ENV"] == "production"
use Rack::SSL, :hsts => {:expires => ONE_MONTH}
end
# to stop XSS
use Rack::Csrf, :raise => true unless ENV["RACK_ENV"] == "test"
run App # the main Sinatra app
end
end # self.app
end # APP_NAME
The initial reason I did this was making it easy to run the app in specs:
shared_context "All routes" do
include Rack::Test::Methods
let(:app){ APP_NAME.app }
end
but it makes sense to me to keep this code with the rest of the application code, so to speak, as I can bundle things together, run other apps etc. I've used this to conditionally load different examples into the specs in a few projects (it helps cut down on duplicated effort and check the examples really work), so I don't see why you couldn't use it to conditionally load configurations.
This way you get to choose to use a conditional in the config.ru as to which config.rb file you would use, or use an env var in the config.rb as to which definiton of self.app to use , or pass in an options hash to self.app…
With your set up I'd rename the APP_NAME module to MyApp, and the Sinatra class to App (because quite often I'll have an website that runs a front end and an API, so the Sinatra classes get named by their function (App, API etc) and wrapped in a module named after the site) and end up with:
config.ru
map "/" do
run MyApp.app( auth: :ldap, snapshot:false, metadata: :remote_wiki )
end
config.rb
def self.app( opts={} )
opts = DEFAULT_OPTIONS.merge opts
# …
run App
end
It'll be interesting to see how other people tackle this.

Why do I need to run my sinatra app again when making changes and my environment is not :development?

I just implemented Compass configuration for my Sinatra app but when I change the environment to :test or :production and modify my files like screen.sass or index.haml my changes are not reflected when I reload the page so I need to run my app again?
Is it normal? Is is just me?
This is how my app.rb file looks like:
require 'sinatra'
require 'haml'
require 'sass'
require 'compass'
require './helpers.rb'
configure do
set :environment, :test
Compass.configuration do |config|
settings.environment == :production ?
config.output_style = :compressed :
config.output_style = :nested
settings.environment == :development ?
config.line_comments = true :
config.line_comments = false
end
set :sass, Compass.sass_engine_options
end
before do
#js = 'javascript:;'
end
get '/scripts/jquery.js' do
# Downloads the latest jQuery 1.x version when needed. Requires to reload the page after done.
`curl "https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" >> public/scripts/jquery.js`
end
get '/styles/:name.css' do
sass :"styles/#{params[:name]}"
end
get '/?' do
haml :index
end
get '/:page/?' do
haml params[:page].to_sym
end
Any idea?
Generally, if you make a change to a running Sinatra application, you have to restart the application, as the program has already been loaded to memory.
There are options for automatically detecting changes and restarting the application on the Sinatra FAQ.
Since Shotgun fix the issue partially (reloading the files for your at production, maybe try with Sinatra::Reloader which, IMHO, works better than Shotgun.
Maybe something like (not tested)
require "sinatra"
configure(:production) do |c|
require "sinatra/reloader"
c.also_reload "*.sass", "*.haml"
end
That being said, are you sure you do need this kind of behavior on a production/test environment for updating? Development env. should be (at least, for what I use it for) for this kind of hot testing.
I used to use sinatra::reloader
but I didn't like the huge dependencies incurred (as should we all be mindful how many gems get activated)
pistol ( at a tender age of ver 0.0.2) and I think does the required job nicely
I use shotgum gem for this.
gem install shotgun
then
shotgun app.rb
from within the app dir
this then reloads the app per request, rather than holding the whole thing in memory. you access the site on localhost:9393

Resources