无法连接到rails 3.2中的两个postgres数据库。

时间:2013-07-16 14:39:45

标签: ruby-on-rails-3 postgresql database-connection multiple-databases

我已经尝试了一些在堆栈溢出上找到的方法来连接到rails 2中的两个数据库,但是没有它们正在工作。这就是我现在所拥有的:

在database.yml中有两个连接设置:

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...

然后我在rails应用程序中有很多普通模型,还有需要连接到其他数据库的奇怪特殊模型,这就是我如何设置它...

models文件夹中有一个名为static_table.rb的模块,其中包含以下内容:

class StaticTable < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "static_api_#{Rails.env}"
end

然后需要其他表的特殊模型具有:

class ContentItem < StaticTable
  self.table_name = 'content_items'
end

但是,如果在控制器中调用ContentItem.all,则表示'content_items'表不存在,并且数据库连接显示为'blerg'而不是'blerg-static-api'应该是。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:1)

尝试establish_connection中的ContentItem

答案 1 :(得分:1)

我的多个数据库连接的例子,可能会对你有帮助。在我的例子中,我使用crm_admin从我们的子域中获取公司信息。子域是使用自己的数据库运行的各个应用程序。 注意! database.yml可能看起来很奇怪,但是当添加或删除子域时,它会自动使用YML生成。

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'

从oktell_crm_production数据库获取公司:

应用/模型/ oktell_crm.rb

class OktellCrm < ActiveRecord::Base
end

class OktellCompany < ActiveRecord::Base
  establish_connection "oktell_crm"
  set_table_name 'companies'
end

应用/视图/子域/ _companies.html.erb

首先我要加载正确的模型,在oktell的情况下我会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。对于视图部分,必须有一个更好的解决方案,但这足以满足我的需求。

答案 2 :(得分:0)

问题在于继承不起作用。

考虑#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

(为简单起见,我们假设owner_to_pool实际上是@owner_to_pool。)

在StaticTable类中,您在类上下文中调用了establish_connection。这会更新@class_to_pool@owner_to_pool,它们是 StaticTable 的实例变量。 (有些人将这些称为类实例变量。)this question中接受的答案进入详细解释。

主要问题是即使ContentItem扩展了StaticTable,它也不会继承@class_to_pool@owner_to_pool,因此不知道它应该与static_api_*建立连接。 / p>

有两种方法可以解决这个问题。首先,您可以在应使用establish_connection连接的每个模型中使用static_api_*。这很简单,但不是DRY。更好的方法是创建Rails concern并将其包含在必要的模型中。

module StaticConnectionConcern
  extend ActiveSupport::Concern
  included do
    establish_connection "static_api_#{Rails.env}"
  end
end

然后在你的模特中,

class ContentItem < ActiveRecord::Base
  include StaticConnectionConcern
end

使用Rails问题,当StaticConnectionConcern中包含ContentItem时,included块中的任何内容都会在ContentItem的类上下文中调用。您可以为关注点创建一个app/concerns目录,然后通过编辑config/application.rb告诉Rails自动加载它们:

config.autoload_paths += %W(#{Rails.root}/app/concerns)

我强烈推荐第二种方式。随着应用程序的增长和变得越来越复杂,StaticConnectionConcern也可能会增长到包含其他方法。