Cannot connect to two postgres databases in rails 3.2.

不羁岁月 提交于 2019-12-07 20:30:06

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!