Не удается подключиться к двум базам данных postgres в rails 3.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, а также странная специальная модель, которая должна подключаться к другой базе данных, вот как я ее настроил...

В папке моделей есть модуль с именем 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», каким оно должно быть.

Любая помощь будет высоко оценена спасибо.


person MintDeparture    schedule 16.07.2013    source источник
comment
WAG: кешированные данные о подключении? Может быть, имя БД должно быть в двойных кавычках?   -  person bma    schedule 18.07.2013


Ответы (3)


Попробуйте establish_connection и в ContentItem тоже.

person maniek    schedule 22.07.2013
comment
Этот на самом деле сработал, хотя это самый короткий ответ, лол. Большое спасибо! - person MintDeparture; 01.08.2013
comment
@rmagnum2002 rmagnum2002 Что ж, это правильный ответ, я пробовал другие, более длинные, но они немного отличаются и не работают. Этот однострочный ответ является точным. Я думаю, что некоторые очки уходят, может быть, половина, я вижу способ дать ему полную награду после того, как она истечет, или я бы так и сделал. :( - person MintDeparture; 05.08.2013

Мой пример нескольких подключений к базе данных, может быть, он вам поможет. В моем случае я использую 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

app/views/subdomains/_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. Для части просмотра должно быть лучшее решение, но этого было достаточно для моих нужд.

person rmagnum2002    schedule 24.07.2013

Проблема в том, что наследование так не работает.

Рассмотрим источник #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. (Некоторые называют их переменными экземпляра класса.) Принятый ответ в этот вопрос содержит подробное объяснение.

Основная проблема заключается в том, что хотя ContentItem расширяет StaticTable, он не наследует @class_to_pool и @owner_to_pool и, следовательно, не знает, что должен устанавливать соединение с static_api_*.

Есть два способа исправить это. Во-первых, вы можете использовать establish_connection в каждой модели, которая должна использовать соединение static_api_*. Это просто, но не СУХО. Лучше создать задачу Rails и включить ее в необходимые модели. .

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 для задач, а затем указать Rails автоматически загружать их, отредактировав config/application.rb:

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

Я настоятельно рекомендую второй способ. По мере того, как ваше приложение растет и становится более сложным, StaticConnectionConcern может включать и другие методы.

person James Lim    schedule 25.07.2013