문제

We have a primary database where all of our app resides.

But there's a second database (updated from an external source), that I'd like to be able to connect to so I can pull data from it. I don't need to write anything...just read.

It also only has one table that I'm pulling from.

I really just need to do something like:

OtherDatabase.articles.where(id > 1000)

And that's it.

So how can I do this in Rails (running 3.2.13)?

도움이 되었습니까?

해결책

For simple scenarios, Rails can support this without any extra gems; simply define the database in database.yml:

other_db:
  adapter: mysql2
  encoding: utf8
  database: other_db
  username: user
  password: passwd
  host: 1.2.3.4
  port: 3306

Then in the model you want to use the other database add:

class Article < ActiveRecord::Base
  establish_connection(:other_db)
  self.table_name = 'other_db.articles'
end

And then you can perform your query:

Article.where("id > 1000")

=)

다른 팁

Firstly, we need to define the external database:

# config/database.yml
external:
  adapter: sqlite3
  database: db/external.sqlite3
  pool: 5
  timeout: 5000

For something like this, I prefer using a module that takes care of database connections.

# lib/database.rb
module Database
  def self.using(db, klass=ActiveRecord::Base)
    klass.establish_connection(db.to_sym)
    result = yield if block_given?
    klass.establish_connection(Rails.env.to_sym)
    result
  end
end

By passing a block to a module like this we can make sure we don't bleed our queries into a database where they don't belong or forget to revert our connection. Also, we default to ActiveRecord::Base so that we can work with any of our models. However, if we know we're only using one and want to isolate our model usage, we can pass it as the secondary parameter.

The resulting implementation can look something like this:

# app/models/user.rb
class User < ActiveRecord::Base
  def read_remote
    Database.using(:external) do
      account = Account.where(active: true)
      account.users
    end
  end
end

Now we have a nice and clean block we can use anywhere we like, use any models we want inside the block and always be operating on the extneral database. Once that block is finished, we know we're working back on our original database.

Copy/Paste:

For a single-master situation, you could define another database connection in database.yml for the read slave:

read_slave:
  adapter: postgresql
  database: read_only_production
  username: user
  password: pass
  host: read_slave_host

This database is backed by a module, which mirrors the ActiveRecord classes using this database connection:

require 'magic_multi_connections'
module ReadSlave
  establish_connection :read_slave
end

Now, all pre-existing models can be accessed through the read_slave connection by prefixing the model class with ReadSlave::.

# use the read-only connection
    @user = ReadSlave::User.find(params[:id])

    # write to the master (can't use @user.update_attributes because it would#
    try to write to the read slave)
    User.update(@user.id, :login => "new_login")
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top