Provisioning database schemas in ruby - ruby

I'm looking for a database agnostic way to create new schemas. Something like
postgres_uri = "postgres://username:password#hostname/database"
mysql_uri = "mysql://username:password#hostname/database"
[postgres_uri, mysql_uri].each do |db|
connection = DB.connect(db_uri)
connection.create_schema("xyz")
end
Bonus marks for something that will work easily with the connection active_record establishes in rails.

The only thing that comes to mind is somehow having two active_record "instances" and running activerecord migrations on each. Sequel allows for the same thing, and even allows for string instance names.

Related

How to get access to Hanami connection instance

Hanami uses Sequel as default ORM
There are different plugins for Sequel
Sometimes to use it you need to access to database connection object
For example to use PostgreSQL advisory locking for mutexes
There are such gems for this: sequel-advisory-locking, sequel-pg_advisory_lock
First, you should load an extension for Sequel::Database instance
DB.extension(:advisory_locking)
Then use it in your app like this
DB.advisory_lock('my_key') do
# do stuff with lock
end
But there is problem to use such libraries with Hanami
There is no information about it in official guide
On database configuration page such info:
Hanami models use ROM as a low-level backend. This means that you can easily use any Sequel plugins in your app. For this you need to define a gateway block in your model configuration, add the extension by calling extension on gateway.connection and pass the extension name in:
# config/environment.rb
Hanami.configure do
model do
gateway do |g|
g.connection.extension(:connection_validator)
end
end
end
What I tried is define constant in this config
Hanami.configure do
model do
gateway do |g|
DB = g.connection
DB.extension(:connection_validator)
DB.extension(:advisory_locking)
end
end
end
And then use this DB somewhere in the app, for example as DB.advisory_lock('my_key') { do_stuff_with_lock }
But such constants define within a block looks not good
How to get connection instance in Hanami app?
There is config object in Hanami -- Hanami::Model.configuration
In fact it is the getter for #configuration instance variable
It is instance of Hanami::Model::Configuration and has such instance variables like #url, #entities, #logger and others. So it's possible to call getters to get them
It also has connection method. This method returns gateway.connection
And this gateway.connection is just what is needed. This is exactly the instance of connection to the database, on which you can call methods
For example
Hanami::Model.configuration.connection.advisory_lock('my_lock') do
# do stuff with lock
end
I want to note that all these methods are indicated by the comment # #api private. It means that their implementation may be changed in future versions.

Database connection too much with ActiveRecord::Base.establish_connection

I use multible databases with ActiveRecord. I must put establish_connection db in all models. But i want to call the connection of libraries file. While put establish_connection db in for all models Database connection count is too much . How can I do other methods?
My project is a Ruby on Sinatra.
Build a global hash of {db_name => connection_instance } for all possible connections you have and retrieve them from your models intelligently:
def get_or_establish_connection db
$connections[db] ||= establish_connection db
end
That way you’ll reuse all already established connections.
NB I wrote “global” because there is no way to suggest anything more robust without knowledge of your architecture details. In the real life one would put this hash as a class variable somewhere accessible from everywhere.
What we did in our projects that used multiple databases was creating one class per database, that establish the connection, and make models inherit from it. That way, only one connection is created per database.
class UsageTable < ActiveRecord::Base
self.abstract_class = true
establish_connection :usage
end
class User < UsageTable

Ruby sequel equivalent to ActiveRecord none

I'm looking for a way to replicate the behavior of none in Sequel. So far I haven't been able to find a way to create a dataset, or a dataset like thing, without tying it to a table.
At the moment I am just returning an enum but I would like to preserve the dataset API to not break any chaining.
E.g.
class User < Sequel::Model
end
User.none # => instance of dataset
Sequel has a null_dataset extension for this: http://sequel.jeremyevans.net/rdoc-plugins/files/lib/sequel/extensions/null_dataset_rb.html

ORM for Ruby that able to generate Model/Migration scripts from existing database

