├── .customink └── catalog.yaml ├── .github └── CODEOWNERS ├── .gitignore ├── .ruby-gemset ├── .ruby-version ├── .travis.yml ├── .yardopts ├── Appraisals ├── CHANGELOG.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── VERSION ├── gemfiles ├── rails50.gemfile └── rails51.gemfile ├── lib ├── rails │ └── second_base │ │ └── generators │ │ └── migration_generator.rb ├── second_base.rb ├── second_base │ ├── base.rb │ ├── databases.rake │ ├── databases_rails_five.rake │ ├── databases_rails_four.rake │ ├── forced.rb │ ├── on_base.rb │ ├── railtie.rb │ ├── test_help.rb │ └── version.rb └── secondbase.rb ├── secondbase.gemspec └── test ├── cases ├── dbtask_test.rb ├── forced_test.rb ├── generator_test.rb ├── on_base_test.rb ├── railtie_test.rb └── rake_test.rb ├── dummy_apps ├── rails_five │ ├── Rakefile │ ├── app │ │ ├── controllers │ │ │ └── application_controller.rb │ │ ├── helpers │ │ │ └── application_helper.rb │ │ └── models │ │ │ ├── application_record.rb │ │ │ ├── comment.rb │ │ │ ├── comment_forced.rb │ │ │ ├── post.rb │ │ │ └── user.rb │ ├── bin │ │ └── rails │ ├── config │ │ ├── database.yml │ │ ├── init.rb │ │ └── routes.rb │ ├── db │ │ ├── migrate │ │ │ ├── 20141209165002_create_users.rb │ │ │ └── 20141214142700_create_posts.rb │ │ ├── schema_cache.yml │ │ └── secondbase │ │ │ ├── migrate │ │ │ └── 20151202075826_create_comments.rb │ │ │ └── schema_cache.yml │ ├── log │ │ └── .keep │ └── tmp │ │ └── .keep └── rails_four │ ├── Rakefile │ ├── app │ ├── controllers │ │ └── application_controller.rb │ ├── helpers │ │ └── application_helper.rb │ └── models │ │ ├── comment.rb │ │ ├── comment_forced.rb │ │ ├── post.rb │ │ └── user.rb │ ├── bin │ └── rails │ ├── config │ ├── database.yml │ └── routes.rb │ ├── db │ ├── migrate │ │ ├── 20141209165002_create_users.rb │ │ └── 20141214142700_create_posts.rb │ └── secondbase │ │ └── migrate │ │ └── 20151202075826_create_comments.rb │ ├── init.rb │ ├── log │ └── .keep │ └── tmp │ └── .keep ├── test_helper.rb └── test_helpers ├── dummy_app_helpers.rb ├── rails_version_helpers.rb └── stream_helpers.rb /.customink/catalog.yaml: -------------------------------------------------------------------------------- 1 | name: secondbase 2 | 3 | owner: principal_engineers # team definitions at https://app.opslevel.com/teams 4 | 5 | purpose: # multiple choice 6 | # - do_not_track # demo testing personal - will not be tracked in catalog 7 | # - app 8 | - library 9 | # - configuration 10 | # - other # example: frontend_dataset 11 | deployment_type: # multiple choice 12 | # - kubernetes 13 | # - infrastructure_serverless 14 | - package 15 | # - cli 16 | # - data 17 | # - docker-image 18 | 19 | # tier: tier_1 # Mission-critical service or repository. Failure could result in significant impact to revenue or reputation. 20 | # tier: tier_2 # Customer-facing service or repository. Failure results in degraded experience for customers, although without significant impact to revenue or reputation. 21 | # tier: tier_3 # Internal service or repository. Failure could result in productivity being compromised within the company. 22 | # tier: tier_4 # Other service or repository. Failure doesn't result in immediate or significant impact. 23 | tier: tier_na # this repo does not have a tier. typically libraries 24 | 25 | properties: 26 | public_facing: false 27 | pci: false 28 | pii: false 29 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | @customink/architecture-forum 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | doc/ 2 | yard/ 3 | .yardoc/ 4 | vendor/ 5 | pkg/ 6 | .bundle/ 7 | Gemfile.lock 8 | *.gemfile.lock 9 | *.log 10 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | secondbase 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.3.1 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | cache: bundler 3 | rvm: 4 | - 2.5.3 5 | services: 6 | - mysql 7 | gemfile: 8 | - gemfiles/rails50.gemfile 9 | - gemfiles/rails51.gemfile 10 | - gemfiles/rails52.gemfile 11 | - gemfiles/rails60.gemfile 12 | install: 13 | - gem install bundler 14 | - bundle --version 15 | - bundle install 16 | script: 17 | - bundle exec rake test 18 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --exclude test/**/*.rb 2 | -------------------------------------------------------------------------------- /Appraisals: -------------------------------------------------------------------------------- 1 | appraise 'rails40' do 2 | gem 'rails', '~> 4.0.0' 3 | gem 'mysql' 4 | end 5 | 6 | appraise 'rails41' do 7 | gem 'rails', '~> 4.1.0' 8 | gem 'mysql' 9 | end 10 | 11 | appraise 'rails42' do 12 | gem 'rails', '~> 4.2.0' 13 | gem 'mysql' 14 | end 15 | 16 | appraise 'rails50' do 17 | gem 'rails', '~> 5.0.0' 18 | gem 'mysql2' 19 | end 20 | 21 | appraise 'rails51' do 22 | gem 'rails', '~> 5.1.0' 23 | gem 'mysql2' 24 | end 25 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | Please follow the format set down in http://keepachangelog.com 4 | 5 | ## v2.2.0 6 | 7 | - Added `structure:dump` task. Thanks @shqear93 8 | 9 | ## v2.1.6 10 | 11 | - Descriptions for Rake tasks. Fixes #60. Thanks @roolo. 12 | 13 | ## v2.1.5 14 | 15 | - Allow custom db paths to work. Fixes #51 #52. Thanks @MrJoy. 16 | 17 | ## v2.1.4 18 | 19 | - Rails v5.1 support. 20 | 21 | ## v2.1.3 22 | 23 | #### Fixed 24 | 25 | - Issue with explicit secondbase tasks not loading config. Fixes #43 26 | 27 | ## v2.1.2 28 | 29 | #### Changed 30 | 31 | - Tested w Rails 5.0 release. 32 | 33 | #### Added 34 | 35 | - Support for schema cache. Fixes #40 36 | 37 | ## v2.1.1 38 | 39 | #### Changed 40 | 41 | - Test updates to track rails 5 rc2. 42 | 43 | ## v2.1.0 44 | 45 | #### Added 46 | 47 | - Ability to disable the database task patching (thanks [@agrberg](https://github.com/agrberg)) 48 | 49 | ## v2.0.0 50 | 51 | #### Added 52 | 53 | - Rails 5 support. 54 | 55 | ## v1.0.1 56 | 57 | #### Fixed 58 | 59 | - Fix base Rails migration generator. Fixes #25. 60 | 61 | ## v1.0 62 | 63 | Initial re-write supporting Rails 4.x. Please see README.md for full details. 64 | 65 | ## v0.6 66 | 67 | Support for Rails 3.x. For 2.x support, check out the branch `rails_2_3` or version v0.5 of the gem. 68 | 69 | #### Fixed 70 | 71 | - The `has_and_belongs_to_many` associations, for SecondBase models. 72 | - Patched `ActiveRecord::TestFixtures` so that transactional fixture support is respected for the SecondBase. 73 | - Reorganized monkey patches to make it easier to work in fixes for different versions of Rails. 74 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | gemspec 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Karle Durante 2 | Copyright (c) 2016 CustomInk.com 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Gem Version](https://badge.fury.io/rb/secondbase.png)](http://badge.fury.io/rb/secondbase) 2 | 3 | 4 | 5 | ## ⚠️ SecondBase - Deprecated for Rails 6+ 6 | 7 | ![SecondBase Logo](https://cloud.githubusercontent.com/assets/2381/12219457/5a5aab4e-b712-11e5-92e1-de6487aa0809.png) 8 | 9 | Note: This project is deprecated for Rails 6 and higher versions. 10 | SecondBase provided seamless second database integration for Rails applications prior to Rails 6. However, with the release of Rails 6.0, built-in support for multiple databases was introduced as a core feature. For current Rails versions, it is recommended to use the official multiple database support instead of this gem. For information on using multiple databases in Rails 6+, please refer to: 11 | 12 | * [Multiple Databases with Active Record (Rails Guides)](https://guides.rubyonrails.org/active_record_multiple_databases.html) 13 | * [Rails 6.0 Release Notes - Multiple Databases](https://edgeguides.rubyonrails.org/6_0_release_notes.html#multiple-databases) 14 | 15 | If you're using Rails 5.x or earlier, you may still find SecondBase useful. However, we encourage upgrading to the latest Rails version to take advantage of native multiple database support and ongoing maintenance. 16 | 17 | Seamless second database integration for Rails. SecondBase provides support for Rails to manage dual databases by extending ActiveRecord tasks that create, migrate, and test your databases. 18 | * [Using SecondBase To Provide Some Level Of Sanity](http://technology.customink.com/blog/2016/01/10/two-headed-cat-using-secondbase-to-provide-some-level-of-sanity-in-a-two-database-rails-application/) 19 | 20 | * [Rails Multi-Database Best Practices Roundup](http://technology.customink.com/blog/2015/06/22/rails-multi-database-best-practices-roundup/) 21 | 22 | 23 | ## Usage 24 | 25 | To get started with your new second database, update your database.yml to include a `secondbase` config key. All SecondBase configurations per Rails environment go under this config key. 26 | 27 | ```yaml 28 | # Default configurations: 29 | development: 30 | adapter: sqlserver 31 | database: myapp_development 32 | test: 33 | adapter: sqlserver 34 | database: myapp_test 35 | # SecondBase configurations: 36 | secondbase: 37 | development: 38 | adapter: mysql 39 | database: myapp_development 40 | test: 41 | adapter: mysql 42 | database: myapp_test 43 | ``` 44 | 45 | #### Database Tasks 46 | 47 | SecondBase aims to work seamlessly within your Rails application. When it makes sense, we run a mirrored `db:second_base` task for matching ActiveRecord base database task. These can all be deactivated by setting `config.second_base.run_with_db_tasks = false` in your Application's configuration. For example: 48 | 49 | ```shell 50 | $ rake db:create 51 | ``` 52 | 53 | This will not only create your base development database, but it will also create your second database as specified by the configuration within the `:secondbase` section of your database.yml. Below is a complete list of `:db` tasks that automatically run a mirrored `:db:second_base` task. Some private or over lapping tasks, like schema dump/loading or `db:setup`, are not listed. 54 | 55 | * db:create 56 | * db:create:all 57 | * db:drop 58 | * db:drop:all 59 | * db:purge 60 | * db:purge:all 61 | * db:migrate 62 | * db:test:purge 63 | * db:test:prepare 64 | * db:schema:cache:dump 65 | 66 | Not all base database tasks make sense to run a mirrored SecondBase task. These include tasks that move a single migration up/down, reporting on your database's current status/version, and others. These tasks have to be run explicitly and only operate on your SecondBase database. Each support any feature that their matching `:db` task has. For example, using `VERSION=123` to target a specific migration. 67 | 68 | * db:second_base:migrate:up 69 | * db:second_base:migrate:down 70 | * db:second_base:migrate:reset 71 | * db:second_base:migrate:redo 72 | * db:second_base:migrate:status 73 | * db:second_base:rollback 74 | * db:second_base:forward 75 | * db:second_base:version 76 | 77 | #### Migration Generator 78 | 79 | SecondBase migrations are stored in your application's `db/secondbase/migrate` directory. Likewise, SecondBase will also dump your schema/structure file into the `db/secondbase` directory. Full support for ActiveRecord's schema format being set to either `:ruby` or `:sql` is supported. 80 | 81 | Migrations can be generated using the `second_base:migration` name. Our generator is a subclass of ActiveRecord's. This means the SecondBase migration generator supports whatever features and arguments are supported by your current Rails version. For example: 82 | 83 | ```shell 84 | $ rails generate second_base:migration CreateWidgetsTable 85 | $ rails generate second_base:migration AddTitleBodyToPost title:string body:text 86 | ``` 87 | 88 | #### Models 89 | 90 | Any model who's table resides in your second database needs to inherit from `SecondBase::Base`. ActiveRecord associations will still work between your base ActiveRecord and SecondBase models! 91 | 92 | ```ruby 93 | class Widget < SecondBase::Base 94 | 95 | end 96 | 97 | class User < ActiveRecord::Base 98 | has_many :widgets 99 | end 100 | ``` 101 | 102 | #### Forced Connections 103 | 104 | Sometimes you want to force a model that inherits from `ActiveRecord::Base` to use the `SecondBase::Base` connection. Using the `SecondBase::Forced` module is a great way to accomplish this. By using this module, we do all the work to ensure the connection, management, and pool are properly freedom patched. 105 | 106 | We recomend forcing modules using a Rails initializer. This example below forces both the [DelayedJob ActiveRecord Backend](https://github.com/collectiveidea/delayed_job_active_record) and ActiveRecord session store to use your SecondBase database. 107 | 108 | ```ruby 109 | # In config/initializers/second_base.rb 110 | Delayed::Backend::ActiveRecord::Job.extend SecondBase::Forced 111 | ActiveRecord::SessionStore::Session.extend SecondBase::Forced 112 | ``` 113 | 114 | #### Testing & DB Synchronization 115 | 116 | Rails 4.2 brought about a new way to keep your test database in sync by checking schema migrations. Where previously forcing a full test database schema load, Rails 4.2 and up is able to run your tests much faster. In order for SecondBase to take advantage of this, you will need to include our test help file directly following the Rails one. Open your `test_helper.rb` and add our `second_base/test_help` after `rails/test_help`. 117 | 118 | ```ruby 119 | ENV["RAILS_ENV"] = "test" 120 | require File.expand_path('../../config/environment', __FILE__) 121 | require 'rails/test_help' 122 | require 'second_base/test_help' 123 | ``` 124 | 125 | #### Configurations 126 | 127 | All SecondBase railtie settings are best done in a `config/application.rb` file. We support the following configurations: 128 | 129 | ```ruby 130 | config.second_base.path # Default: 'db/secondbase' 131 | config.second_base.config_key # Default: 'secondbase' 132 | ``` 133 | 134 | * `path` - Used as location for migrations & schema. Path is relative to application root. 135 | * `config_key` - The key to in database.yml/configurations to search for SecondBase configs. 136 | 137 | 138 | ## Advanced Usage 139 | 140 | #### Twelve-Factor & DATABASE_URL 141 | 142 | We love the [Twelve Factors](http://12factor.net) principals and using tools like Dotenv with Rails. Using SecondBase does not mean you have to abandon these best practices. You will however need to take advantage of a [new feature](https://github.com/rails/rails/pull/14633) in Rails 4.1 and upward that allows database.yml configurations to leverage a `:url` key that will resolve and merge the same connection string format consumed by `DATABASE_URL`. For example: 143 | 144 | ```yaml 145 | development: 146 | database: encom-pg_development 147 | url: <%= ENV.fetch('DATABASE_URL') %> 148 | test: 149 | database: encom-pg_test 150 | url: <%= ENV.fetch('DATABASE_URL') %> 151 | production: 152 | url: <%= ENV.fetch('DATABASE_URL') %> 153 | 154 | secondbase: 155 | development: 156 | database: encom-mysql_development 157 | url: <%= ENV.fetch('DATABASE_URL_SECONDBASE') %> 158 | test: 159 | database: encom-mysql_test 160 | url: <%= ENV.fetch('DATABASE_URL_SECONDBASE') %> 161 | production: 162 | url: <%= ENV.fetch('DATABASE_URL_SECONDBASE') %> 163 | ``` 164 | 165 | There are many ways to use Dotenv and enviornment variables. This is only one example and we hope it helps you decide on which is best for you. 166 | 167 | #### The ActiveRecord Query Cache 168 | 169 | Rails only knows about your base connection for the Rack-based query cache. In order to take advantage of this feature for your SecondBase, you will need to set an arround filter in your controller. 170 | 171 | ```ruby 172 | class ApplicationController < ActionController::Base 173 | around_filter :query_cache_secondBase 174 | private 175 | def query_cache_secondBase 176 | SecondBase::Base.connection.cache { yield } 177 | end 178 | end 179 | ``` 180 | 181 | ## Versions 182 | 183 | The current master branch is for Rails v4.0.0 and up and. We have older work in previous v1.0 releases which partial work for Rails 3.2 or lower. These old versions are feature incomplete and are not supported. 184 | 185 | 186 | ## Contributing 187 | 188 | We use the [Appraisal](https://github.com/thoughtbot/appraisal) gem from Thoughtbot to help us test different versions of Rails. The `rake appraisal test` command actually runs our test suite against all Rails versions in our `Appraisal` file. So after cloning the repo, running the following commands. 189 | 190 | ```shell 191 | $ bundle install 192 | $ bundle exec appraisal update 193 | $ bundle exec appraisal rake test 194 | ``` 195 | 196 | If you want to run the tests for a specific Rails version, use one of the appraisal names found in our `Appraisals` file. For example, the following will run our tests suite for Rails 4.1.x. 197 | 198 | ```shell 199 | $ bundle exec appraisal rails41 rake test 200 | ``` 201 | 202 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rake/testtask' 3 | 4 | Rake::TestTask.new do |t| 5 | t.libs = ['lib','test'] 6 | t.test_files = FileList['test/**/*_test.rb'] 7 | t.verbose = true 8 | end 9 | 10 | desc "Bootstrap development/test DB setup." 11 | task :bootstrap do 12 | # ENV['DATBASE_URL'] = 'mysql://root@localhost/secondbase_url' 13 | require_relative './test/dummy_app/init' 14 | require_relative './test/test_helpers/dummy_app_helpers' 15 | include SecondBase::DummyAppHelpers 16 | # dummy_root = File.expand_path "#{__dir__}/test/dummy_app" 17 | Dir.chdir(dummy_root) { `rake db:create` } 18 | delete_dummy_files 19 | end 20 | 21 | task :default do 22 | Kernel.system 'appraisal update' 23 | Kernel.system 'appraisal rake test' 24 | end 25 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 2.2.0 2 | -------------------------------------------------------------------------------- /gemfiles/rails50.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "rails", "~> 5.0.0" 6 | gem "mysql2" 7 | 8 | gemspec path: "../" 9 | -------------------------------------------------------------------------------- /gemfiles/rails51.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "rails", "~> 5.1.0" 6 | gem "mysql2" 7 | 8 | gemspec path: "../" 9 | -------------------------------------------------------------------------------- /lib/rails/second_base/generators/migration_generator.rb: -------------------------------------------------------------------------------- 1 | require 'rails/generators' 2 | require 'rails/generators/active_record' 3 | require 'rails/generators/active_record/migration/migration_generator' 4 | 5 | module SecondBase 6 | class MigrationGenerator < ActiveRecord::Generators::MigrationGenerator 7 | 8 | source_root ActiveRecord::Generators::MigrationGenerator.source_root 9 | 10 | def self.desc 11 | require 'rails/generators/rails/migration/migration_generator' 12 | Rails::Generators::MigrationGenerator.desc 13 | end 14 | 15 | include(Module.new{ 16 | 17 | def migration_template(*args) 18 | path = Pathname 19 | .new(Rails.application.config.paths['db/migrate'].first) 20 | .relative_path_from(Rails.root) 21 | .to_s 22 | args[1].sub! path, "#{Railtie.config_path}/migrate" if args[1] 23 | super(*args) 24 | end 25 | 26 | }) 27 | 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/second_base.rb: -------------------------------------------------------------------------------- 1 | require 'rails' 2 | require 'active_record' 3 | require 'active_record/railtie' 4 | require 'second_base/version' 5 | require 'second_base/railtie' 6 | require 'second_base/on_base' 7 | require 'second_base/forced' 8 | 9 | module SecondBase 10 | 11 | extend ActiveSupport::Autoload 12 | 13 | autoload :Base 14 | 15 | def self.config(env = nil) 16 | config = Rails.application.config.database_configuration[Railtie.config_key] 17 | config ? config[env || Rails.env] : nil 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /lib/second_base/base.rb: -------------------------------------------------------------------------------- 1 | module SecondBase 2 | class Base < ActiveRecord::Base 3 | 4 | self.abstract_class = true 5 | establish_connection SecondBase.config 6 | 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/second_base/databases.rake: -------------------------------------------------------------------------------- 1 | namespace :db do 2 | namespace :second_base do 3 | 4 | namespace :create do 5 | desc 'Creates ALL DBs configured for Second base' unless SecondBase::Railtie.run_with_db_tasks? 6 | task :all => ['db:load_config'] do 7 | SecondBase.on_base { Rake::Task['db:create:all'].execute } 8 | end 9 | end 10 | 11 | desc 'Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:secondbase:create:all to create all databases in the config). Without RAILS_ENV it defaults to creating the development and test databases.' unless SecondBase::Railtie.run_with_db_tasks? 12 | task :create => ['db:load_config'] do 13 | SecondBase.on_base { Rake::Task['db:create'].execute } 14 | end 15 | 16 | namespace :drop do 17 | desc 'Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:secondbase:drop:all to drop all databases in the config). Without RAILS_ENV it defaults to dropping the development and test databases.' unless SecondBase::Railtie.run_with_db_tasks? 18 | task :all => ['db:load_config'] do 19 | SecondBase.on_base { Rake::Task['db:drop:all'].execute } 20 | end 21 | end 22 | 23 | namespace :purge do 24 | desc 'Purges (empties) ALL DBs configured for Second base' unless SecondBase::Railtie.run_with_db_tasks? 25 | task :all => ['db:load_config'] do 26 | SecondBase.on_base { Rake::Task['db:purge:all'].execute } 27 | end 28 | end 29 | 30 | desc 'Empty the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:secondbase:drop:all to drop all databases in the config). Without RAILS_ENV it defaults to purging the development and test databases.' unless SecondBase::Railtie.run_with_db_tasks? 31 | task :purge => ['db:load_config'] do 32 | SecondBase.on_base { Rake::Task['db:purge'].execute } 33 | end 34 | 35 | desc 'Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog).' unless SecondBase::Railtie.run_with_db_tasks? 36 | task :migrate => ['db:load_config'] do 37 | SecondBase.on_base { Rake::Task['db:migrate'].execute } 38 | end 39 | 40 | namespace :migrate do 41 | 42 | desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).' unless SecondBase::Railtie.run_with_db_tasks? 43 | task :redo => ['db:load_config'] do 44 | SecondBase.on_base { Rake::Task['db:migrate:redo'].execute } 45 | end 46 | 47 | desc 'Runs the "up" for a given migration VERSION.' 48 | task :up => ['db:load_config'] do 49 | SecondBase.on_base { Rake::Task['db:migrate:up'].execute } 50 | end 51 | 52 | desc 'Runs the "down" for a given migration VERSION.' 53 | task :down => ['db:load_config'] do 54 | SecondBase.on_base { Rake::Task['db:migrate:down'].execute } 55 | end 56 | 57 | desc 'Display status of migrations' 58 | task :status => ['db:load_config'] do 59 | SecondBase.on_base { Rake::Task['db:migrate:status'].execute } 60 | end 61 | 62 | end 63 | 64 | desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).' 65 | task :rollback => ['db:load_config'] do 66 | SecondBase.on_base { Rake::Task['db:rollback'].execute } 67 | end 68 | 69 | desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.' 70 | task :forward => ['db:load_config'] do 71 | SecondBase.on_base { Rake::Task['db:forward'].execute } 72 | end 73 | 74 | task :abort_if_pending_migrations do 75 | SecondBase.on_base { Rake::Task['db:abort_if_pending_migrations'].execute } 76 | end 77 | 78 | desc 'Retrieves the current schema version number' 79 | task :version => ['db:load_config'] do 80 | SecondBase.on_base { Rake::Task['db:version'].execute } 81 | end 82 | 83 | namespace :schema do 84 | # desc 'Load a schema.rb file into the database' unless SecondBase::Railtie.run_with_db_tasks? 85 | task :load => ['db:load_config'] do 86 | SecondBase.on_base { Rake::Task['db:schema:load'].execute } 87 | end 88 | 89 | namespace :cache do 90 | desc 'Create a db/schema_cache.dump file.' unless SecondBase::Railtie.run_with_db_tasks? 91 | task :dump => ['db:load_config'] do 92 | SecondBase.on_base { Rake::Task['db:schema:cache:dump'].execute } 93 | end 94 | 95 | end 96 | 97 | end 98 | 99 | namespace :structure do 100 | # desc 'Recreate the databases from the structure.sql file' unless SecondBase::Railtie.run_with_db_tasks? 101 | task :load => ['db:load_config'] do 102 | SecondBase.on_base { Rake::Task['db:structure:load'].execute } 103 | end 104 | 105 | # desc 'Dumps the databases to structure.sql file' 106 | task :dump => ['db:load_config'] do 107 | SecondBase.on_base { Rake::Task['db:structure:dump'].execute } 108 | end 109 | 110 | end 111 | 112 | namespace :test do 113 | desc 'Empty the test database' unless SecondBase::Railtie.run_with_db_tasks? 114 | task :purge => ['db:load_config'] do 115 | SecondBase.on_base { Rake::Task['db:test:purge'].execute } 116 | end 117 | 118 | # desc 'Recreate the test database from an existent schema.rb file' unless SecondBase::Railtie.run_with_db_tasks? 119 | task :load_schema => ['db:load_config'] do 120 | SecondBase.on_base { Rake::Task['db:test:load_schema'].execute } 121 | end 122 | 123 | # desc 'Recreate the test database from the current schema' unless SecondBase::Railtie.run_with_db_tasks? 124 | task :load_structure => ['db:load_config'] do 125 | SecondBase.on_base { Rake::Task['db:test:load_structure'].execute } 126 | end 127 | 128 | desc 'Check for pending migrations and load the test schema' unless SecondBase::Railtie.run_with_db_tasks? 129 | task :prepare => ['db:load_config'] do 130 | SecondBase.on_base { Rake::Task['db:test:prepare'].execute } 131 | end 132 | 133 | end 134 | 135 | end 136 | end 137 | 138 | %w{ 139 | create:all create drop:all purge:all purge 140 | migrate migrate:status abort_if_pending_migrations 141 | schema:load schema:cache:dump structure:load structure:dump 142 | test:purge test:load_schema test:load_structure test:prepare 143 | }.each do |name| 144 | task = Rake::Task["db:#{name}"] rescue nil 145 | next unless task && SecondBase::Railtie.run_with_db_tasks? 146 | task.enhance do 147 | Rake::Task["db:load_config"].invoke 148 | Rake::Task["db:second_base:#{name}"].invoke 149 | end 150 | end 151 | -------------------------------------------------------------------------------- /lib/second_base/databases_rails_five.rake: -------------------------------------------------------------------------------- 1 | namespace :db do 2 | namespace :second_base do 3 | task "drop:_unsafe" do 4 | SecondBase.on_base { Rake::Task['db:drop:_unsafe'].execute } 5 | end 6 | 7 | namespace :migrate do 8 | desc 'Resets SecondBase database using your migrations for the current environment' 9 | task :reset => ['db:second_base:drop:_unsafe', 'db:second_base:create', 'db:second_base:migrate'] 10 | end 11 | end 12 | end 13 | 14 | %w{ 15 | drop:_unsafe 16 | }.each do |name| 17 | task = Rake::Task["db:#{name}"] rescue nil 18 | next unless task && SecondBase::Railtie.run_with_db_tasks? 19 | task.enhance do 20 | Rake::Task["db:load_config"].invoke 21 | Rake::Task["db:second_base:#{name}"].invoke 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/second_base/databases_rails_four.rake: -------------------------------------------------------------------------------- 1 | namespace :db do 2 | namespace :second_base do 3 | task :drop do 4 | SecondBase.on_base { Rake::Task['db:drop'].execute } 5 | end 6 | 7 | namespace :migrate do 8 | desc 'Resets SecondBase database using your migrations for the current environment' 9 | task :reset => ['db:second_base:drop', 'db:second_base:create', 'db:second_base:migrate'] 10 | end 11 | end 12 | end 13 | 14 | %w{ 15 | drop 16 | }.each do |name| 17 | task = Rake::Task["db:#{name}"] rescue nil 18 | next unless task && SecondBase::Railtie.run_with_db_tasks? 19 | task.enhance do 20 | Rake::Task["db:load_config"].invoke 21 | Rake::Task["db:second_base:#{name}"].invoke 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/second_base/forced.rb: -------------------------------------------------------------------------------- 1 | module SecondBase 2 | module Forced 3 | 4 | def connection_pool 5 | SecondBase::Base.connection_pool 6 | end 7 | 8 | def retrieve_connection 9 | SecondBase::Base.retrieve_connection 10 | end 11 | 12 | def connected? 13 | SecondBase::Base.connected? 14 | end 15 | 16 | def remove_connection(klass = self) 17 | SecondBase::Base.remove_connection 18 | end 19 | 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/second_base/on_base.rb: -------------------------------------------------------------------------------- 1 | module SecondBase 2 | 3 | mattr_accessor :is_on_base, instance_accessor: false 4 | self.is_on_base = false 5 | 6 | def self.on_base 7 | already_on_base = is_on_base 8 | if already_on_base 9 | yield 10 | return 11 | end 12 | original_config = ActiveRecord::Tasks::DatabaseTasks.current_config 13 | original_configurations = Rails.application.config.database_configuration 14 | original_migrations_path = ActiveRecord::Tasks::DatabaseTasks.migrations_paths 15 | original_db_dir = ActiveRecord::Tasks::DatabaseTasks.db_dir 16 | ActiveRecord::Tasks::DatabaseTasks.current_config = config 17 | ActiveRecord::Base.configurations = original_configurations[Railtie.config_key] 18 | ActiveRecord::Base.establish_connection(config) 19 | ActiveRecord::Tasks::DatabaseTasks.migrations_paths = [SecondBase::Railtie.fullpath('migrate')] 20 | ActiveRecord::Tasks::DatabaseTasks.db_dir = SecondBase::Railtie.fullpath 21 | ActiveRecord::Migrator.migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths 22 | self.is_on_base = true 23 | yield 24 | ensure 25 | unless already_on_base 26 | ActiveRecord::Base.configurations = original_configurations 27 | ActiveRecord::Tasks::DatabaseTasks.migrations_paths = original_migrations_path 28 | ActiveRecord::Tasks::DatabaseTasks.db_dir = original_db_dir 29 | ActiveRecord::Migrator.migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths 30 | ActiveRecord::Tasks::DatabaseTasks.current_config = original_config 31 | ActiveRecord::Base.establish_connection(original_config) 32 | self.is_on_base = false 33 | end 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /lib/second_base/railtie.rb: -------------------------------------------------------------------------------- 1 | module SecondBase 2 | class Railtie < Rails::Railtie 3 | 4 | config.second_base = ActiveSupport::OrderedOptions.new 5 | config.second_base.path = 'db/secondbase' 6 | config.second_base.config_key = 'secondbase' 7 | config.second_base.run_with_db_tasks = true 8 | 9 | config.after_initialize do |app| 10 | secondbase_dir = app.root.join(config.second_base.path) 11 | FileUtils.mkdir(secondbase_dir) unless File.directory?(secondbase_dir) 12 | end 13 | 14 | rake_tasks do 15 | load 'second_base/databases.rake' 16 | 17 | if Rails.version.to_i == 4 18 | load 'second_base/databases_rails_four.rake' 19 | else 20 | load 'second_base/databases_rails_five.rake' 21 | end 22 | 23 | end 24 | 25 | generators do 26 | require 'rails/second_base/generators/migration_generator' 27 | end 28 | 29 | initializer 'second_base.add_watchable_files' do |app| 30 | secondbase_dir = app.root.join(config.second_base.path) 31 | config.watchable_files.concat ["#{secondbase_dir}/schema.rb", "#{secondbase_dir}/structure.sql"] 32 | end 33 | 34 | initializer 'second_base.check_schema_cache_dump', after: 'active_record.check_schema_cache_dump' do |app| 35 | use_cache = config.active_record.use_schema_cache_dump 36 | cache_file = app.root.join(config.second_base.path, 'schema_cache.dump') 37 | if use_cache && File.file?(cache_file) 38 | cache = Marshal.load File.binread(cache_file) 39 | SecondBase::Base.connection.schema_cache = cache 40 | end 41 | end 42 | 43 | def config_path 44 | config.second_base.path 45 | end 46 | 47 | def config_key 48 | config.second_base.config_key 49 | end 50 | 51 | def run_with_db_tasks? 52 | config.second_base.run_with_db_tasks 53 | end 54 | 55 | def fullpath(extra=nil) 56 | path = Rails.root.join(config.second_base.path) 57 | (extra ? path.join(path, extra) : path).to_s 58 | end 59 | 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/second_base/test_help.rb: -------------------------------------------------------------------------------- 1 | if defined?(ActiveRecord::Base) 2 | 3 | # Support test schema sync for Rails 4.2.x and up. 4 | if ActiveRecord::Migration.respond_to? :maintain_test_schema! 5 | SecondBase.on_base do 6 | ActiveRecord::Migration.maintain_test_schema! 7 | end 8 | end 9 | 10 | 11 | end 12 | -------------------------------------------------------------------------------- /lib/second_base/version.rb: -------------------------------------------------------------------------------- 1 | module SecondBase 2 | VERSION = File.read(File.expand_path("../../../VERSION", __FILE__)).chomp 3 | end 4 | -------------------------------------------------------------------------------- /lib/secondbase.rb: -------------------------------------------------------------------------------- 1 | require 'second_base' 2 | -------------------------------------------------------------------------------- /secondbase.gemspec: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path('../lib', __FILE__) 2 | require 'second_base/version' 3 | 4 | Gem::Specification.new do |s| 5 | s.name = 'secondbase' 6 | s.version = SecondBase::VERSION 7 | s.platform = Gem::Platform::RUBY 8 | s.authors = ['Karle Durante', 'Hunter Madison', 'Ken Collins'] 9 | s.email = ['kdurante@customink.com', 'hunterglenmadison@icloud.com', 'ken@metaskills.net'] 10 | s.homepage = 'http://github.com/customink/secondbase' 11 | s.summary = 'Seamless second database integration for Rails.' 12 | s.description = "SecondBase provides support for Rails to manage dual databases by extending ActiveRecord tasks that create, migrate, and test your databases." 13 | s.files = `git ls-files`.split("\n") 14 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 15 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 16 | s.require_paths = ['lib'] 17 | s.rdoc_options = ['--charset=UTF-8'] 18 | s.license = 'MIT' 19 | s.add_runtime_dependency 'rails', '>= 4.0' 20 | s.add_development_dependency 'rake', '11.3.0' 21 | s.add_development_dependency 'appraisal' 22 | s.add_development_dependency 'pry' 23 | s.add_development_dependency 'sqlite3', '1.3.13' 24 | s.add_development_dependency 'yard' 25 | end 26 | -------------------------------------------------------------------------------- /test/cases/dbtask_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class DbTaskTest < SecondBase::TestCase 4 | 5 | def test_db_create 6 | refute_dummy_databases 7 | run_db :create 8 | assert_dummy_databases 9 | end 10 | 11 | def test_db_create_all 12 | refute_dummy_databases 13 | run_db 'create:all' 14 | assert_dummy_databases 15 | end 16 | 17 | def test_db_setup 18 | run_db :create 19 | run_db :migrate 20 | assert_dummy_databases 21 | run_db :drop 22 | refute_dummy_databases 23 | run_db :setup 24 | assert_dummy_databases 25 | end 26 | 27 | def test_db_drop 28 | run_db :create 29 | run_db :drop 30 | refute_dummy_databases 31 | end 32 | 33 | def test_db_drop_all 34 | run_db :create 35 | run_db 'drop:all' 36 | refute_dummy_databases 37 | end 38 | 39 | def test_db_purge_all 40 | skip 'Rails 4.2 & Up' unless rails_42_up? 41 | run_db :create 42 | run_db :migrate 43 | assert_dummy_databases 44 | run_db 'purge:all' 45 | establish_connection 46 | assert_no_tables 47 | end 48 | 49 | def test_db_purge 50 | skip 'Rails 4.2 & Up' unless rails_42_up? 51 | run_db :create 52 | run_db :migrate 53 | assert_dummy_databases 54 | run_db :purge 55 | establish_connection 56 | assert_no_tables 57 | end 58 | 59 | def test_db_migrate 60 | run_db :create 61 | run_db :migrate 62 | # First database and schema. 63 | schema = File.read(dummy_schema) 64 | assert_match %r{version: 20141214142700}, schema 65 | assert_match %r{create_table "users"}, schema 66 | assert_match %r{create_table "posts"}, schema 67 | refute_match %r{create_table "comments"}, schema 68 | assert_connection_tables ActiveRecord::Base, ['users', 'posts'] 69 | # Second database and schema. 70 | secondbase_schema = File.read(dummy_secondbase_schema) 71 | assert_match %r{version: 20151202075826}, secondbase_schema 72 | refute_match %r{create_table "users"}, secondbase_schema 73 | refute_match %r{create_table "posts"}, secondbase_schema 74 | assert_match %r{create_table "comments"}, secondbase_schema 75 | assert_connection_tables SecondBase::Base, ['comments'] 76 | end 77 | 78 | def test_secondbase_migrate_updown 79 | run_db :create 80 | run_db :migrate 81 | assert_match(/no migration.*20151202075826/i, run_db('migrate:down VERSION=20151202075826', :stderr)) 82 | run_secondbase 'migrate:down VERSION=20151202075826' 83 | secondbase_schema = File.read(dummy_secondbase_schema) 84 | refute_match %r{version: 20151202075826}, secondbase_schema 85 | refute_match %r{create_table "comments"}, secondbase_schema 86 | assert_match(/no migration.*20151202075826/i, run_db('migrate:up VERSION=20151202075826', :stderr)) 87 | run_secondbase 'migrate:up VERSION=20151202075826' 88 | secondbase_schema = File.read(dummy_secondbase_schema) 89 | assert_match %r{version: 20151202075826}, secondbase_schema 90 | assert_match %r{create_table "comments"}, secondbase_schema 91 | end 92 | 93 | def test_secondbase_migrate_reset 94 | run_db :create 95 | run_db :migrate 96 | secondbase_schema = File.read(dummy_secondbase_schema) 97 | assert_match %r{version: 20151202075826}, secondbase_schema 98 | assert_match %r{create_table "comments"}, secondbase_schema 99 | FileUtils.rm_rf dummy_secondbase_schema 100 | run_secondbase 'migrate:reset' 101 | secondbase_schema = File.read(dummy_secondbase_schema) 102 | assert_match %r{version: 20151202075826}, secondbase_schema 103 | assert_match %r{create_table "comments"}, secondbase_schema 104 | end 105 | 106 | def test_secondbase_migrate_redo 107 | run_db :create 108 | run_db :migrate 109 | secondbase_schema = File.read(dummy_secondbase_schema) 110 | assert_match %r{version: 20151202075826}, secondbase_schema 111 | assert_match %r{create_table "comments"}, secondbase_schema 112 | FileUtils.rm_rf dummy_secondbase_schema 113 | run_secondbase 'migrate:redo' 114 | secondbase_schema = File.read(dummy_secondbase_schema) 115 | assert_match %r{version: 20151202075826}, secondbase_schema 116 | assert_match %r{create_table "comments"}, secondbase_schema 117 | # Can redo latest SecondBase migration using previous VERSION env. 118 | version = dummy_migration[:version] 119 | run_db :migrate 120 | assert_match %r{version: #{version}}, File.read(dummy_secondbase_schema) 121 | establish_connection 122 | Comment.create! body: 'test', user_id: 420 123 | run_secondbase 'migrate:redo VERSION=20151202075826' 124 | secondbase_schema = File.read(dummy_secondbase_schema) 125 | assert_match %r{version: #{version}}, secondbase_schema 126 | assert_match %r{create_table "comments"}, secondbase_schema 127 | establish_connection 128 | assert_nil Comment.first 129 | end 130 | 131 | def test_secondbase_migrate_status 132 | run_db :create 133 | stream = rails_42_up? ? :stderr : :stdout 134 | assert_match %r{migrations table does not exist}, run_secondbase('migrate:status', stream) 135 | run_db :migrate 136 | assert_match %r{up.*20151202075826}, run_secondbase('migrate:status') 137 | version = dummy_migration[:version] 138 | status = run_secondbase('migrate:status') 139 | assert_match %r{up.*20151202075826}, status 140 | assert_match %r{down.*#{version}}, status 141 | end 142 | 143 | def test_secondbase_forward_and_rollback 144 | run_db :create 145 | run_db :migrate 146 | secondbase_schema = File.read(dummy_secondbase_schema) 147 | assert_match %r{version: 20151202075826}, secondbase_schema 148 | refute_match %r{create_table "foos"}, secondbase_schema 149 | version = dummy_migration[:version] # ActiveRecord does not support start index 0. 150 | run_secondbase :forward 151 | secondbase_schema = File.read(dummy_secondbase_schema) 152 | assert_match %r{version: #{version}}, secondbase_schema 153 | assert_match %r{create_table "foos"}, secondbase_schema 154 | run_secondbase :rollback 155 | secondbase_schema = File.read(dummy_secondbase_schema) 156 | assert_match %r{version: 20151202075826}, secondbase_schema 157 | refute_match %r{create_table "foos"}, secondbase_schema 158 | end 159 | 160 | def test_db_test_purge 161 | run_db :create 162 | assert_dummy_databases 163 | run_db 'test:purge' 164 | establish_connection 165 | assert_no_tables 166 | end 167 | 168 | def test_db_test_load_schema 169 | run_db :create 170 | assert_dummy_databases 171 | run_db 'test:purge' 172 | run_db :migrate 173 | Dir.chdir(dummy_root) { `rake db:test:load_schema` } 174 | establish_connection 175 | assert_connection_tables ActiveRecord::Base, ['users', 'posts'] 176 | assert_connection_tables SecondBase::Base, ['comments'] 177 | end 178 | 179 | def test_db_test_load_schema_via_env 180 | run_db :create 181 | assert_dummy_databases 182 | run_db 'test:purge' 183 | Dir.chdir(dummy_root) { `env SCHEMA_FORMAT=ruby rake db:migrate` } 184 | Dir.chdir(dummy_root) { `rake db:test:load_schema` } 185 | establish_connection 186 | assert_connection_tables ActiveRecord::Base, ['users', 'posts'] 187 | assert_connection_tables SecondBase::Base, ['comments'] 188 | end 189 | 190 | def test_db_test_schema_cache_dump 191 | # this is a bug in rails >5.1.1 192 | return if Rails::VERSION::STRING.start_with?("5.1") 193 | run_db :create 194 | run_db :migrate 195 | assert_dummy_databases 196 | Dir.chdir(dummy_root) { `rake db:schema:cache:dump` } 197 | assert File.file?(dummy_schema_cache), 'dummy schema cache does not exist' 198 | assert File.file?(dummy_secondbase_schema_cache), 'dummy secondbase schema cache does not exist' 199 | cache1 = Marshal.load(File.binread(dummy_schema_cache)) 200 | cache2 = Marshal.load(File.binread(dummy_secondbase_schema_cache)) 201 | source_method = rails_50_up? ? :data_sources : :tables 202 | assert cache1.send(source_method, 'posts'), 'base should have posts table in cache' 203 | refute cache1.send(source_method, 'comments'), 'base should not have comments table in cache' 204 | refute cache2.send(source_method, 'posts'), 'secondbase should not have posts table in cache' 205 | assert cache2.send(source_method, 'comments'), 'secondbase should have comments table in cache' 206 | end 207 | 208 | def test_abort_if_pending 209 | run_db :create 210 | run_db :migrate 211 | assert_equal "", run_db(:abort_if_pending_migrations, :stderr) 212 | version = dummy_migration[:version] 213 | capture(:stderr) do 214 | stdout = run_db :abort_if_pending_migrations 215 | assert_match(/1 pending migration/, stdout) 216 | assert_match(/#{version}/, stdout) 217 | end 218 | end 219 | 220 | def test_db_test_load_structure 221 | run_db :create 222 | assert_dummy_databases 223 | run_db 'test:purge' 224 | Dir.chdir(dummy_root) { `env SCHEMA_FORMAT=sql rake db:migrate` } 225 | Dir.chdir(dummy_root) { `rake db:test:load_structure` } 226 | establish_connection 227 | assert_connection_tables ActiveRecord::Base, ['users', 'posts'] 228 | assert_connection_tables SecondBase::Base, ['comments'] 229 | end 230 | 231 | def test_secondbase_version 232 | run_db :create 233 | assert_match(/version: 0/, run_secondbase(:version)) 234 | run_db :migrate 235 | assert_match(/version: 20141214142700/, run_db(:version)) 236 | assert_match(/version: 20151202075826/, run_secondbase(:version)) 237 | end 238 | 239 | def test_secondbase_db_tasks_disabled 240 | refute_dummy_databases 241 | run_db :create, :stdout, false 242 | assert_dummy_created_but_not_secondbase 243 | end 244 | 245 | private 246 | 247 | def assert_dummy_created_but_not_secondbase 248 | assert_equal 'base.sqlite3', dummy_database_sqlite 249 | refute_match(/secondbase_test/, `mysql -uroot -e "SHOW DATABASES"`) 250 | end 251 | 252 | def assert_no_tables 253 | if ActiveRecord::Base.connection.respond_to? :data_sources 254 | assert_equal [], ActiveRecord::Base.connection.data_sources 255 | assert_equal [], SecondBase::Base.connection.data_sources 256 | else 257 | assert_equal [], ActiveRecord::Base.connection.tables 258 | assert_equal [], SecondBase::Base.connection.tables 259 | end 260 | end 261 | 262 | def assert_connection_tables(model, expected_tables) 263 | establish_connection 264 | 265 | if ActiveRecord::Base.connection.respond_to? :data_sources 266 | tables = model.connection.data_sources 267 | else 268 | tables = model.connection.tables 269 | end 270 | 271 | expected_tables.each do |table| 272 | message = "Expected #{model.name} tables #{tables.inspect} to include #{table.inspect}" 273 | assert tables.include?(table), message 274 | end 275 | end 276 | 277 | end 278 | -------------------------------------------------------------------------------- /test/cases/forced_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ForcedTest < SecondBase::TestCase 4 | 5 | setup do 6 | run_db :create 7 | run_db :migrate 8 | establish_connection 9 | end 10 | 11 | def test_shared_pool 12 | assert_equal SecondBase::Base.connection_pool.object_id, 13 | CommentForced.connection_pool.object_id 14 | end 15 | 16 | def test_shared_connection 17 | assert_equal SecondBase::Base.connection.raw_connection.object_id, 18 | CommentForced.connection.raw_connection.object_id 19 | end 20 | 21 | def test_shared_new_connection_in_a_different_thread 22 | current_base_connection_id = SecondBase::Base.connection.raw_connection.object_id 23 | new_base_connection_id, new_forced_connection_id = Thread.new { 24 | [ SecondBase::Base.connection.raw_connection.object_id, 25 | CommentForced.connection.raw_connection.object_id ] 26 | }.value 27 | refute_equal new_base_connection_id, current_base_connection_id 28 | assert_equal new_base_connection_id, new_forced_connection_id 29 | end 30 | 31 | def test_shared_connected_query 32 | assert SecondBase::Base.connected? 33 | assert CommentForced.connected? 34 | CommentForced.clear_all_connections! 35 | refute SecondBase::Base.connected? 36 | refute CommentForced.connected? 37 | end 38 | 39 | def test_can_remove_connection_properly 40 | base_connection = SecondBase::Base.connection 41 | forced_connection = CommentForced.connection 42 | assert base_connection.active? 43 | assert forced_connection.active? 44 | CommentForced.remove_connection 45 | refute base_connection.active? 46 | refute forced_connection.active? 47 | end 48 | 49 | end 50 | -------------------------------------------------------------------------------- /test/cases/generator_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class GeneratorTest < SecondBase::TestCase 4 | 5 | teardown do 6 | generated_migration_delete 7 | generated_migration_base_delete 8 | end 9 | 10 | def test_initialization_via_help 11 | output = Dir.chdir(dummy_root) { `rails g -h` } 12 | assert_match(/second_base\:migration/, output) 13 | end 14 | 15 | def test_description_uses_rails_base 16 | output = Dir.chdir(dummy_root) { `rails g second_base:migration -h` } 17 | assert_match %r{db/migrate/20080514090912_add_ssl_flag\.rb}, output 18 | end 19 | 20 | def test_migration 21 | output = Dir.chdir(dummy_root) { `rails g second_base:migration CreateFavorites post_id:integer count:integer` } 22 | assert_match %r{create.*db/secondbase/migrate/.*create_favorites\.rb}, output 23 | migration = generated_migration_data 24 | assert_match %r{create_table :favorites}, migration 25 | assert_match %r{t.integer :post_id}, migration 26 | assert_match %r{t.integer :count}, migration 27 | end 28 | 29 | def test_base_migration_generator 30 | output = Dir.chdir(dummy_root) { `rails g migration AddBaseColumn` } 31 | assert_match %r{create.*db/migrate/.*add_base_column\.rb}, output 32 | migration = generated_migration_base_data 33 | assert_match %r{class AddBaseColumn}, migration 34 | assert_match %r{def change}, migration 35 | end 36 | 37 | 38 | private 39 | 40 | def generated_migration 41 | Dir["#{dummy_db}/secondbase/migrate/*favorites.{rb}"].first 42 | end 43 | 44 | def generated_migration_data 45 | generated_migration ? File.read(generated_migration) : '' 46 | end 47 | 48 | def generated_migration_delete 49 | FileUtils.rm_rf(generated_migration) if generated_migration 50 | end 51 | 52 | def generated_migration_base 53 | Dir["#{dummy_db}/migrate/*add_base*.{rb}"].first 54 | end 55 | 56 | def generated_migration_base_data 57 | generated_migration_base ? File.read(generated_migration_base) : '' 58 | end 59 | 60 | def generated_migration_base_delete 61 | FileUtils.rm_rf(generated_migration_base) if generated_migration_base 62 | end 63 | 64 | end 65 | -------------------------------------------------------------------------------- /test/cases/on_base_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class OnBaseTest < SecondBase::TestCase 4 | 5 | setup do 6 | run_db :create 7 | run_db :migrate 8 | establish_connection 9 | end 10 | 11 | def test_on_base 12 | refute SecondBase.is_on_base 13 | SecondBase.on_base do 14 | assert SecondBase.is_on_base 15 | assert_equal SecondBase::Base.connection.class, ActiveRecord::Base.connection.class 16 | assert_equal [SecondBase::Railtie.fullpath('migrate')], ActiveRecord::Tasks::DatabaseTasks.migrations_paths 17 | assert_equal SecondBase::Railtie.fullpath, ActiveRecord::Tasks::DatabaseTasks.db_dir 18 | end 19 | refute SecondBase.is_on_base 20 | end 21 | 22 | def test_on_base_nested 23 | refute SecondBase.is_on_base 24 | SecondBase.on_base do 25 | assert SecondBase.is_on_base 26 | SecondBase.on_base do 27 | assert SecondBase.is_on_base 28 | end 29 | assert SecondBase.is_on_base 30 | end 31 | refute SecondBase.is_on_base 32 | end 33 | 34 | 35 | end 36 | -------------------------------------------------------------------------------- /test/cases/railtie_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class RailtieTest < SecondBase::TestCase 4 | 5 | def test_config 6 | expected_path = 'db/secondbase' 7 | assert_equal expected_path, railtie_inst.config.second_base.path 8 | assert_equal expected_path, railtie_klass.config.second_base.path 9 | expected_config_key = 'secondbase' 10 | assert_equal expected_config_key, railtie_inst.config.second_base.config_key 11 | assert_equal expected_config_key, railtie_klass.config.second_base.config_key 12 | end 13 | 14 | def test_fullpath 15 | expected = dummy_db.join('secondbase').to_s 16 | assert_equal expected, railtie_inst.fullpath 17 | assert_equal expected, railtie_klass.fullpath 18 | end 19 | 20 | 21 | private 22 | 23 | def railtie_inst 24 | dummy_app.railties.grep(railtie_klass).first 25 | end 26 | 27 | def railtie_klass 28 | SecondBase::Railtie 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /test/cases/rake_test.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/customink/secondbase/2e7c1655e9ea51999432bcc457bc1374455e1be1/test/cases/rake_test.rb -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/Rakefile: -------------------------------------------------------------------------------- 1 | require_relative 'config/init' 2 | Dummy::Application.load_tasks 3 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | 3 | def index 4 | render :html => '

