问题
I've tried a few methods found on stack overflow for connecting to two database in rails two however non of them are working. Here's what I've got at the moment:
In the database.yml there's two connection settings:
development:
adapter: postgresql
host: localhost
database: blerg
username: postgres
encoding: utf8
production:
blah...
test: &test
blah...
cucumber:
<<: *test
static_api_development:
adapter: postgresql
host: localhost
database: blerg-static-api
username: postgres
encoding: utf8
static_api_production:
blah...
static_api_test:
blah...
And then I have lots of normal models in the rails app, but also the odd special model that need to connect to the other database, here's how I've set it up...
There is a module in the models folder called static_table.rb which has this content:
class StaticTable < ActiveRecord::Base
self.abstract_class = true
establish_connection "static_api_#{Rails.env}"
end
Then the special models that need the other tables have this:
class ContentItem < StaticTable
self.table_name = 'content_items'
end
However if you call ContentItem.all in a controller it says the 'content_items' table does not exist and the database connection is showing as 'blerg' not the 'blerg-static-api' which it should be.
Any help would be much appreciated thanks.
回答1:
Try to establish_connection
in ContentItem
too.
回答2:
My exemple of multiple database connections, may be it will help you. In my case I use crm_admin to get the companies information from our subdomains. Subdomains are individual apps running with their own database. Note! the database.yml might look strange, but it's generated automatically with YML when a subdomain is added or removed.
production:
adapter: postgresql
encoding: utf8
reconnect: false
database: crm_admin
username: username
password: passwrod
pool: 5
simtravel_crm:
adapter: postgresql
database: simtravel_crm_production
username: simtravel_username
password: simtravel_password
encoding: utf8
pool: 5
reconnect: 'false'
oktell_crm:
adapter: postgresql
database: oktell_crm_production
username: oktell_username
password: oktell_password
encoding: utf8
pool: 5
reconnect: 'false'
design_crm:
adapter: postgresql
database: design_crm_production
username: design_username
password: design_password
encoding: utf8
pool: 5
reconnect: 'false'
To get the companies from oktell_crm_production database:
app/models/oktell_crm.rb
class OktellCrm < ActiveRecord::Base
end
class OktellCompany < ActiveRecord::Base
establish_connection "oktell_crm"
set_table_name 'companies'
end
app/views/subdomains/_companies.html.erb
First I get the right model to load, in oktell case I'll have companies = OktellCompany.all
:
<%
model_name = ("#{@subdomain.name.downcase.capitalize}Company").singularize.classify.constantize
companies = model_name.all
%>
<div class="model">
<b>Companies in <%= @subdomain.name %> subdomain: <%= companies.count %></b>
<table>
<thead>
<tr>
<th>Name</th>
<th>Created at</th>
</tr>
</thead>
<tbody>
<% companies.each do |company| %>
<tr>
<td><%= company.name %></td>
<td><%= l company.created_at, format: :long %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
p.s. For the view part there must be a better solution but this was good enough for my needs.
回答3:
The issue is that inheritance doesn't work that way.
Consider the source of #establish_connection
:
def establish_connection(owner, spec)
@class_to_pool.clear
raise RuntimeError, "Anonymous class is not allowed." unless owner.name
owner_to_pool[owner.name] = ConnectionAdapters::ConnectionPool.new(spec)
end
(Let's suppose owner_to_pool
is actually @owner_to_pool
for simplicity.)
Inside the StaticTable class, you invoked establish_connection
within the class context. This updates @class_to_pool
and @owner_to_pool
, which are instance variables of StaticTable. (Some refer to these as class instance variables.) The accepted answer in this question goes into a detailed explanation.
The main problem is that even though ContentItem extends StaticTable, it does not inherit @class_to_pool
and @owner_to_pool
, and thus does not know that it should be establishing a connection to static_api_*
.
There are two ways to fix this. First, you can use establish_connection
in every model that should be using a static_api_*
connection. This is simple, but not DRY. A better way is to create a Rails concern and include it in the necessary models.
module StaticConnectionConcern
extend ActiveSupport::Concern
included do
establish_connection "static_api_#{Rails.env}"
end
end
Then in your models,
class ContentItem < ActiveRecord::Base
include StaticConnectionConcern
end
Using Rails concerns, when StaticConnectionConcern
is included in ContentItem
, whatever is inside the included
block is invoked in ContentItem
's class context. You can create a app/concerns
directory for concerns, and then tell Rails to autoload them by editing config/application.rb
:
config.autoload_paths += %W(#{Rails.root}/app/concerns)
I strongly recommend the second way. As your application grows and becomes more complex, the StaticConnectionConcern might grow to include other methods as well.
来源:https://stackoverflow.com/questions/17679573/cannot-connect-to-two-postgres-databases-in-rails-3-2