Is there ORM for Ruby that able to generate Model/Migration scripts from existing database?
i will use it with sinatra.
You can use Sequel's migrations to dump an existing schema (see "Dumping the current schema as a migration" down the linked page).
Also, I know that if you're on Postgresql or MS SQL Server you can dump the database into scripts, either as a schema or with data too. If the ORM you want to use doesn't have a to-migration facility (or even if it does) you can use those scripts, and even embed them within a migration (Sequel will accept standard SQL strings too, other ORM's probably can too).
Edit: generating models.
If you want to generate models, then Sequel has a reflection API. Something like this could get you started:
generator = ->(table) {
s = <<STR
require 'sequel'
class #{table} < Sequel::Model
# other stuff here
end
STR
}
DB.tables.reject{|name| name == :schema_info }
.each do |table|
File.new "app/models/#{table}.rb" do |f|
f.write generator.call(table)
end
end
To do the associations would be harder, but I think possible. Take a look at Database#foreign_key_list and Model association basics.
It's not an ORM, but there's a very old gem called magic_models which does this, not sure if it still works: http://magicmodels.rubyforge.org/

ActiveRecord 3.1.0 multiple databases

I'm trying to upgrade the ActiveRecord gem to the latest 3.1.0 release and seeing a lot of exceptions being raised, I think it's due to how we handle multiple databases.
For each of our databases we specify a separate base class which inherits from ActiveRecord::Base, and call establish_connection in there. There are no cross-database relations. This has worked fine for us up until now.
Having upgraded to ActiveRecord 3.1.0 I'm seeing that it fails with an ActiveRecord::ConnectionNotEstablished exception, when traversing relations (i.e. it will successfully pull a single entity or set of them from the DB, but fails when navigating to a related class).
The top line of the backtrace is C:/Ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.1.0/lib/active_record/connection_adapters/abstract/connection_pool.rb:410:in 'retrieve_connection', so I dug into this a little. The method is defined as follows:
def retrieve_connection(klass) #:nodoc:
pool = retrieve_connection_pool(klass)
(pool && pool.connection) or raise ConnectionNotEstablished
end
My simple test (puts Customer.first.address) calls retrieve_connection 3 times. Twice with Customer as the klass parameter, and once with ActiveRecord::Base as the parameter - which is when it fails as establish_connection has not been called for ActiveRecord::Base.
To the actual question then - is there a new recommended way of handling multiple database connections in ActiveRecord? If so, what is it?
If not, what could be causing this problem?
I ran into the same issue yesterday while upgrading to ActiveRecord 3.1.0. I can't speak to whether there is a new recommended way of handling multiple database connections in ActiveRecord 3.1, but I did find a way to unblock myself.
It appears a connection must now be established on ActiveRecord::Base in order for it to determine the table name lengths/rules of the adapter. Along with the rest of my connections established in my database initializer, I now also have an ActiveRecord::Base connection established to one of my DBs (it doesn't matter which one).
I'd like to think there's a better solution to be found, but I'm happy to be unblocked for now.
I am using this solution - What I was seeing was that when establish_connection was called in each of the OtherDb classes - there seemed to be alot of overhead reloading table definitions and I would randomly see issues every time the class def was reloaded.
# The idea here is to specify that a given model should use another
# database without having to change the entire inheritance hierarchy
# declare model for table in primary connection
class Bar < ActiveRecord::Base
# assume we have logic here that we don't want to refactor into a module
# but we do want to inherit in OtherDb::Bar
end
module Foo
# base model in Foo namespace - uses another db
class BaseConnection < ActiveRecord::Base
# OtherDb::Title.database contains a db config hash
# This would probably go in the initializers
establish_connection OtherDb::Title.database
end
# module used to override db connection
module OtherDb::Base
def retrieve_connection
# connection_handler.retrieve_connection(self) # normal behavior
connection_handler.retrieve_connection(Foo::BaseConnection) # use db from Foo::BaseConnection
end
end
# Foo::Bar is identical to ::Bar but is in another db
class Bar < ::Bar
extend OtherDb::Base
end
end

Resources