Dynamic Database Connections

Hey everyone! I have a problem that’s been making me a little nuts.
I would like to use RoR for a upcoming project, but if I can’t get
past this hiccup I’m
afraid I’ll have to use PHP or Java. Ugh.

The application needs to have a database-per-customer model. So when
I do a Product.find(:all) I need to make sure i’m connecting to say
acme.products and not xyz_company.products.

I toyed around with the magic_multi_connections gem but I’m having
trouble getting it to work without knowing the connection up front.

In the examples it shows how to connect when you know which db you’ll
need … in their example :Private.

I attempted to look at the code, but there is some meta programming
stuff in there that is beyond my newb level i’m afraid.

The other problem with the magic_multi is that if there are 140
customers then I need 140 modules added in the environment.rb. That
doesn’t sound fun!

If anyone has done something like that and can’t get me started I’d be
so grateful!

And please, if I wasn’t clear enough, ask me to elaborate rather than
ignoring the post. I only have a couple more days to decide which
language to use, and i’d really like to go with Ruby and Rails.

jmamma wrote:

Hey everyone! I have a problem that’s been making me a little nuts.
I would like to use RoR for a upcoming project, but if I can’t get
past this hiccup I’m
afraid I’ll have to use PHP or Java. Ugh.

check out data_fabric gem
http://www.codefutures.com/database-sharding/ and check this article

Thanks Amar. Sharding isn’t exactly what I need here, but some
interesting info nonetheless.

I have a main db ( users, applications, etc ) and a database for each
customer ( products, orders, etc )

When I want to get all the products, for example, I need to connect
to
a particular customers version of products. I can do it by using
ActiveRecord::Base.establish_connection (:connection_name) in the
controller
but its not perfect… also there are some plugins that use some
activeRecord
stuff in them and the model doesn’t know which db its supposed to
connect to
so I have to modify all those gems and put the establish_connection in
there too.

I put the customer in session on user login, and then I can easily get
which customer
db I need, but again that doesn’t work so well in the models since the
session isn’t
easily available in the models.

On Nov 2, 7:12 am, Amar D. [email protected]

The usual trick in situations like this is to use a thread-local
variable, set in the controller action and accessed from the models.
It’s a somewhat leaky abstraction, but probably the most reliable way
to do things (ActiveSupport uses it for the Time.zone stuff). The code
would look like (sketch):

in application_controller.rb (or elsewhere):

before_filter :set_customer_db

def set_customer_db
Thread.current[:customer_db] = …
end

I can’t think of how exactly you’ll end up accessing it in the models,
but the magic_multi_connections gem should provide some guidance.

–Matt J.

Thanks for your suggestion Matt. I’ll look into it a bit and see if
it will work. I’m not stuck
on using the magic_multi_connections at this point. I’d go with an
easier way if I could figure it out.
I tinkered with just having a method in the application_controller
that sets the connection via establish_connection
( from a value in session ), and it seems to work okay. Its just a
little clunky in a few parts and it doesn’t solve
the problem when you need to make a db call in the model ( or some
plugin tries to use a model find(:all) or something ).

Marnen - We need a db per customer for a few reasons. It will keep
the clients data separate ( some of them are weird like that about
their data, and require us to separate ), and also a particular
customer could have a customer feature they purchase that won’t make
sense
for all clients. That feature will cause for extra tables or columns
in that particular customers db that won’t be spread to everyone.

Also, this way we can easily backup a particular customer, or grab a
customer’s db a dump it on our local machine
really quick and test with their data, rather than pulling down a
giant db.

And finally, we can take down a particular customer rather easy and
not affect anyone else.

I’m in some ways trying to convince myself that its a good thing to do
as well, since I don’t have much choice in the matter haha! Thanks
for the input though!

jmamma wrote:
[…]

Marnen - We need a db per customer for a few reasons. It will keep
the clients data separate ( some of them are weird like that about
their data, and require us to separate ), and also a particular
customer could have a customer feature they purchase that won’t make
sense
for all clients. That feature will cause for extra tables or columns
in that particular customers db that won’t be spread to everyone.

None of these are good reasons to have a DB per customer, IMHO. These
are all easily achieved with one DB. As far as your clients’
requirements, the structure of the DB is really not any of their
business, and they are being unreasonable if they are trying to dictate
your implementation.

Also, this way we can easily backup a particular customer, or grab a
customer’s db a dump it on our local machine
really quick and test with their data, rather than pulling down a
giant db.

You should be able to dump a subset without too much trouble.

And finally, we can take down a particular customer rather easy and
not affect anyone else.

Again, easy with one DB.

I’m in some ways trying to convince myself that its a good thing to do
as well, since I don’t have much choice in the matter haha!

Not a laughing matter. If you don’t have control over DB design, find
another project. You’ve apparently been stuck with asinine
requirements.

Thanks
for the input though!

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

jmamma wrote:

Hey everyone! I have a problem that’s been making me a little nuts.
I would like to use RoR for a upcoming project, but if I can’t get
past this hiccup I’m
afraid I’ll have to use PHP or Java. Ugh.

The application needs to have a database-per-customer model.
[…]

Why does it “need” to have a database per customer? There’s usually no
reason for that sort of thing. In most cases, you really just want one
big DB. Can you explain more about what’s going on?

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Hi again Marnen. I think we’re a little off topic.
The problem at hand is connecting to multiple databases, not
poo poo’ing on the requirements haha!

Thanks again for your input though! All thoughts are welcome.

On Nov 2, 5:49 pm, Marnen Laibow-Koser <rails-mailing-l…@andreas-

jmamma wrote:

Hi again Marnen. I think we’re a little off topic.
The problem at hand is connecting to multiple databases, not
poo poo’ing on the requirements haha!

As Colin said, it is entirely appropriate to question the requirements
here. You’re making your life difficult with these requirements, and
you don’t seem to have a particularly good reason for them, so why keep
them?

Thanks again for your input though! All thoughts are welcome.

If you really mean that, then please give my suggestions some serious
consideration.

On Nov 2, 5:49�pm, Marnen Laibow-Koser <rails-mailing-l…@andreas-

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

2009/11/3 jmamma [email protected]:

Hi again Marnen. Â I think we’re a little off topic.
The problem at hand is connecting to multiple databases, not
poo poo’ing on the requirements haha!

Very often the solution to a problem is to change the approach so that
the problem does not exist in the first place, rather than code around
a tricky issue. To suggest such alternatives here is entirely valid.
In a particular instance there may be a good reason for using the
problematic approach of course.

Colin