Dummy::Application

'.html_safe, :layout => false 5 | end 6 | 7 | end 8 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/app/models/comment.rb: -------------------------------------------------------------------------------- 1 | class Comment < SecondBase::Base 2 | 3 | belongs_to :user 4 | 5 | 6 | end 7 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/app/models/comment_forced.rb: -------------------------------------------------------------------------------- 1 | class CommentForced < ApplicationRecord 2 | self.table_name = 'comments' 3 | belongs_to :user 4 | end 5 | 6 | CommentForced.extend SecondBase::Forced 7 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/app/models/post.rb: -------------------------------------------------------------------------------- 1 | class Post < ApplicationRecord 2 | 3 | belongs_to :user 4 | has_many :comments 5 | 6 | 7 | end 8 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ApplicationRecord 2 | 3 | has_many :posts 4 | 5 | 6 | end 7 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | APP_PATH = File.expand_path('../../config/init', __FILE__) 4 | require APP_PATH 5 | require 'rails/commands' 6 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/config/database.yml: -------------------------------------------------------------------------------- 1 | 2 | test: 3 | adapter: sqlite3 4 | database: ./db/base.sqlite3 5 | 6 | secondbase: 7 | 8 | test: 9 | adapter: mysql2 10 | database: 'secondbase_test' 11 | username: root 12 | password: 13 | host: localhost 14 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/config/init.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) 3 | require 'bundler/setup' 4 | require 'rails/all' 5 | Bundler.require(:default, Rails.env) 6 | 7 | module Dummy 8 | class Application < ::Rails::Application 9 | 10 | # Basic Engine 11 | config.root = File.join __FILE__, '..', '..' 12 | config.cache_store = :memory_store 13 | config.assets.enabled = false 14 | config.secret_token = '012345678901234567890123456789' 15 | config.active_support.test_order = :random 16 | 17 | # Mimic Test Environment Config. 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | config.action_dispatch.show_exceptions = false 21 | config.action_controller.allow_forgery_protection = false 22 | config.action_mailer.delivery_method = :test 23 | config.active_support.deprecation = :stderr 24 | config.allow_concurrency = true 25 | config.cache_classes = true 26 | config.dependency_loading = true 27 | config.preload_frameworks = true 28 | config.eager_load = true 29 | config.secret_key_base = '012345678901234567890123456789' 30 | 31 | # Keep pending test:prepare via pending migrations from running. 32 | config.active_record.maintain_test_schema = false if ActiveRecord::Base.respond_to?(:maintain_test_schema) 33 | 34 | config.active_record.schema_format = (ENV['SCHEMA_FORMAT'] || :ruby).to_sym 35 | 36 | if ENV['WITH_SECONDBASE_TASKS'].present? 37 | config.second_base.run_with_db_tasks = ENV['WITH_SECONDBASE_TASKS'] == 'true' 38 | end 39 | end 40 | end 41 | 42 | Dummy::Application.initialize! 43 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/config/routes.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.routes.draw do 2 | root :to => 'application#index' 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/db/migrate/20141209165002_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration[4.2] 2 | 3 | def change 4 | create_table :users, force: true do |t| 5 | t.string :name 6 | t.string :email 7 | t.timestamps null: false 8 | end 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/db/migrate/20141214142700_create_posts.rb: -------------------------------------------------------------------------------- 1 | class CreatePosts < ActiveRecord::Migration[4.2] 2 | 3 | def change 4 | create_table :posts, force: true do |t| 5 | t.text :title 6 | t.text :body 7 | t.references :user, index: true 8 | t.timestamps null: false 9 | end 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/db/schema_cache.yml: -------------------------------------------------------------------------------- 1 | --- !ruby/object:ActiveRecord::ConnectionAdapters::SchemaCache 2 | columns: 3 | schema_migrations: 4 | - &1 !ruby/object:ActiveRecord::ConnectionAdapters::Column 5 | name: version 6 | table_name: schema_migrations 7 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 8 | sql_type: varchar 9 | type: :string 10 | limit: 11 | precision: 12 | scale: 13 | 'null': false 14 | default: 15 | default_function: 16 | collation: 17 | comment: 18 | ar_internal_metadata: 19 | - &2 !ruby/object:ActiveRecord::ConnectionAdapters::Column 20 | name: key 21 | table_name: ar_internal_metadata 22 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 23 | sql_type: varchar 24 | type: :string 25 | limit: 26 | precision: 27 | scale: 28 | 'null': false 29 | default: 30 | default_function: 31 | collation: 32 | comment: 33 | - &3 !ruby/object:ActiveRecord::ConnectionAdapters::Column 34 | name: value 35 | table_name: ar_internal_metadata 36 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 37 | sql_type: varchar 38 | type: :string 39 | limit: 40 | precision: 41 | scale: 42 | 'null': true 43 | default: 44 | default_function: 45 | collation: 46 | comment: 47 | - &4 !ruby/object:ActiveRecord::ConnectionAdapters::Column 48 | name: created_at 49 | table_name: ar_internal_metadata 50 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 51 | sql_type: datetime 52 | type: :datetime 53 | limit: 54 | precision: 55 | scale: 56 | 'null': false 57 | default: 58 | default_function: 59 | collation: 60 | comment: 61 | - &5 !ruby/object:ActiveRecord::ConnectionAdapters::Column 62 | name: updated_at 63 | table_name: ar_internal_metadata 64 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 65 | sql_type: datetime 66 | type: :datetime 67 | limit: 68 | precision: 69 | scale: 70 | 'null': false 71 | default: 72 | default_function: 73 | collation: 74 | comment: 75 | users: 76 | - &6 !ruby/object:ActiveRecord::ConnectionAdapters::Column 77 | name: id 78 | table_name: users 79 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 80 | sql_type: INTEGER 81 | type: :integer 82 | limit: 83 | precision: 84 | scale: 85 | 'null': false 86 | default: 87 | default_function: 88 | collation: 89 | comment: 90 | - &7 !ruby/object:ActiveRecord::ConnectionAdapters::Column 91 | name: name 92 | table_name: users 93 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 94 | sql_type: varchar 95 | type: :string 96 | limit: 97 | precision: 98 | scale: 99 | 'null': true 100 | default: 101 | default_function: 102 | collation: 103 | comment: 104 | - &8 !ruby/object:ActiveRecord::ConnectionAdapters::Column 105 | name: email 106 | table_name: users 107 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 108 | sql_type: varchar 109 | type: :string 110 | limit: 111 | precision: 112 | scale: 113 | 'null': true 114 | default: 115 | default_function: 116 | collation: 117 | comment: 118 | - &9 !ruby/object:ActiveRecord::ConnectionAdapters::Column 119 | name: created_at 120 | table_name: users 121 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 122 | sql_type: datetime 123 | type: :datetime 124 | limit: 125 | precision: 126 | scale: 127 | 'null': false 128 | default: 129 | default_function: 130 | collation: 131 | comment: 132 | - &10 !ruby/object:ActiveRecord::ConnectionAdapters::Column 133 | name: updated_at 134 | table_name: users 135 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 136 | sql_type: datetime 137 | type: :datetime 138 | limit: 139 | precision: 140 | scale: 141 | 'null': false 142 | default: 143 | default_function: 144 | collation: 145 | comment: 146 | posts: 147 | - &11 !ruby/object:ActiveRecord::ConnectionAdapters::Column 148 | name: id 149 | table_name: posts 150 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 151 | sql_type: INTEGER 152 | type: :integer 153 | limit: 154 | precision: 155 | scale: 156 | 'null': false 157 | default: 158 | default_function: 159 | collation: 160 | comment: 161 | - &12 !ruby/object:ActiveRecord::ConnectionAdapters::Column 162 | name: title 163 | table_name: posts 164 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 165 | sql_type: text 166 | type: :text 167 | limit: 168 | precision: 169 | scale: 170 | 'null': true 171 | default: 172 | default_function: 173 | collation: 174 | comment: 175 | - &13 !ruby/object:ActiveRecord::ConnectionAdapters::Column 176 | name: body 177 | table_name: posts 178 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 179 | sql_type: text 180 | type: :text 181 | limit: 182 | precision: 183 | scale: 184 | 'null': true 185 | default: 186 | default_function: 187 | collation: 188 | comment: 189 | - &14 !ruby/object:ActiveRecord::ConnectionAdapters::Column 190 | name: user_id 191 | table_name: posts 192 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 193 | sql_type: integer 194 | type: :integer 195 | limit: 196 | precision: 197 | scale: 198 | 'null': true 199 | default: 200 | default_function: 201 | collation: 202 | comment: 203 | - &15 !ruby/object:ActiveRecord::ConnectionAdapters::Column 204 | name: created_at 205 | table_name: posts 206 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 207 | sql_type: datetime 208 | type: :datetime 209 | limit: 210 | precision: 211 | scale: 212 | 'null': false 213 | default: 214 | default_function: 215 | collation: 216 | comment: 217 | - &16 !ruby/object:ActiveRecord::ConnectionAdapters::Column 218 | name: updated_at 219 | table_name: posts 220 | sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 221 | sql_type: datetime 222 | type: :datetime 223 | limit: 224 | precision: 225 | scale: 226 | 'null': false 227 | default: 228 | default_function: 229 | collation: 230 | comment: 231 | columns_hash: 232 | schema_migrations: 233 | version: *1 234 | ar_internal_metadata: 235 | key: *2 236 | value: *3 237 | created_at: *4 238 | updated_at: *5 239 | users: 240 | id: *6 241 | name: *7 242 | email: *8 243 | created_at: *9 244 | updated_at: *10 245 | posts: 246 | id: *11 247 | title: *12 248 | body: *13 249 | user_id: *14 250 | created_at: *15 251 | updated_at: *16 252 | primary_keys: 253 | schema_migrations: version 254 | ar_internal_metadata: key 255 | users: id 256 | posts: id 257 | data_sources: 258 | schema_migrations: true 259 | ar_internal_metadata: true 260 | users: true 261 | posts: true 262 | version: 20141214142700 263 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/db/secondbase/migrate/20151202075826_create_comments.rb: -------------------------------------------------------------------------------- 1 | class CreateComments < ActiveRecord::Migration[4.2] 2 | 3 | def change 4 | create_table :comments, force: true do |t| 5 | t.text :body 6 | t.references :user, index: true 7 | t.timestamps null: false 8 | end 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/db/secondbase/schema_cache.yml: -------------------------------------------------------------------------------- 1 | --- !ruby/object:ActiveRecord::ConnectionAdapters::SchemaCache 2 | columns: 3 | ar_internal_metadata: 4 | - &11 !ruby/object:ActiveRecord::ConnectionAdapters::MySQL::Column 5 | name: key 6 | table_name: ar_internal_metadata 7 | sql_type_metadata: !ruby/marshalable:ActiveRecord::ConnectionAdapters::MySQL::TypeMetadata 8 | :__v2__: 9 | - :@type_metadata 10 | - :@extra 11 | ? - &1 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 12 | sql_type: varchar(255) 13 | type: :string 14 | limit: 255 15 | precision: 16 | scale: 17 | - '' 18 | : *1 19 | 'null': false 20 | default: 21 | default_function: 22 | collation: utf8_general_ci 23 | comment: 24 | - &12 !ruby/object:ActiveRecord::ConnectionAdapters::MySQL::Column 25 | name: value 26 | table_name: ar_internal_metadata 27 | sql_type_metadata: !ruby/marshalable:ActiveRecord::ConnectionAdapters::MySQL::TypeMetadata 28 | :__v2__: 29 | - :@type_metadata 30 | - :@extra 31 | ? - &2 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 32 | sql_type: varchar(255) 33 | type: :string 34 | limit: 255 35 | precision: 36 | scale: 37 | - '' 38 | : *2 39 | 'null': true 40 | default: 41 | default_function: 42 | collation: utf8_general_ci 43 | comment: 44 | - &13 !ruby/object:ActiveRecord::ConnectionAdapters::MySQL::Column 45 | name: created_at 46 | table_name: ar_internal_metadata 47 | sql_type_metadata: !ruby/marshalable:ActiveRecord::ConnectionAdapters::MySQL::TypeMetadata 48 | :__v2__: 49 | - :@type_metadata 50 | - :@extra 51 | ? - &3 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 52 | sql_type: datetime 53 | type: :datetime 54 | limit: 55 | precision: 0 56 | scale: 57 | - '' 58 | : *3 59 | 'null': false 60 | default: 61 | default_function: 62 | collation: 63 | comment: 64 | - &14 !ruby/object:ActiveRecord::ConnectionAdapters::MySQL::Column 65 | name: updated_at 66 | table_name: ar_internal_metadata 67 | sql_type_metadata: !ruby/marshalable:ActiveRecord::ConnectionAdapters::MySQL::TypeMetadata 68 | :__v2__: 69 | - :@type_metadata 70 | - :@extra 71 | ? - &4 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 72 | sql_type: datetime 73 | type: :datetime 74 | limit: 75 | precision: 0 76 | scale: 77 | - '' 78 | : *4 79 | 'null': false 80 | default: 81 | default_function: 82 | collation: 83 | comment: 84 | comments: 85 | - &15 !ruby/object:ActiveRecord::ConnectionAdapters::MySQL::Column 86 | name: id 87 | table_name: comments 88 | sql_type_metadata: !ruby/marshalable:ActiveRecord::ConnectionAdapters::MySQL::TypeMetadata 89 | :__v2__: 90 | - :@type_metadata 91 | - :@extra 92 | ? - &5 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 93 | sql_type: int(11) 94 | type: :integer 95 | limit: 4 96 | precision: 97 | scale: 98 | - auto_increment 99 | : *5 100 | 'null': false 101 | default: 102 | default_function: 103 | collation: 104 | comment: 105 | - &16 !ruby/object:ActiveRecord::ConnectionAdapters::MySQL::Column 106 | name: body 107 | table_name: comments 108 | sql_type_metadata: !ruby/marshalable:ActiveRecord::ConnectionAdapters::MySQL::TypeMetadata 109 | :__v2__: 110 | - :@type_metadata 111 | - :@extra 112 | ? - &6 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 113 | sql_type: text 114 | type: :text 115 | limit: 65535 116 | precision: 117 | scale: 118 | - '' 119 | : *6 120 | 'null': true 121 | default: 122 | default_function: 123 | collation: utf8_general_ci 124 | comment: 125 | - &17 !ruby/object:ActiveRecord::ConnectionAdapters::MySQL::Column 126 | name: user_id 127 | table_name: comments 128 | sql_type_metadata: !ruby/marshalable:ActiveRecord::ConnectionAdapters::MySQL::TypeMetadata 129 | :__v2__: 130 | - :@type_metadata 131 | - :@extra 132 | ? - &7 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 133 | sql_type: int(11) 134 | type: :integer 135 | limit: 4 136 | precision: 137 | scale: 138 | - '' 139 | : *7 140 | 'null': true 141 | default: 142 | default_function: 143 | collation: 144 | comment: 145 | - &18 !ruby/object:ActiveRecord::ConnectionAdapters::MySQL::Column 146 | name: created_at 147 | table_name: comments 148 | sql_type_metadata: !ruby/marshalable:ActiveRecord::ConnectionAdapters::MySQL::TypeMetadata 149 | :__v2__: 150 | - :@type_metadata 151 | - :@extra 152 | ? - &8 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 153 | sql_type: datetime 154 | type: :datetime 155 | limit: 156 | precision: 0 157 | scale: 158 | - '' 159 | : *8 160 | 'null': false 161 | default: 162 | default_function: 163 | collation: 164 | comment: 165 | - &19 !ruby/object:ActiveRecord::ConnectionAdapters::MySQL::Column 166 | name: updated_at 167 | table_name: comments 168 | sql_type_metadata: !ruby/marshalable:ActiveRecord::ConnectionAdapters::MySQL::TypeMetadata 169 | :__v2__: 170 | - :@type_metadata 171 | - :@extra 172 | ? - &9 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 173 | sql_type: datetime 174 | type: :datetime 175 | limit: 176 | precision: 0 177 | scale: 178 | - '' 179 | : *9 180 | 'null': false 181 | default: 182 | default_function: 183 | collation: 184 | comment: 185 | schema_migrations: 186 | - &20 !ruby/object:ActiveRecord::ConnectionAdapters::MySQL::Column 187 | name: version 188 | table_name: schema_migrations 189 | sql_type_metadata: !ruby/marshalable:ActiveRecord::ConnectionAdapters::MySQL::TypeMetadata 190 | :__v2__: 191 | - :@type_metadata 192 | - :@extra 193 | ? - &10 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata 194 | sql_type: varchar(255) 195 | type: :string 196 | limit: 255 197 | precision: 198 | scale: 199 | - '' 200 | : *10 201 | 'null': false 202 | default: 203 | default_function: 204 | collation: utf8_general_ci 205 | comment: 206 | columns_hash: 207 | ar_internal_metadata: 208 | key: *11 209 | value: *12 210 | created_at: *13 211 | updated_at: *14 212 | comments: 213 | id: *15 214 | body: *16 215 | user_id: *17 216 | created_at: *18 217 | updated_at: *19 218 | schema_migrations: 219 | version: *20 220 | primary_keys: 221 | ar_internal_metadata: key 222 | comments: id 223 | schema_migrations: version 224 | data_sources: 225 | ar_internal_metadata: true 226 | comments: true 227 | schema_migrations: true 228 | version: 20151202075826 229 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/customink/secondbase/2e7c1655e9ea51999432bcc457bc1374455e1be1/test/dummy_apps/rails_five/log/.keep -------------------------------------------------------------------------------- /test/dummy_apps/rails_five/tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/customink/secondbase/2e7c1655e9ea51999432bcc457bc1374455e1be1/test/dummy_apps/rails_five/tmp/.keep -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/Rakefile: -------------------------------------------------------------------------------- 1 | require File.expand_path '../init', __FILE__ 2 | Dummy::Application.load_tasks 3 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | 3 | def index 4 | render :html => '

Dummy::Application

'.html_safe, :layout => false 5 | end 6 | 7 | end 8 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/app/models/comment.rb: -------------------------------------------------------------------------------- 1 | class Comment < SecondBase::Base 2 | 3 | belongs_to :user 4 | 5 | 6 | end 7 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/app/models/comment_forced.rb: -------------------------------------------------------------------------------- 1 | class CommentForced < ActiveRecord::Base 2 | self.table_name = 'comments' 3 | belongs_to :user 4 | end 5 | 6 | CommentForced.extend SecondBase::Forced 7 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/app/models/post.rb: -------------------------------------------------------------------------------- 1 | class Post < ActiveRecord::Base 2 | 3 | belongs_to :user 4 | has_many :comments 5 | 6 | 7 | end 8 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | 3 | has_many :posts 4 | 5 | 6 | end 7 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | APP_PATH = File.expand_path('../../init', __FILE__) 4 | require APP_PATH 5 | require 'rails/commands' 6 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/config/database.yml: -------------------------------------------------------------------------------- 1 | 2 | test: 3 | adapter: sqlite3 4 | database: ./db/base.sqlite3 5 | 6 | secondbase: 7 | 8 | test: 9 | adapter: mysql 10 | database: 'secondbase_test' 11 | username: root 12 | password: 13 | host: localhost 14 | 15 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/config/routes.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.routes.draw do 2 | root :to => 'application#index' 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/db/migrate/20141209165002_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration 2 | 3 | def change 4 | create_table :users, force: true do |t| 5 | t.string :name 6 | t.string :email 7 | t.timestamps null: false 8 | end 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/db/migrate/20141214142700_create_posts.rb: -------------------------------------------------------------------------------- 1 | class CreatePosts < ActiveRecord::Migration 2 | 3 | def change 4 | create_table :posts, force: true do |t| 5 | t.text :title 6 | t.text :body 7 | t.references :user, index: true 8 | t.timestamps null: false 9 | end 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/db/secondbase/migrate/20151202075826_create_comments.rb: -------------------------------------------------------------------------------- 1 | class CreateComments < ActiveRecord::Migration 2 | 3 | def change 4 | create_table :comments, force: true do |t| 5 | t.text :body 6 | t.references :user, index: true 7 | t.timestamps null: false 8 | end 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/init.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __FILE__) 3 | require 'bundler/setup' 4 | require 'rails/all' 5 | Bundler.require(:default, Rails.env) 6 | 7 | module Dummy 8 | class Application < ::Rails::Application 9 | 10 | # Basic Engine 11 | config.root = File.join __FILE__, '..' 12 | config.cache_store = :memory_store 13 | config.assets.enabled = false 14 | config.secret_token = '012345678901234567890123456789' 15 | config.active_support.test_order = :random 16 | 17 | # Mimic Test Environment Config. 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | config.action_dispatch.show_exceptions = false 21 | config.action_controller.allow_forgery_protection = false 22 | config.action_mailer.delivery_method = :test 23 | config.active_support.deprecation = :stderr 24 | config.allow_concurrency = true 25 | config.cache_classes = true 26 | config.dependency_loading = true 27 | config.preload_frameworks = true 28 | config.eager_load = true 29 | config.secret_key_base = '012345678901234567890123456789' 30 | 31 | # Keep pending test:prepare via pending migrations from running. 32 | config.active_record.maintain_test_schema = false if ActiveRecord::Base.respond_to?(:maintain_test_schema) 33 | 34 | config.active_record.schema_format = (ENV['SCHEMA_FORMAT'] || :ruby).to_sym 35 | 36 | if ENV['WITH_SECONDBASE_TASKS'].present? 37 | config.second_base.run_with_db_tasks = ENV['WITH_SECONDBASE_TASKS'] == 'true' 38 | end 39 | end 40 | end 41 | 42 | Dummy::Application.initialize! 43 | -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/customink/secondbase/2e7c1655e9ea51999432bcc457bc1374455e1be1/test/dummy_apps/rails_four/log/.keep -------------------------------------------------------------------------------- /test/dummy_apps/rails_four/tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/customink/secondbase/2e7c1655e9ea51999432bcc457bc1374455e1be1/test/dummy_apps/rails_four/tmp/.keep -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | require 'bundler/setup' 4 | Bundler.require :default, :development 5 | require 'second_base' 6 | require 'active_support/test_case' 7 | require 'active_support/testing/autorun' 8 | 9 | if Rails.version.to_i == 4 10 | require 'dummy_apps/rails_four/init' 11 | else 12 | require 'dummy_apps/rails_five/config/init' 13 | end 14 | 15 | require 'rails/test_help' 16 | Dir['test/test_helpers/*.{rb}'].each { |f| require_relative "../#{f}" } 17 | 18 | ActiveSupport.test_order = :random if ActiveSupport.respond_to?(:test_order) 19 | 20 | module SecondBase 21 | class TestCase < ActiveSupport::TestCase 22 | 23 | if Rails.version.to_i == 4 24 | self.use_transactional_fixtures = false 25 | else 26 | self.use_transactional_tests = false 27 | end 28 | 29 | include RailsVersionHelpers, 30 | DummyAppHelpers, 31 | StreamHelpers 32 | 33 | setup :delete_dummy_files 34 | teardown :delete_dummy_files 35 | 36 | private 37 | 38 | def establish_connection 39 | ActiveRecord::Base.establish_connection 40 | ActiveRecord::Base.connection 41 | SecondBase::Base.establish_connection(SecondBase.config) 42 | SecondBase::Base.connection 43 | end 44 | 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /test/test_helpers/dummy_app_helpers.rb: -------------------------------------------------------------------------------- 1 | module SecondBase 2 | module DummyAppHelpers 3 | 4 | extend ActiveSupport::Concern 5 | 6 | private 7 | 8 | def dummy_app 9 | ::Dummy::Application 10 | end 11 | 12 | def dummy_root 13 | dummy_app.root 14 | end 15 | 16 | def dummy_config 17 | dummy_app.config 18 | end 19 | 20 | def dummy_tmp 21 | dummy_app.root.join 'tmp' 22 | end 23 | 24 | def dummy_db 25 | dummy_app.root.join 'db' 26 | end 27 | 28 | def dummy_schema 29 | dummy_db.join 'schema.rb' 30 | end 31 | 32 | def dummy_schema_cache 33 | dummy_db.join 'schema_cache.dump' 34 | end 35 | 36 | def dummy_secondbase_schema 37 | dummy_db.join('secondbase', 'schema.rb') 38 | end 39 | 40 | def dummy_secondbase_schema_cache 41 | dummy_db.join('secondbase', 'schema_cache.dump') 42 | end 43 | 44 | def dummy_database_sqlite 45 | Dir.chdir(dummy_db){ Dir['*.sqlite3'] }.first 46 | end 47 | 48 | def dummy_migration 49 | @dummy_migration ||= begin 50 | vers = Time.now.utc.strftime '%Y%m%d%H%M%S' 51 | file = dummy_root.join 'db', 'secondbase', 'migrate', "#{vers}_create_foos.rb" 52 | if rails_50_up? 53 | migr = %|class CreateFoos < ActiveRecord::Migration[4.2] ; def change ; create_table(:foos) ; end ; end| 54 | else 55 | migr = %|class CreateFoos < ActiveRecord::Migration ; def change ; create_table(:foos) ; end ; end| 56 | end 57 | File.open(file,'w') { |f| f.write(migr) } 58 | {version: vers, file: file} 59 | end 60 | end 61 | 62 | def delete_dummy_files 63 | FileUtils.rm_rf dummy_schema 64 | FileUtils.rm_rf dummy_secondbase_schema 65 | FileUtils.rm_rf dummy_schema_cache 66 | FileUtils.rm_rf dummy_secondbase_schema_cache 67 | Dir.chdir(dummy_db) { Dir['**/structure.sql'].each { |structure| FileUtils.rm_rf(structure) } } 68 | Dir.chdir(dummy_db) { FileUtils.rm_rf(dummy_database_sqlite) } if dummy_database_sqlite 69 | FileUtils.rm_rf(dummy_migration[:file]) if defined?(@dummy_migration) && @dummy_migration 70 | `mysql -uroot -e "DROP DATABASE IF EXISTS secondbase_test"` 71 | end 72 | 73 | # Runners 74 | 75 | def run_cmd 76 | 'rake' 77 | end 78 | 79 | def run_db(args, stream=:stdout, with_secondbase_tasks=true) 80 | capture(stream) do 81 | Dir.chdir(dummy_root) { Kernel.system "env WITH_SECONDBASE_TASKS=#{with_secondbase_tasks} #{run_cmd} db:#{args}" } 82 | end 83 | end 84 | 85 | def run_secondbase(args, stream=:stdout) 86 | capture(stream) do 87 | Dir.chdir(dummy_root) { Kernel.system "#{run_cmd} db:second_base:#{args}" } 88 | end 89 | end 90 | 91 | # Assertions 92 | 93 | def assert_dummy_databases 94 | assert_equal 'base.sqlite3', dummy_database_sqlite 95 | assert_match(/secondbase_test/, `mysql -uroot -e "SHOW DATABASES"`) 96 | end 97 | 98 | def refute_dummy_databases 99 | assert_nil dummy_database_sqlite 100 | refute_match(/secondbase_test/, `mysql -uroot -e "SHOW DATABASES"`) 101 | end 102 | 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /test/test_helpers/rails_version_helpers.rb: -------------------------------------------------------------------------------- 1 | module SecondBase 2 | module RailsVersionHelpers 3 | 4 | extend ActiveSupport::Concern 5 | 6 | included { extend RailsVersionHelpers } 7 | 8 | private 9 | 10 | def rails_version 11 | Rails.version.to(2) 12 | end 13 | 14 | ['4.0', '4.1', '4.2', '5.0', '5.1'].each do |v| 15 | 16 | vm = v.sub '.', '' 17 | 18 | define_method :"rails_#{vm}?" do 19 | rails_version == v 20 | end 21 | 22 | define_method :"rails_#{vm}_up?" do 23 | rails_version >= v 24 | end 25 | 26 | end 27 | 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /test/test_helpers/stream_helpers.rb: -------------------------------------------------------------------------------- 1 | module SecondBase 2 | module StreamHelpers 3 | 4 | private 5 | 6 | def silence_stream(stream) 7 | old_stream = stream.dup 8 | stream.reopen(IO::NULL) 9 | stream.sync = true 10 | yield 11 | ensure 12 | stream.reopen(old_stream) 13 | old_stream.close 14 | end 15 | 16 | def quietly 17 | silence_stream(STDOUT) do 18 | silence_stream(STDERR) do 19 | yield 20 | end 21 | end 22 | end 23 | 24 | def capture(stream) 25 | stream = stream.to_s 26 | captured_stream = Tempfile.new(stream) 27 | stream_io = eval("$#{stream}") 28 | origin_stream = stream_io.dup 29 | stream_io.reopen(captured_stream) 30 | yield 31 | stream_io.rewind 32 | return captured_stream.read 33 | ensure 34 | captured_stream.close 35 | captured_stream.unlink 36 | stream_io.reopen(origin_stream) 37 | end 38 | 39 | end 40 | end 41 | --------------------------------------------------------------------------------