diff --git a/.github/workflows/.rubocop-linter.yml b/.github/workflows/.rubocop-linter.yml new file mode 100644 index 00000000..cab9704b --- /dev/null +++ b/.github/workflows/.rubocop-linter.yml @@ -0,0 +1,22 @@ +name: Rubocop Lint + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + container: + image: ruby:2.6.5 + + steps: + - uses: actions/checkout@v1 + - name: Rubocop Linter + uses: andrewmcodes/rubocop-linter-action@v2.0.0 + with: + additional_gems: 'perx-rubocop:0.0.3' + fail_level: 'warning' + version: '0.77.0' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.pryrc b/.pryrc index 22e16cde..33d98970 100644 --- a/.pryrc +++ b/.pryrc @@ -1,3 +1,5 @@ -if defined?(Rails) && Rails.env - extend Rails::ConsoleMethods -end +# frozen_string_literal: true + +# rubocop:disable Style/MixinUsage +extend Rails::ConsoleMethods if defined?(Rails) && Rails.env +# rubocop:enable Style/MixinUsage diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..e8cc53e7 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,17 @@ +inherit_from: .rubocop_todo.yml + +inherit_gem: + perx-rubocop: + - default.yml + +Style/WordArray: + Exclude: + - spec/schemas/**/*.rb + +Style/NumericLiterals: + Exclude: + - spec/schemas/**/*.rb + +Layout/EmptyLineAfterMagicComment: + Exclude: + - spec/schemas/**/*.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 00000000..0f709629 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,29 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2020-02-16 15:36:55 +0800 using RuboCop version 0.77.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 5 +Metrics/AbcSize: + Max: 33 + +# Offense count: 11 +# Configuration parameters: CountComments, ExcludedMethods. +# ExcludedMethods: refine +Metrics/BlockLength: + Max: 176 + +# Offense count: 18 +# Cop supports --auto-correct. +# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. +# URISchemes: http, https +Metrics/LineLength: + Max: 237 + +# Offense count: 4 +# Configuration parameters: CountComments, ExcludedMethods. +Metrics/MethodLength: + Max: 24 diff --git a/.story_branch.yml b/.story_branch.yml new file mode 100644 index 00000000..d9ad6922 --- /dev/null +++ b/.story_branch.yml @@ -0,0 +1,4 @@ +--- +tracker: github +project_id: +- rails-on-services/apartment diff --git a/.travis.yml b/.travis.yml index 78067b58..3fe43feb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,10 @@ -sudo: required +os: linux + language: ruby services: - docker rvm: - - jruby-9.1.15.0 + - jruby-9.1.17.0 - 2.1.9 - 2.2.9 - 2.3.6 @@ -11,6 +12,12 @@ rvm: - 2.5.0 - 2.6.2 - ruby-head + +branches: + only: + - master + - development + gemfile: - gemfiles/rails_4_2.gemfile - gemfiles/rails_5_0.gemfile @@ -29,12 +36,16 @@ before_install: env: RUBY_GC_MALLOC_LIMIT: 90000000 RUBY_GC_HEAP_FREE_SLOTS: 200000 -matrix: +jobs: allow_failures: - rvm: ruby-head - gemfile: gemfiles/rails_master.gemfile - - rvm: jruby-9.1.15.0 + - rvm: jruby-9.1.17.0 gemfile: gemfiles/rails_5_0.gemfile + # Rails 5.2.4.1 is currently broken. Code has been fixed but no release + # for it yet - https://github.com/rails/rails/issues/38137 + - rvm: 2.2.9 + gemfile: gemfiles/rails_5_2.gemfile exclude: - rvm: 2.1.9 gemfile: gemfiles/rails_5_0.gemfile @@ -46,19 +57,19 @@ matrix: gemfile: gemfiles/rails_6_0.gemfile - rvm: 2.1.9 gemfile: gemfiles/rails_master.gemfile - - rvm: 2.2.9 + - rvm: 2.2.9 gemfile: gemfiles/rails_6_0.gemfile - rvm: 2.3.6 gemfile: gemfiles/rails_6_0.gemfile - rvm: 2.4.3 gemfile: gemfiles/rails_6_0.gemfile - - rvm: jruby-9.1.15.0 + - rvm: jruby-9.1.17.0 gemfile: gemfiles/rails_5_1.gemfile - - rvm: jruby-9.1.15.0 + - rvm: jruby-9.1.17.0 gemfile: gemfiles/rails_5_2.gemfile - - rvm: jruby-9.1.15.0 + - rvm: jruby-9.1.17.0 gemfile: gemfiles/rails_6_0.gemfile - - rvm: jruby-9.1.15.0 + - rvm: jruby-9.1.17.0 gemfile: gemfiles/rails_master.gemfile fast_finish: true cache: bundler diff --git a/Appraisals b/Appraisals index f6904095..9a5ad27a 100644 --- a/Appraisals +++ b/Appraisals @@ -1,8 +1,10 @@ -appraise "rails-4-2" do - gem "rails", "~> 4.2.0" +# frozen_string_literal: true + +appraise 'rails-4-2' do + gem 'rails', '~> 4.2.0' platforms :ruby do - gem "pg", "< 1.0.0" - gem "mysql2", "~> 0.4.0" + gem 'pg', '< 1.0.0' + gem 'mysql2', '~> 0.4.0' end platforms :jruby do gem 'activerecord-jdbc-adapter', '~> 1.3' @@ -11,10 +13,10 @@ appraise "rails-4-2" do end end -appraise "rails-5-0" do - gem "rails", "~> 5.0.0" +appraise 'rails-5-0' do + gem 'rails', '~> 5.0.0' platforms :ruby do - gem "pg", "< 1.0.0" + gem 'pg', '< 1.0.0' end platforms :jruby do gem 'activerecord-jdbc-adapter', '~> 50.0' @@ -23,10 +25,10 @@ appraise "rails-5-0" do end end -appraise "rails-5-1" do - gem "rails", "~> 5.1.0" +appraise 'rails-5-1' do + gem 'rails', '~> 5.1.0' platforms :ruby do - gem "pg", "< 1.0.0" + gem 'pg', '< 1.0.0' end platforms :jruby do gem 'activerecord-jdbc-adapter', '~> 51.0' @@ -35,8 +37,8 @@ appraise "rails-5-1" do end end -appraise "rails-5-2" do - gem "rails", "~> 5.2.0" +appraise 'rails-5-2' do + gem 'rails', '~> 5.2.0' platforms :jruby do gem 'activerecord-jdbc-adapter', '~> 52.0' gem 'activerecord-jdbcpostgresql-adapter', '~> 52.0' @@ -44,9 +46,8 @@ appraise "rails-5-2" do end end - -appraise "rails-6-0" do - gem "rails", "~> 6.0.0.rc1" +appraise 'rails-6-0' do + gem 'rails', '~> 6.0.0.rc1' platforms :ruby do gem 'sqlite3', '~> 1.4' end @@ -57,9 +58,8 @@ appraise "rails-6-0" do end end - -appraise "rails-master" do - gem "rails", git: 'https://github.com/rails/rails.git' +appraise 'rails-master' do + gem 'rails', git: 'https://github.com/rails/rails.git' platforms :ruby do gem 'sqlite3', '~> 1.4' end diff --git a/Gemfile b/Gemfile index 6c13b34a..8bad8db6 100644 --- a/Gemfile +++ b/Gemfile @@ -1,10 +1,13 @@ +# frozen_string_literal: true + source 'http://rubygems.org' gemspec -gem 'rails', '>= 3.1.2' +gem 'rails', '>= 3.1.2' +gem 'perx-rubocop', '~> 0.0.3' group :local do - gem 'pry' gem 'guard-rspec', '~> 4.2' + gem 'pry' end diff --git a/HISTORY.md b/HISTORY.md index c6e1398f..5bf2609c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,10 @@ +# 2.3.0 + * January 3, 2020 + +## Added + - Basic support for rails 6 + - Released different gem name, with same API as apartment + # 2.2.1 * June 19, 2019 diff --git a/README.md b/README.md index 6713baaa..31e8ca13 100644 --- a/README.md +++ b/README.md @@ -10,26 +10,21 @@ Apartment provides tools to help you deal with multiple tenants in your Rails application. If you need to have certain data sequestered based on account or company, but still allow some data to exist in a common tenant, Apartment can help. -## HELP! +## Apartment drop in replacement gem -In order to help drive the direction of development and clean up the codebase, we'd like to take a poll -on how people are currently using Apartment. If you can take 5 seconds (1 question) to answer -this poll, we'd greatly appreciated it. +After having reached out via github issues and email directly, no replies ever +came. Since we wanted to upgrade our application to Rails 6 we decided to fork +and start some development to support Rails 6. Because we don't have access +to the apartment gem itself, the solution was to release it under a different +name but providing the exact same API as it was before. -[View Poll](http://www.poll-maker.com/poll391552x4Bfb41a9-15) +## Help wanted -## Excessive Memory Issues on ActiveRecord 4.x - -> If you're noticing ever growing memory issues (ie growing with each tenant you add) -> when using Apartment, that's because there's [an issue](https://github.com/rails/rails/issues/19578) -> with how ActiveRecord maps Postgresql data types into AR data types. -> This has been patched and will be released for AR 4.2.2. It's apparently hard -> to backport to 4.1 unfortunately. -> If you're noticing high memory usage from ActiveRecord with Apartment please upgrade. - -```ruby -gem 'rails', '4.2.1', github: 'influitive/rails', tag: 'v4.2.1.memfix' -``` +We were never involved with the development of Apartment gem in the first place +and this project started out of our own needs. We will be more than happy +to collaborate to maintain the gem alive and supporting the latest versions +of ruby and rails, but your help is appreciated. Either by reporting bugs you +may find or proposing improvements to the gem itself. Feel free to reach out. ## Installation @@ -38,7 +33,7 @@ gem 'rails', '4.2.1', github: 'influitive/rails', tag: 'v4.2.1.memfix' Add the following to your Gemfile: ```ruby -gem 'apartment' +gem 'ros-apartment', require: 'apartment' ``` Then generate your `Apartment` config file using @@ -234,7 +229,7 @@ A Generic Elevator exists that allows you to pass a `Proc` (or anything that res module MyApplication class Application < Rails::Application # Obviously not a contrived example - config.middleware.use Apartment::Elevators::Generic, Proc.new { |request| request.host.reverse } + config.middleware.use Apartment::Elevators::Generic, proc { |request| request.host.reverse } end end ``` @@ -484,7 +479,7 @@ Note that you can disable the default migrating of all tenants with `db:migrate` Apartment supports parallelizing migrations into multiple threads when you have a large number of tenants. By default, parallel migrations is -turned off. You can enable this by setting `parallel_migration_threads` to +turned off. You can enable this by setting `parallel_migration_threads` to the number of threads you want to use in your initializer. Keep in mind that because migrations are going to access the database, @@ -531,7 +526,12 @@ end ## Background workers -See [apartment-sidekiq](https://github.com/influitive/apartment-sidekiq) or [apartment-activejob](https://github.com/influitive/apartment-activejob). +Both these gems have been forked as a side consequence of having a new gem name. +You can use them exactly as you were using before. They are, just like this one +a drop-in replacement. + +See [apartment-sidekiq](https://github.com/rails-on-services/apartment-sidekiq) +or [apartment-activejob](https://github.com/rails-on-services/apartment-activejob). ## Callbacks @@ -569,6 +569,13 @@ end * If you're looking to help, check out the TODO file for some upcoming changes I'd like to implement in Apartment. +### Running bundle install + +mysql2 gem in some cases fails to install. +If you face problems running bundle install in OSX, try installing the gem running: + +`gem install mysql2 -v '0.5.3' -- --with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include` + ## License Apartment is released under the [MIT License](http://www.opensource.org/licenses/MIT). diff --git a/Rakefile b/Rakefile index df67edc6..8eaec6d0 100644 --- a/Rakefile +++ b/Rakefile @@ -119,10 +119,18 @@ def activerecord_below_5_2? ActiveRecord.version.release < Gem::Version.new('5.2.0') end +def activerecord_below_6_0? + ActiveRecord.version.release < Gem::Version.new('6.0.0') +end + def migrate if activerecord_below_5_2? ActiveRecord::Migrator.migrate('spec/dummy/db/migrate') - else + elsif activerecord_below_6_0? ActiveRecord::MigrationContext.new('spec/dummy/db/migrate').migrate + else + # TODO: Figure out if there is any other possibility that can/should be + # passed here as the second argument for the migration context + ActiveRecord::MigrationContext.new('spec/dummy/db/migrate', ActiveRecord::SchemaMigration).migrate end end diff --git a/apartment.gemspec b/apartment.gemspec index eb59070f..e00a1304 100644 --- a/apartment.gemspec +++ b/apartment.gemspec @@ -1,42 +1,43 @@ -# -*- encoding: utf-8 -*- -$: << File.expand_path("../lib", __FILE__) -require "apartment/version" +# frozen_string_literal: true + +$LOAD_PATH << File.expand_path('lib', __dir__) +require 'apartment/version' Gem::Specification.new do |s| - s.name = %q{apartment} + s.name = 'ros-apartment' s.version = Apartment::VERSION - s.authors = ["Ryan Brunner", "Brad Robertson"] - s.summary = %q{A Ruby gem for managing database multitenancy} - s.description = %q{Apartment allows Rack applications to deal with database multitenancy through ActiveRecord} - s.email = ["ryan@influitive.com", "brad@influitive.com"] + s.authors = ['Ryan Brunner', 'Brad Robertson', 'Rui Baltazar'] + s.summary = 'A Ruby gem for managing database multitenancy. Apartment Gem drop in replacement' + s.description = 'Apartment allows Rack applications to deal with database multitenancy through ActiveRecord' + s.email = ['ryan@influitive.com', 'brad@influitive.com', 'rui.p.baltazar@gmail.com'] s.files = `git ls-files`.split($/) - s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) } + s.executables = s.files.grep(%r{^bin/}).map { |f| File.basename(f) } s.test_files = s.files.grep(%r{^(test|spec|features)/}) - s.require_paths = ["lib"] + s.require_paths = ['lib'] - s.homepage = %q{https://github.com/influitive/apartment} - s.licenses = ["MIT"] + s.homepage = 'https://github.com/rails-on-services/apartment' + s.licenses = ['MIT'] # must be >= 3.1.2 due to bug in prepared_statements s.add_dependency 'activerecord', '>= 3.1.2', '< 6.1' - s.add_dependency 'rack', '>= 1.3.6' - s.add_dependency 'public_suffix', '>= 2' s.add_dependency 'parallel', '>= 0.7.1' + s.add_dependency 'public_suffix', '>= 2' + s.add_dependency 'rack', '>= 1.3.6' s.add_development_dependency 'appraisal' + s.add_development_dependency 'bundler', '>= 1.3', '< 2.0' + s.add_development_dependency 'capybara', '~> 2.0' s.add_development_dependency 'rake', '~> 0.9' s.add_development_dependency 'rspec', '~> 3.4' s.add_development_dependency 'rspec-rails', '~> 3.4' - s.add_development_dependency 'capybara', '~> 2.0' - s.add_development_dependency 'bundler', '>= 1.3', '< 2.0' if defined?(JRUBY_VERSION) s.add_development_dependency 'activerecord-jdbc-adapter' - s.add_development_dependency 'activerecord-jdbcpostgresql-adapter' s.add_development_dependency 'activerecord-jdbcmysql-adapter' - s.add_development_dependency 'jdbc-postgres' + s.add_development_dependency 'activerecord-jdbcpostgresql-adapter' s.add_development_dependency 'jdbc-mysql' + s.add_development_dependency 'jdbc-postgres' s.add_development_dependency 'jruby-openssl' else s.add_development_dependency 'mysql2' diff --git a/gemfiles/rails_4_2.gemfile b/gemfiles/rails_4_2.gemfile index ef31a500..33048072 100644 --- a/gemfiles/rails_4_2.gemfile +++ b/gemfiles/rails_4_2.gemfile @@ -1,23 +1,25 @@ +# frozen_string_literal: true + # This file was generated by Appraisal -source "http://rubygems.org" +source 'http://rubygems.org' -gem "rails", "~> 4.2.0" +gem 'rails', '~> 4.2.0' group :local do - gem "pry" - gem "guard-rspec", "~> 4.2" + gem 'guard-rspec', '~> 4.2' + gem 'pry' end platforms :ruby do - gem "pg", "< 1.0.0" - gem "mysql2", "~> 0.4.0" + gem 'mysql2', '~> 0.4.0' + gem 'pg', '< 1.0.0' end platforms :jruby do - gem "activerecord-jdbc-adapter", "~> 1.3" - gem "activerecord-jdbcpostgresql-adapter", "~> 1.3" - gem "activerecord-jdbcmysql-adapter", "~> 1.3" + gem 'activerecord-jdbc-adapter', '~> 1.3' + gem 'activerecord-jdbcmysql-adapter', '~> 1.3' + gem 'activerecord-jdbcpostgresql-adapter', '~> 1.3' end -gemspec path: "../" +gemspec path: '../' diff --git a/gemfiles/rails_5_0.gemfile b/gemfiles/rails_5_0.gemfile index 07d99a14..3d1c50a4 100644 --- a/gemfiles/rails_5_0.gemfile +++ b/gemfiles/rails_5_0.gemfile @@ -1,22 +1,24 @@ +# frozen_string_literal: true + # This file was generated by Appraisal -source "http://rubygems.org" +source 'http://rubygems.org' -gem "rails", "~> 5.0.0" +gem 'rails', '~> 5.0.0' group :local do - gem "pry" - gem "guard-rspec", "~> 4.2" + gem 'guard-rspec', '~> 4.2' + gem 'pry' end platforms :ruby do - gem "pg", "< 1.0.0" + gem 'pg', '< 1.0.0' end platforms :jruby do - gem "activerecord-jdbc-adapter", "~> 50.0" - gem "activerecord-jdbcpostgresql-adapter", "~> 50.0" - gem "activerecord-jdbcmysql-adapter", "~> 50.0" + gem 'activerecord-jdbc-adapter', '~> 50.0' + gem 'activerecord-jdbcmysql-adapter', '~> 50.0' + gem 'activerecord-jdbcpostgresql-adapter', '~> 50.0' end -gemspec path: "../" +gemspec path: '../' diff --git a/gemfiles/rails_5_1.gemfile b/gemfiles/rails_5_1.gemfile index 28353198..fd285b95 100644 --- a/gemfiles/rails_5_1.gemfile +++ b/gemfiles/rails_5_1.gemfile @@ -1,22 +1,24 @@ +# frozen_string_literal: true + # This file was generated by Appraisal -source "http://rubygems.org" +source 'http://rubygems.org' -gem "rails", "~> 5.1.0" +gem 'rails', '~> 5.1.0' group :local do - gem "pry" - gem "guard-rspec", "~> 4.2" + gem 'guard-rspec', '~> 4.2' + gem 'pry' end platforms :ruby do - gem "pg", "< 1.0.0" + gem 'pg', '< 1.0.0' end platforms :jruby do - gem "activerecord-jdbc-adapter", "~> 51.0" - gem "activerecord-jdbcpostgresql-adapter", "~> 51.0" - gem "activerecord-jdbcmysql-adapter", "~> 51.0" + gem 'activerecord-jdbc-adapter', '~> 51.0' + gem 'activerecord-jdbcmysql-adapter', '~> 51.0' + gem 'activerecord-jdbcpostgresql-adapter', '~> 51.0' end -gemspec path: "../" +gemspec path: '../' diff --git a/gemfiles/rails_5_2.gemfile b/gemfiles/rails_5_2.gemfile index 5a18c669..fb42246f 100644 --- a/gemfiles/rails_5_2.gemfile +++ b/gemfiles/rails_5_2.gemfile @@ -1,18 +1,20 @@ +# frozen_string_literal: true + # This file was generated by Appraisal -source "http://rubygems.org" +source 'http://rubygems.org' -gem "rails", "~> 5.2.0" +gem 'rails', '~> 5.2.0' group :local do - gem "pry" - gem "guard-rspec", "~> 4.2" + gem 'guard-rspec', '~> 4.2' + gem 'pry' end platforms :jruby do - gem "activerecord-jdbc-adapter", "~> 52.0" - gem "activerecord-jdbcpostgresql-adapter", "~> 52.0" - gem "activerecord-jdbcmysql-adapter", "~> 52.0" + gem 'activerecord-jdbc-adapter', '~> 52.0' + gem 'activerecord-jdbcmysql-adapter', '~> 52.0' + gem 'activerecord-jdbcpostgresql-adapter', '~> 52.0' end -gemspec path: "../" +gemspec path: '../' diff --git a/gemfiles/rails_6_0.gemfile b/gemfiles/rails_6_0.gemfile index 20ed8a37..ec151217 100644 --- a/gemfiles/rails_6_0.gemfile +++ b/gemfiles/rails_6_0.gemfile @@ -1,22 +1,24 @@ +# frozen_string_literal: true + # This file was generated by Appraisal -source "http://rubygems.org" +source 'http://rubygems.org' -gem "rails", "~> 6.0.0.rc1" +gem 'rails', '~> 6.0.0.rc1' group :local do - gem "pry" - gem "guard-rspec", "~> 4.2" + gem 'guard-rspec', '~> 4.2' + gem 'pry' end platforms :ruby do - gem "sqlite3", "~> 1.4" + gem 'sqlite3', '~> 1.4' end platforms :jruby do - gem "activerecord-jdbc-adapter", "~> 60.0.rc1" - gem "activerecord-jdbcpostgresql-adapter", "~> 60.0.rc1" - gem "activerecord-jdbcmysql-adapter", "~> 60.0.rc1" + gem 'activerecord-jdbc-adapter', '~> 60.0.rc1' + gem 'activerecord-jdbcmysql-adapter', '~> 60.0.rc1' + gem 'activerecord-jdbcpostgresql-adapter', '~> 60.0.rc1' end -gemspec path: "../" +gemspec path: '../' diff --git a/gemfiles/rails_master.gemfile b/gemfiles/rails_master.gemfile index edc30465..af85bb04 100644 --- a/gemfiles/rails_master.gemfile +++ b/gemfiles/rails_master.gemfile @@ -1,22 +1,24 @@ +# frozen_string_literal: true + # This file was generated by Appraisal -source "http://rubygems.org" +source 'http://rubygems.org' -gem "rails", git: "https://github.com/rails/rails.git" +gem 'rails', git: 'https://github.com/rails/rails.git' group :local do - gem "pry" - gem "guard-rspec", "~> 4.2" + gem 'guard-rspec', '~> 4.2' + gem 'pry' end platforms :ruby do - gem "sqlite3", "~> 1.4" + gem 'sqlite3', '~> 1.4' end platforms :jruby do - gem "activerecord-jdbc-adapter", "~> 52.0" - gem "activerecord-jdbcpostgresql-adapter", "~> 52.0" - gem "activerecord-jdbcmysql-adapter", "~> 52.0" + gem 'activerecord-jdbc-adapter', '~> 52.0' + gem 'activerecord-jdbcmysql-adapter', '~> 52.0' + gem 'activerecord-jdbcpostgresql-adapter', '~> 52.0' end -gemspec path: "../" +gemspec path: '../' diff --git a/lib/apartment.rb b/lib/apartment.rb index b20a7728..b0d49758 100644 --- a/lib/apartment.rb +++ b/lib/apartment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'apartment/railtie' if defined?(Rails) require 'active_support/core_ext/object/blank' require 'forwardable' @@ -5,13 +7,16 @@ require 'apartment/tenant' module Apartment - class << self - extend Forwardable - ACCESSOR_METHODS = [:use_schemas, :use_sql, :seed_after_create, :prepend_environment, :append_environment, :with_multi_server_setup] - WRITER_METHODS = [:tenant_names, :database_schema_file, :excluded_models, :default_schema, :persistent_schemas, :connection_class, :tld_length, :db_migrate_tenants, :seed_data_file, :parallel_migration_threads, :pg_excluded_names] + ACCESSOR_METHODS = %i[use_schemas use_sql seed_after_create prepend_environment + append_environment with_multi_server_setup].freeze + + WRITER_METHODS = %i[tenant_names database_schema_file excluded_models + default_schema persistent_schemas connection_class + tld_length db_migrate_tenants seed_data_file + parallel_migration_threads pg_excluded_names].freeze attr_accessor(*ACCESSOR_METHODS) attr_writer(*WRITER_METHODS) @@ -49,14 +54,14 @@ def excluded_models end def default_schema - @default_schema || "public" # TODO 'public' is postgres specific + @default_schema || 'public' # TODO: 'public' is postgres specific end def parallel_migration_threads @parallel_migration_threads || 0 end - alias :default_tenant :default_schema - alias :default_tenant= :default_schema= + alias default_tenant default_schema + alias default_tenant= default_schema= def persistent_schemas @persistent_schemas || [] @@ -75,7 +80,7 @@ def database_schema_file def seed_data_file return @seed_data_file if defined?(@seed_data_file) - @seed_data_file = "#{Rails.root}/db/seeds.rb" + @seed_data_file = Rails.root.join('db', 'seeds.rb') end def pg_excluded_names @@ -84,11 +89,12 @@ def pg_excluded_names # Reset all the config for Apartment def reset - (ACCESSOR_METHODS + WRITER_METHODS).each{|method| remove_instance_variable(:"@#{method}") if instance_variable_defined?(:"@#{method}") } + (ACCESSOR_METHODS + WRITER_METHODS).each { |method| remove_instance_variable(:"@#{method}") if instance_variable_defined?(:"@#{method}") } end def extract_tenant_config return {} unless @tenant_names + values = @tenant_names.respond_to?(:call) ? @tenant_names.call : @tenant_names unless values.is_a? Hash values = values.each_with_object({}) do |tenant, hash| diff --git a/lib/apartment/adapters/abstract_adapter.rb b/lib/apartment/adapters/abstract_adapter.rb index 78b844b9..3890d661 100644 --- a/lib/apartment/adapters/abstract_adapter.rb +++ b/lib/apartment/adapters/abstract_adapter.rb @@ -1,5 +1,8 @@ +# frozen_string_literal: true + module Apartment module Adapters + # rubocop:disable Metrics/ClassLength class AbstractAdapter include ActiveSupport::Callbacks define_callbacks :create, :switch @@ -45,7 +48,7 @@ def current def default_tenant @default_tenant || Apartment.default_tenant end - alias :default_schema :default_tenant # TODO deprecate default_schema + alias default_schema default_tenant # TODO: deprecate default_schema # Drop the tenant # @@ -55,9 +58,8 @@ def drop(tenant) with_neutral_connection(tenant) do |conn| drop_command(conn, tenant) end - - rescue *rescuable_exceptions => exception - raise_drop_tenant_error!(tenant, exception) + rescue *rescuable_exceptions => e + raise_drop_tenant_error!(tenant, e) end # Switch to a new tenant @@ -79,13 +81,14 @@ def switch!(tenant = nil) # @param {String?} tenant to connect to # def switch(tenant = nil) + previous_tenant = current + switch!(tenant) + yield + ensure begin - previous_tenant = current - switch!(tenant) - yield - - ensure - switch!(previous_tenant) rescue reset + switch!(previous_tenant) + rescue StandardError => _e + reset end end @@ -93,7 +96,7 @@ def switch(tenant = nil) # def each(tenants = Apartment.tenant_names) tenants.each do |tenant| - switch(tenant){ yield tenant } + switch(tenant) { yield tenant } end end @@ -116,9 +119,9 @@ def reset # def seed_data # Don't log the output of seeding the db - silence_warnings{ load_or_raise(Apartment.seed_data_file) } if Apartment.seed_data_file + silence_warnings { load_or_raise(Apartment.seed_data_file) } if Apartment.seed_data_file end - alias_method :seed, :seed_data + alias seed seed_data # Prepend the environment if configured and the environment isn't already there # @@ -126,7 +129,7 @@ def seed_data # @return {String} tenant name with Rails environment *optionally* prepended # def environmentify(tenant) - unless tenant.include?(Rails.env) + if !tenant.include?(Rails.env) if Apartment.prepend_environment "#{Rails.env}_#{tenant}" elsif Apartment.append_environment @@ -139,7 +142,7 @@ def environmentify(tenant) end end - protected + protected def process_excluded_model(excluded_model) excluded_model.constantize.establish_connection @config @@ -158,8 +161,8 @@ def create_tenant(tenant) with_neutral_connection(tenant) do |conn| create_tenant_command(conn, tenant) end - rescue *rescuable_exceptions => exception - raise_create_tenant_error!(tenant, exception) + rescue *rescuable_exceptions => e + raise_create_tenant_error!(tenant, e) end def create_tenant_command(conn, tenant) @@ -174,18 +177,18 @@ def connect_to_new(tenant) query_cache_enabled = ActiveRecord::Base.connection.query_cache_enabled Apartment.establish_connection multi_tenantify(tenant) - Apartment.connection.active? # call active? to manually check if this connection is valid + Apartment.connection.active? # call active? to manually check if this connection is valid Apartment.connection.enable_query_cache! if query_cache_enabled - rescue *rescuable_exceptions => exception + rescue *rescuable_exceptions => e Apartment::Tenant.reset if reset_on_connection_exception? - raise_connect_error!(tenant, exception) + raise_connect_error!(tenant, e) end # Import the database schema # def import_database_schema - ActiveRecord::Schema.verbose = false # do not log schema load output. + ActiveRecord::Schema.verbose = false # do not log schema load output. load_or_raise(Apartment.database_schema_file) if Apartment.database_schema_file end @@ -196,9 +199,7 @@ def import_database_schema # if false, use the default db name from the db def multi_tenantify(tenant, with_database = true) db_connection_config(tenant).tap do |config| - if with_database - multi_tenantify_with_tenant_db_name(config, tenant) - end + multi_tenantify_with_tenant_db_name(config, tenant) if with_database end end @@ -209,14 +210,12 @@ def multi_tenantify_with_tenant_db_name(config, tenant) # Load a file or raise error if it doesn't exists # def load_or_raise(file) - if File.exists?(file) - load(file) - else - raise FileNotFound, "#{file} doesn't exist yet" - end + raise FileNotFound, "#{file} doesn't exist yet" unless File.exist?(file) + + load(file) end # Backward compatibility - alias_method :load_or_abort, :load_or_raise + alias load_or_abort load_or_raise # Exceptions to rescue from on db operations # @@ -234,7 +233,7 @@ def db_connection_config(tenant) Apartment.db_config_for(tenant).clone end - def with_neutral_connection(tenant, &block) + def with_neutral_connection(tenant, &_block) if Apartment.with_multi_server_setup # neutral connection is necessary whenever you need to create/remove a database from a server. # example: when you use postgresql, you need to connect to the default postgresql database before you create your own. @@ -251,19 +250,20 @@ def reset_on_connection_exception? end def raise_drop_tenant_error!(tenant, exception) - raise TenantNotFound, "Error while dropping tenant #{environmentify(tenant)}: #{ exception.message }" + raise TenantNotFound, "Error while dropping tenant #{environmentify(tenant)}: #{exception.message}" end def raise_create_tenant_error!(tenant, exception) - raise TenantExists, "Error while creating tenant #{environmentify(tenant)}: #{ exception.message }" + raise TenantExists, "Error while creating tenant #{environmentify(tenant)}: #{exception.message}" end def raise_connect_error!(tenant, exception) - raise TenantNotFound, "Error while connecting to tenant #{environmentify(tenant)}: #{ exception.message }" + raise TenantNotFound, "Error while connecting to tenant #{environmentify(tenant)}: #{exception.message}" end class SeparateDbConnectionHandler < ::ActiveRecord::Base end end end + # rubocop:enable Metrics/ClassLength end diff --git a/lib/apartment/adapters/abstract_jdbc_adapter.rb b/lib/apartment/adapters/abstract_jdbc_adapter.rb index c4f7f32f..d37aa79d 100644 --- a/lib/apartment/adapters/abstract_jdbc_adapter.rb +++ b/lib/apartment/adapters/abstract_jdbc_adapter.rb @@ -1,13 +1,14 @@ +# frozen_string_literal: true + require 'apartment/adapters/abstract_adapter' module Apartment module Adapters class AbstractJDBCAdapter < AbstractAdapter - - private + private def multi_tenantify_with_tenant_db_name(config, tenant) - config[:url] = "#{config[:url].gsub(/(\S+)\/.+$/, '\1')}/#{environmentify(tenant)}" + config[:url] = "#{config[:url].gsub(%r{(\S+)\/.+$}, '\1')}/#{environmentify(tenant)}" end def rescue_from diff --git a/lib/apartment/adapters/jdbc_mysql_adapter.rb b/lib/apartment/adapters/jdbc_mysql_adapter.rb index 53fc7dea..90c1bfeb 100644 --- a/lib/apartment/adapters/jdbc_mysql_adapter.rb +++ b/lib/apartment/adapters/jdbc_mysql_adapter.rb @@ -1,7 +1,8 @@ -require "apartment/adapters/abstract_jdbc_adapter" +# frozen_string_literal: true -module Apartment +require 'apartment/adapters/abstract_jdbc_adapter' +module Apartment module Tenant def self.jdbc_mysql_adapter(config) Adapters::JDBCMysqlAdapter.new config @@ -10,7 +11,6 @@ def self.jdbc_mysql_adapter(config) module Adapters class JDBCMysqlAdapter < AbstractJDBCAdapter - def reset_on_connection_exception? true end diff --git a/lib/apartment/adapters/jdbc_postgresql_adapter.rb b/lib/apartment/adapters/jdbc_postgresql_adapter.rb index f0922d8c..4353cfbf 100644 --- a/lib/apartment/adapters/jdbc_postgresql_adapter.rb +++ b/lib/apartment/adapters/jdbc_postgresql_adapter.rb @@ -1,28 +1,29 @@ +# frozen_string_literal: true + require 'apartment/adapters/postgresql_adapter' module Apartment module Tenant - def self.jdbc_postgresql_adapter(config) - Apartment.use_schemas ? - Adapters::JDBCPostgresqlSchemaAdapter.new(config) : + if Apartment.use_schemas + Adapters::JDBCPostgresqlSchemaAdapter.new(config) + else Adapters::JDBCPostgresqlAdapter.new(config) + end end end module Adapters - # Default adapter when not using Postgresql Schemas class JDBCPostgresqlAdapter < PostgresqlAdapter - - private + private def multi_tenantify_with_tenant_db_name(config, tenant) - config[:url] = "#{config[:url].gsub(/(\S+)\/.+$/, '\1')}/#{environmentify(tenant)}" + config[:url] = "#{config[:url].gsub(%r{(\S+)\/.+$}, '\1')}/#{environmentify(tenant)}" end def create_tenant_command(conn, tenant) - conn.create_database(environmentify(tenant), { :thisisahack => '' }) + conn.create_database(environmentify(tenant), thisisahack: '') end def rescue_from @@ -32,21 +33,22 @@ def rescue_from # Separate Adapter for Postgresql when using schemas class JDBCPostgresqlSchemaAdapter < PostgresqlSchemaAdapter - # Set schema search path to new schema # def connect_to_new(tenant = nil) return reset if tenant.nil? + # rubocop:disable Style/RaiseArgs raise ActiveRecord::StatementInvalid.new("Could not find schema #{tenant}") unless Apartment.connection.all_schemas.include? tenant.to_s + # rubocop:enable Style/RaiseArgs + @current = tenant.to_s Apartment.connection.schema_search_path = full_search_path - rescue ActiveRecord::StatementInvalid, ActiveRecord::JDBCError raise TenantNotFound, "One of the following schema(s) is invalid: #{full_search_path}" end - private + private def rescue_from ActiveRecord::JDBCError diff --git a/lib/apartment/adapters/mysql2_adapter.rb b/lib/apartment/adapters/mysql2_adapter.rb index d1e324ca..d35427ff 100644 --- a/lib/apartment/adapters/mysql2_adapter.rb +++ b/lib/apartment/adapters/mysql2_adapter.rb @@ -1,25 +1,27 @@ +# frozen_string_literal: true + require 'apartment/adapters/abstract_adapter' module Apartment module Tenant - def self.mysql2_adapter(config) - Apartment.use_schemas ? - Adapters::Mysql2SchemaAdapter.new(config) : + if Apartment.use_schemas + Adapters::Mysql2SchemaAdapter.new(config) + else Adapters::Mysql2Adapter.new(config) + end end end module Adapters class Mysql2Adapter < AbstractAdapter - def initialize(config) super @default_tenant = config[:database] end - protected + protected def rescue_from Mysql2::Error @@ -40,7 +42,7 @@ def reset Apartment.connection.execute "use `#{default_tenant}`" end - protected + protected # Connect to new tenant # @@ -48,10 +50,9 @@ def connect_to_new(tenant) return reset if tenant.nil? Apartment.connection.execute "use `#{environmentify(tenant)}`" - - rescue ActiveRecord::StatementInvalid => exception + rescue ActiveRecord::StatementInvalid => e Apartment::Tenant.reset - raise_connect_error!(tenant, exception) + raise_connect_error!(tenant, e) end def process_excluded_model(model) diff --git a/lib/apartment/adapters/postgis_adapter.rb b/lib/apartment/adapters/postgis_adapter.rb index 4f5e9176..bcf67be1 100644 --- a/lib/apartment/adapters/postgis_adapter.rb +++ b/lib/apartment/adapters/postgis_adapter.rb @@ -1,10 +1,11 @@ +# frozen_string_literal: true + # handle postgis adapter as if it were postgresql, # only override the adapter_method used for initialization -require "apartment/adapters/postgresql_adapter" +require 'apartment/adapters/postgresql_adapter' module Apartment module Tenant - def self.postgis_adapter(config) postgresql_adapter(config) end diff --git a/lib/apartment/adapters/postgresql_adapter.rb b/lib/apartment/adapters/postgresql_adapter.rb index 446b9b5d..3e98b627 100644 --- a/lib/apartment/adapters/postgresql_adapter.rb +++ b/lib/apartment/adapters/postgresql_adapter.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require 'apartment/adapters/abstract_adapter' module Apartment module Tenant - def self.postgresql_adapter(config) adapter = Adapters::PostgresqlAdapter adapter = Adapters::PostgresqlSchemaAdapter if Apartment.use_schemas @@ -14,8 +15,7 @@ def self.postgresql_adapter(config) module Adapters # Default adapter when not using Postgresql Schemas class PostgresqlAdapter < AbstractAdapter - - private + private def rescue_from PG::Error @@ -24,7 +24,6 @@ def rescue_from # Separate Adapter for Postgresql when using schemas class PostgresqlSchemaAdapter < AbstractAdapter - def initialize(config) super @@ -44,7 +43,7 @@ def current @current || default_tenant end - protected + protected def process_excluded_model(excluded_model) excluded_model.constantize.tap do |klass| @@ -56,39 +55,39 @@ def process_excluded_model(excluded_model) end def drop_command(conn, tenant) - conn.execute(%{DROP SCHEMA "#{tenant}" CASCADE}) + conn.execute(%(DROP SCHEMA "#{tenant}" CASCADE)) end # Set schema search path to new schema # def connect_to_new(tenant = nil) return reset if tenant.nil? + # rubocop:disable Style/RaiseArgs raise ActiveRecord::StatementInvalid.new("Could not find schema #{tenant}") unless Apartment.connection.schema_exists?(tenant.to_s) + # rubocop:enable Style/RaiseArgs + @current = tenant.to_s Apartment.connection.schema_search_path = full_search_path # When the PostgreSQL version is < 9.3, # there is a issue for prepared statement with changing search_path. # https://www.postgresql.org/docs/9.3/static/sql-prepare.html - if postgresql_version < 90300 - Apartment.connection.clear_cache! - end - + Apartment.connection.clear_cache! if postgresql_version < 90_300 rescue *rescuable_exceptions raise TenantNotFound, "One of the following schema(s) is invalid: \"#{tenant}\" #{full_search_path}" end - private + private def create_tenant_command(conn, tenant) - conn.execute(%{CREATE SCHEMA "#{tenant}"}) + conn.execute(%(CREATE SCHEMA "#{tenant}")) end # Generate the final search path to set including persistent_schemas # def full_search_path - persistent_schemas.map(&:inspect).join(", ") + persistent_schemas.map(&:inspect).join(', ') end def persistent_schemas @@ -104,16 +103,15 @@ def postgresql_version # Another Adapter for Postgresql when using schemas and SQL class PostgresqlSchemaFromSqlAdapter < PostgresqlSchemaAdapter - - PSQL_DUMP_BLACKLISTED_STATEMENTS= [ + PSQL_DUMP_BLACKLISTED_STATEMENTS = [ /SET search_path/i, # overridden later /SET lock_timeout/i, # new in postgresql 9.3 /SET row_security/i, # new in postgresql 9.5 /SET idle_in_transaction_session_timeout/i, # new in postgresql 9.6 /CREATE SCHEMA public/i, - /COMMENT ON SCHEMA public/i, + /COMMENT ON SCHEMA public/i - ] + ].freeze def import_database_schema preserving_search_path do @@ -122,14 +120,14 @@ def import_database_schema end end - private + private # Re-set search path after the schema is imported. # Postgres now sets search path to empty before dumping the schema # and it mut be reset # def preserving_search_path - search_path = Apartment.connection.execute("show search_path").first["search_path"] + search_path = Apartment.connection.execute('show search_path').first['search_path'] yield Apartment.connection.execute("set search_path = #{search_path}") end @@ -153,7 +151,6 @@ def copy_schema_migrations # @return {String} raw SQL contaning only postgres schema dump # def pg_dump_schema - # Skip excluded tables? :/ # excluded_tables = # collect_table_names(Apartment.excluded_models) @@ -176,7 +173,10 @@ def pg_dump_schema_migrations_data # Temporary set Postgresql related environment variables if there are in @config # def with_pg_env(&block) - pghost, pgport, pguser, pgpassword = ENV['PGHOST'], ENV['PGPORT'], ENV['PGUSER'], ENV['PGPASSWORD'] + pghost = ENV['PGHOST'] + pgport = ENV['PGPORT'] + pguser = ENV['PGUSER'] + pgpassword = ENV['PGPASSWORD'] ENV['PGHOST'] = @config[:host] if @config[:host] ENV['PGPORT'] = @config[:port].to_s if @config[:port] @@ -185,7 +185,10 @@ def with_pg_env(&block) block.call ensure - ENV['PGHOST'], ENV['PGPORT'], ENV['PGUSER'], ENV['PGPASSWORD'] = pghost, pgport, pguser, pgpassword + ENV['PGHOST'] = pghost + ENV['PGPORT'] = pgport + ENV['PGUSER'] = pguser + ENV['PGPASSWORD'] = pgpassword end # Remove "SET search_path ..." line from SQL dump and prepend search_path set to current tenant @@ -197,7 +200,7 @@ def patch_search_path(sql) swap_schema_qualifier(sql) .split("\n") - .select {|line| check_input_against_regexps(line, PSQL_DUMP_BLACKLISTED_STATEMENTS).empty?} + .select { |line| check_input_against_regexps(line, PSQL_DUMP_BLACKLISTED_STATEMENTS).empty? } .prepend(search_path) .join("\n") end @@ -207,7 +210,7 @@ def swap_schema_qualifier(sql) if Apartment.pg_excluded_names.any? { |name| match.include? name } match else - match.gsub("#{default_tenant}.", %{"#{current}".}) + match.gsub("#{default_tenant}.", %("#{current}".)) end end end @@ -215,7 +218,7 @@ def swap_schema_qualifier(sql) # Checks if any of regexps matches against input # def check_input_against_regexps(input, regexps) - regexps.select {|c| input.match c} + regexps.select { |c| input.match c } end # Collect table names from AR Models diff --git a/lib/apartment/adapters/sqlite3_adapter.rb b/lib/apartment/adapters/sqlite3_adapter.rb index dff5a21b..44896ef4 100644 --- a/lib/apartment/adapters/sqlite3_adapter.rb +++ b/lib/apartment/adapters/sqlite3_adapter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'apartment/adapters/abstract_adapter' module Apartment @@ -16,8 +18,10 @@ def initialize(config) end def drop(tenant) - raise TenantNotFound, - "The tenant #{environmentify(tenant)} cannot be found." unless File.exists?(database_file(tenant)) + unless File.exist?(database_file(tenant)) + raise TenantNotFound, + "The tenant #{environmentify(tenant)} cannot be found." + end File.delete(database_file(tenant)) end @@ -26,18 +30,22 @@ def current File.basename(Apartment.connection.instance_variable_get(:@config)[:database], '.sqlite3') end - protected + protected def connect_to_new(tenant) - raise TenantNotFound, - "The tenant #{environmentify(tenant)} cannot be found." unless File.exists?(database_file(tenant)) + unless File.exist?(database_file(tenant)) + raise TenantNotFound, + "The tenant #{environmentify(tenant)} cannot be found." + end super database_file(tenant) end def create_tenant(tenant) - raise TenantExists, - "The tenant #{environmentify(tenant)} already exists." if File.exists?(database_file(tenant)) + if File.exist?(database_file(tenant)) + raise TenantExists, + "The tenant #{environmentify(tenant)} already exists." + end begin f = File.new(database_file(tenant), File::CREAT) @@ -46,7 +54,7 @@ def create_tenant(tenant) end end - private + private def database_file(tenant) "#{@default_dir}/#{environmentify(tenant)}.sqlite3" diff --git a/lib/apartment/console.rb b/lib/apartment/console.rb index 6ce18832..d5a45d57 100644 --- a/lib/apartment/console.rb +++ b/lib/apartment/console.rb @@ -1,11 +1,16 @@ +# frozen_string_literal: true + # A workaraound to get `reload!` to also call Apartment::Tenant.init # This is unfortunate, but I haven't figured out how to hook into the reload process *after* files are reloaded # reloads the environment -def reload!(print=true) - puts "Reloading..." if print +def reload!(print = true) + # rubocop:disable Rails/Output + puts 'Reloading...' if print + # rubocop:enable Rails/Output + # This triggers the to_prepare callbacks - ActionDispatch::Callbacks.new(Proc.new {}).call({}) + ActionDispatch::Callbacks.new(proc {}).call({}) # Manually init Apartment again once classes are reloaded Apartment::Tenant.init true diff --git a/lib/apartment/deprecation.rb b/lib/apartment/deprecation.rb index 0b225847..db73dd5d 100644 --- a/lib/apartment/deprecation.rb +++ b/lib/apartment/deprecation.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require 'active_support/deprecation' module Apartment module Deprecation - def self.warn(message) ActiveSupport::Deprecation.warn message end diff --git a/lib/apartment/elevators/domain.rb b/lib/apartment/elevators/domain.rb index 5b81bb8a..8915289a 100644 --- a/lib/apartment/elevators/domain.rb +++ b/lib/apartment/elevators/domain.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'apartment/elevators/generic' module Apartment @@ -8,14 +10,13 @@ module Elevators # eg. example.com => example # www.example.bc.ca => example # a.example.bc.ca => a - # + # # class Domain < Generic - def parse_tenant_name(request) return nil if request.host.blank? - request.host.match(/(www\.)?(?[^.]*)/)["sld"] + request.host.match(/(www\.)?(?[^.]*)/)['sld'] end end end diff --git a/lib/apartment/elevators/first_subdomain.rb b/lib/apartment/elevators/first_subdomain.rb index 71d0d8d1..20ef3e68 100644 --- a/lib/apartment/elevators/first_subdomain.rb +++ b/lib/apartment/elevators/first_subdomain.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'apartment/elevators/subdomain' module Apartment @@ -8,10 +10,9 @@ module Elevators # - example1.domain.com => example1 # - example2.something.domain.com => example2 class FirstSubdomain < Subdomain - def parse_tenant_name(request) super.split('.')[0] unless super.nil? end end end -end \ No newline at end of file +end diff --git a/lib/apartment/elevators/generic.rb b/lib/apartment/elevators/generic.rb index 21349378..a765486e 100644 --- a/lib/apartment/elevators/generic.rb +++ b/lib/apartment/elevators/generic.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rack/request' require 'apartment/tenant' @@ -6,7 +8,6 @@ module Elevators # Provides a rack based tenant switching solution based on request # class Generic - def initialize(app, processor = nil) @app = app @processor = processor || method(:parse_tenant_name) @@ -24,8 +25,8 @@ def call(env) end end - def parse_tenant_name(request) - raise "Override" + def parse_tenant_name(_request) + raise 'Override' end end end diff --git a/lib/apartment/elevators/host.rb b/lib/apartment/elevators/host.rb index c8cbd2f8..2db8dfd0 100644 --- a/lib/apartment/elevators/host.rb +++ b/lib/apartment/elevators/host.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'apartment/elevators/generic' module Apartment @@ -16,15 +18,18 @@ def self.ignored_first_subdomains @ignored_first_subdomains ||= [] end + # rubocop:disable Style/TrivialAccessors def self.ignored_first_subdomains=(arg) @ignored_first_subdomains = arg end + # rubocop:enable Style/TrivialAccessors def parse_tenant_name(request) return nil if request.host.blank? + parts = request.host.split('.') self.class.ignored_first_subdomains.include?(parts[0]) ? parts.drop(1).join('.') : request.host end end end -end \ No newline at end of file +end diff --git a/lib/apartment/elevators/host_hash.rb b/lib/apartment/elevators/host_hash.rb index 7a0454f1..f68c10cb 100644 --- a/lib/apartment/elevators/host_hash.rb +++ b/lib/apartment/elevators/host_hash.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'apartment/elevators/generic' module Apartment @@ -12,8 +14,10 @@ def initialize(app, hash = {}, processor = nil) end def parse_tenant_name(request) - raise TenantNotFound, - "Cannot find tenant for host #{request.host}" unless @hash.has_key?(request.host) + unless @hash.key?(request.host) + raise TenantNotFound, + "Cannot find tenant for host #{request.host}" + end @hash[request.host] end diff --git a/lib/apartment/elevators/subdomain.rb b/lib/apartment/elevators/subdomain.rb index c625e29b..38604d60 100644 --- a/lib/apartment/elevators/subdomain.rb +++ b/lib/apartment/elevators/subdomain.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'apartment/elevators/generic' require 'public_suffix' @@ -11,9 +13,11 @@ def self.excluded_subdomains @excluded_subdomains ||= [] end + # rubocop:disable Style/TrivialAccessors def self.excluded_subdomains=(arg) @excluded_subdomains = arg end + # rubocop:enable Style/TrivialAccessors def parse_tenant_name(request) request_subdomain = subdomain(request.host) @@ -21,15 +25,15 @@ def parse_tenant_name(request) # If the domain acquired is set to be excluded, set the tenant to whatever is currently # next in line in the schema search path. tenant = if self.class.excluded_subdomains.include?(request_subdomain) - nil - else - request_subdomain - end + nil + else + request_subdomain + end tenant.presence end - protected + protected # *Almost* a direct ripoff of ActionDispatch::Request subdomain methods diff --git a/lib/apartment/migrator.rb b/lib/apartment/migrator.rb index c99e9a3b..089109df 100644 --- a/lib/apartment/migrator.rb +++ b/lib/apartment/migrator.rb @@ -1,16 +1,17 @@ +# frozen_string_literal: true + require 'apartment/tenant' module Apartment module Migrator - extend self # Migrate to latest def migrate(database) Tenant.switch(database) do - version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil + version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil - migration_scope_block = -> (migration) { ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope) } + migration_scope_block = ->(migration) { ENV['SCOPE'].blank? || (ENV['SCOPE'] == migration.scope) } if activerecord_below_5_2? ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, version, &migration_scope_block) diff --git a/lib/apartment/railtie.rb b/lib/apartment/railtie.rb index 6a18833f..e082ab9e 100644 --- a/lib/apartment/railtie.rb +++ b/lib/apartment/railtie.rb @@ -1,10 +1,11 @@ +# frozen_string_literal: true + require 'rails' require 'apartment/tenant' require 'apartment/reloader' module Apartment class Railtie < Rails::Railtie - # # Set up our default config options # Do this before the app initializers run so we don't override custom settings @@ -33,10 +34,15 @@ class Railtie < Rails::Railtie Apartment.connection_class.connection_pool.with_connection do Apartment::Tenant.init end - rescue ::ActiveRecord::NoDatabaseError + # rubocop:disable Lint/SuppressedException + rescue ::ActiveRecord::NoDatabaseError, PG::ConnectionBad # Since `db:create` and other tasks invoke this block from Rails 5.2.0, # we need to swallow the error to execute `db:create` properly. + Rails.logger.warn do + 'Failed to initialize Apartment because a database connection could not be established.' + end end + # rubocop:enable Lint/SuppressedException end # @@ -48,8 +54,10 @@ class Railtie < Rails::Railtie end # - # The following initializers are a workaround to the fact that I can't properly hook into the rails reloader - # Note this is technically valid for any environment where cache_classes is false, for us, it's just development + # The following initializers are a workaround to the fact that I can't + # properly hook into the rails reloader + # Note this is technically valid for any environment where cache_classes + # is false, for us, it's just development # if Rails.env.development? @@ -58,7 +66,8 @@ class Railtie < Rails::Railtie app.config.middleware.use Apartment::Reloader end - # Overrides reload! to also call Apartment::Tenant.init as well so that the reloaded classes have the proper table_names + # Overrides reload! to also call Apartment::Tenant.init as well so that the + # reloaded classes have the proper table_names console do require 'apartment/console' end diff --git a/lib/apartment/reloader.rb b/lib/apartment/reloader.rb index fd315371..cd8b6861 100644 --- a/lib/apartment/reloader.rb +++ b/lib/apartment/reloader.rb @@ -1,6 +1,7 @@ +# frozen_string_literal: true + module Apartment class Reloader - # Middleware used in development to init Apartment for each request # Necessary due to code reload (annoying). When models are reloaded, they no longer have the proper table_name # That is prepended with the schema (if using postgresql schemas) diff --git a/lib/apartment/tasks/enhancements.rb b/lib/apartment/tasks/enhancements.rb index ce93e58a..f9a13206 100644 --- a/lib/apartment/tasks/enhancements.rb +++ b/lib/apartment/tasks/enhancements.rb @@ -1,12 +1,13 @@ +# frozen_string_literal: true + # Require this file to append Apartment rake tasks to ActiveRecord db rake tasks # Enabled by default in the initializer module Apartment class RakeTaskEnhancer - module TASKS - ENHANCE_BEFORE = %w(db:drop) - ENHANCE_AFTER = %w(db:migrate db:rollback db:migrate:up db:migrate:down db:migrate:redo db:seed) + ENHANCE_BEFORE = %w[db:drop].freeze + ENHANCE_AFTER = %w[db:migrate db:rollback db:migrate:up db:migrate:down db:migrate:redo db:seed].freeze freeze end @@ -28,7 +29,6 @@ def enhance! task = Rake::Task[name] enhance_after_task(task) end - end def should_enhance? @@ -48,9 +48,7 @@ def enhance_after_task(task) def inserted_task_name(task) task.name.sub(/db:/, 'apartment:') end - end - end end diff --git a/lib/apartment/tenant.rb b/lib/apartment/tenant.rb index acabad31..93e755a0 100644 --- a/lib/apartment/tenant.rb +++ b/lib/apartment/tenant.rb @@ -1,10 +1,11 @@ +# frozen_string_literal: true + require 'forwardable' module Apartment # The main entry point to Apartment functions # module Tenant - extend self extend Forwardable @@ -40,9 +41,7 @@ def adapter raise "The adapter `#{adapter_method}` is not yet supported" end - unless respond_to?(adapter_method) - raise AdapterNotFound, "database configuration specifies nonexistent #{config[:adapter]} adapter" - end + raise AdapterNotFound, "database configuration specifies nonexistent #{config[:adapter]} adapter" unless respond_to?(adapter_method) send(adapter_method, config) end diff --git a/lib/apartment/version.rb b/lib/apartment/version.rb index 40b2f751..8f84b610 100644 --- a/lib/apartment/version.rb +++ b/lib/apartment/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Apartment - VERSION = "2.2.1" + VERSION = '2.3.0' end diff --git a/lib/generators/apartment/install/install_generator.rb b/lib/generators/apartment/install/install_generator.rb index eb7cbe66..9fe7152e 100755 --- a/lib/generators/apartment/install/install_generator.rb +++ b/lib/generators/apartment/install/install_generator.rb @@ -1,10 +1,11 @@ +# frozen_string_literal: true + module Apartment class InstallGenerator < Rails::Generators::Base - source_root File.expand_path('../templates', __FILE__) + source_root File.expand_path('templates', __dir__) def copy_files - template "apartment.rb", File.join("config", "initializers", "apartment.rb") + template 'apartment.rb', File.join('config', 'initializers', 'apartment.rb') end - end end diff --git a/lib/generators/apartment/install/templates/apartment.rb b/lib/generators/apartment/install/templates/apartment.rb index 6c7c52fb..2a774737 100644 --- a/lib/generators/apartment/install/templates/apartment.rb +++ b/lib/generators/apartment/install/templates/apartment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # You can have Apartment route to the appropriate Tenant by adding some Rack middleware. # Apartment can support many different "Elevators" that can take care of this routing to your data. # Require whichever Elevator you're using below or none if you have a custom one. @@ -12,7 +14,6 @@ # Apartment Configuration # Apartment.configure do |config| - # Add any models that you do not want to be multi-tenanted, but remain in the global (public) namespace. # A typical example would be a Customer or Tenant model that stores each Tenant's information. # @@ -48,7 +49,7 @@ # end # end # - config.tenant_names = lambda { ToDo_Tenant_Or_User_Model.pluck :database } + config.tenant_names = -> { ToDo_Tenant_Or_User_Model.pluck :database } # PostgreSQL: # Specifies whether to use PostgreSQL schemas or create a new database per Tenant. diff --git a/lib/tasks/apartment.rake b/lib/tasks/apartment.rake index bccd9dd2..437deda7 100644 --- a/lib/tasks/apartment.rake +++ b/lib/tasks/apartment.rake @@ -1,9 +1,10 @@ +# frozen_string_literal: true + require 'apartment/migrator' require 'parallel' apartment_namespace = namespace :apartment do - - desc "Create all tenants" + desc 'Create all tenants' task :create do tenants.each do |tenant| begin @@ -15,7 +16,7 @@ apartment_namespace = namespace :apartment do end end - desc "Drop all tenants" + desc 'Drop all tenants' task :drop do tenants.each do |tenant| begin @@ -27,7 +28,7 @@ apartment_namespace = namespace :apartment do end end - desc "Migrate all tenants" + desc 'Migrate all tenants' task :migrate do warn_if_tenants_empty each_tenant do |tenant| @@ -40,7 +41,7 @@ apartment_namespace = namespace :apartment do end end - desc "Seed all tenants" + desc 'Seed all tenants' task :seed do warn_if_tenants_empty @@ -56,7 +57,7 @@ apartment_namespace = namespace :apartment do end end - desc "Rolls the migration back to the previous version (specify steps w/ STEP=n) across all tenants." + desc 'Rolls the migration back to the previous version (specify steps w/ STEP=n) across all tenants.' task :rollback do warn_if_tenants_empty @@ -107,7 +108,7 @@ apartment_namespace = namespace :apartment do end end - desc 'Rolls back the tenant one migration and re migrate up (options: STEP=x, VERSION=x).' + desc 'Rolls back the tenant one migration and re migrate up (options: STEP=x, VERSION=x).' task :redo do if ENV['VERSION'] apartment_namespace['migrate:down'].invoke @@ -126,20 +127,20 @@ apartment_namespace = namespace :apartment do end def tenants - ENV['DB'] ? ENV['DB'].split(',').map { |s| s.strip } : Apartment.tenant_names || [] + ENV['DB'] ? ENV['DB'].split(',').map(&:strip) : Apartment.tenant_names || [] end def warn_if_tenants_empty - if tenants.empty? && ENV['IGNORE_EMPTY_TENANTS'] != "true" - puts <<-WARNING - [WARNING] - The list of tenants to migrate appears to be empty. This could mean a few things: + return unless tenants.empty? && ENV['IGNORE_EMPTY_TENANTS'] != 'true' - 1. You may not have created any, in which case you can ignore this message - 2. You've run `apartment:migrate` directly without loading the Rails environment - * `apartment:migrate` is now deprecated. Tenants will automatically be migrated with `db:migrate` + puts <<-WARNING + [WARNING] - The list of tenants to migrate appears to be empty. This could mean a few things: - Note that your tenants currently haven't been migrated. You'll need to run `db:migrate` to rectify this. - WARNING - end + 1. You may not have created any, in which case you can ignore this message + 2. You've run `apartment:migrate` directly without loading the Rails environment + * `apartment:migrate` is now deprecated. Tenants will automatically be migrated with `db:migrate` + + Note that your tenants currently haven't been migrated. You'll need to run `db:migrate` to rectify this. + WARNING end end diff --git a/spec/adapters/jdbc_mysql_adapter_spec.rb b/spec/adapters/jdbc_mysql_adapter_spec.rb index 1fee3e14..4833f93d 100644 --- a/spec/adapters/jdbc_mysql_adapter_spec.rb +++ b/spec/adapters/jdbc_mysql_adapter_spec.rb @@ -1,19 +1,20 @@ +# frozen_string_literal: true + if defined?(JRUBY_VERSION) require 'spec_helper' require 'apartment/adapters/jdbc_mysql_adapter' describe Apartment::Adapters::JDBCMysqlAdapter, database: :mysql do - subject { Apartment::Tenant.jdbc_mysql_adapter config.symbolize_keys } def tenant_names - ActiveRecord::Base.connection.execute("SELECT schema_name FROM information_schema.schemata").collect { |row| row['schema_name'] } + ActiveRecord::Base.connection.execute('SELECT schema_name FROM information_schema.schemata').collect { |row| row['schema_name'] } end let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.current_database } } - it_should_behave_like "a generic apartment adapter" - it_should_behave_like "a connection based apartment adapter" + it_should_behave_like 'a generic apartment adapter' + it_should_behave_like 'a connection based apartment adapter' end end diff --git a/spec/adapters/jdbc_postgresql_adapter_spec.rb b/spec/adapters/jdbc_postgresql_adapter_spec.rb index 28cf135f..49dfaf1a 100644 --- a/spec/adapters/jdbc_postgresql_adapter_spec.rb +++ b/spec/adapters/jdbc_postgresql_adapter_spec.rb @@ -1,41 +1,39 @@ +# frozen_string_literal: true + if defined?(JRUBY_VERSION) require 'spec_helper' require 'apartment/adapters/jdbc_postgresql_adapter' describe Apartment::Adapters::JDBCPostgresqlAdapter, database: :postgresql do - subject { Apartment::Tenant.jdbc_postgresql_adapter config.symbolize_keys } - context "using schemas" do - + context 'using schemas' do before { Apartment.use_schemas = true } # Not sure why, but somehow using let(:tenant_names) memoizes for the whole example group, not just each test def tenant_names - ActiveRecord::Base.connection.execute("SELECT nspname FROM pg_namespace;").collect { |row| row['nspname'] } + ActiveRecord::Base.connection.execute('SELECT nspname FROM pg_namespace;').collect { |row| row['nspname'] } end let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.schema_search_path.gsub('"', '') } } - it_should_behave_like "a generic apartment adapter" - it_should_behave_like "a schema based apartment adapter" + it_should_behave_like 'a generic apartment adapter' + it_should_behave_like 'a schema based apartment adapter' end - context "using databases" do - + context 'using databases' do before { Apartment.use_schemas = false } # Not sure why, but somehow using let(:tenant_names) memoizes for the whole example group, not just each test def tenant_names - connection.execute("select datname from pg_database;").collect { |row| row['datname'] } + connection.execute('select datname from pg_database;').collect { |row| row['datname'] } end let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.current_database } } - it_should_behave_like "a generic apartment adapter" - it_should_behave_like "a connection based apartment adapter" - + it_should_behave_like 'a generic apartment adapter' + it_should_behave_like 'a connection based apartment adapter' end end end diff --git a/spec/adapters/mysql2_adapter_spec.rb b/spec/adapters/mysql2_adapter_spec.rb index 78f7b589..29529514 100644 --- a/spec/adapters/mysql2_adapter_spec.rb +++ b/spec/adapters/mysql2_adapter_spec.rb @@ -1,34 +1,36 @@ +# frozen_string_literal: true + require 'spec_helper' require 'apartment/adapters/mysql2_adapter' describe Apartment::Adapters::Mysql2Adapter, database: :mysql do unless defined?(JRUBY_VERSION) - subject(:adapter){ Apartment::Tenant.mysql2_adapter config } + subject(:adapter) { Apartment::Tenant.mysql2_adapter config } def tenant_names - ActiveRecord::Base.connection.execute("SELECT schema_name FROM information_schema.schemata").collect { |row| row[0] } + ActiveRecord::Base.connection.execute('SELECT schema_name FROM information_schema.schemata').collect { |row| row[0] } end let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.current_database } } - context "using - the equivalent of - schemas" do + context 'using - the equivalent of - schemas' do before { Apartment.use_schemas = true } - it_should_behave_like "a generic apartment adapter" + it_should_behave_like 'a generic apartment adapter' - describe "#default_tenant" do - it "is set to the original db from config" do + describe '#default_tenant' do + it 'is set to the original db from config' do expect(subject.default_tenant).to eq(config[:database]) end end - describe "#init" do + describe '#init' do include Apartment::Spec::AdapterRequirements before do Apartment.configure do |config| - config.excluded_models = ["Company"] + config.excluded_models = ['Company'] end end @@ -40,7 +42,7 @@ def tenant_names end end - it "should process model exclusions" do + it 'should process model exclusions' do Apartment::Tenant.init expect(Company.table_name).to eq("#{default_tenant}.companies") @@ -48,12 +50,12 @@ def tenant_names end end - context "using connections" do + context 'using connections' do before { Apartment.use_schemas = false } - it_should_behave_like "a generic apartment adapter" - it_should_behave_like "a generic apartment adapter able to handle custom configuration" - it_should_behave_like "a connection based apartment adapter" + it_should_behave_like 'a generic apartment adapter' + it_should_behave_like 'a generic apartment adapter able to handle custom configuration' + it_should_behave_like 'a connection based apartment adapter' end end end diff --git a/spec/adapters/postgresql_adapter_spec.rb b/spec/adapters/postgresql_adapter_spec.rb index e246fd10..d553ff8b 100644 --- a/spec/adapters/postgresql_adapter_spec.rb +++ b/spec/adapters/postgresql_adapter_spec.rb @@ -1,39 +1,42 @@ +# frozen_string_literal: true + require 'spec_helper' require 'apartment/adapters/postgresql_adapter' describe Apartment::Adapters::PostgresqlAdapter, database: :postgresql do unless defined?(JRUBY_VERSION) - subject{ Apartment::Tenant.postgresql_adapter config } - - context "using schemas with schema.rb" do + subject { Apartment::Tenant.postgresql_adapter config } - before{ Apartment.use_schemas = true } + context 'using schemas with schema.rb' do + before { Apartment.use_schemas = true } # Not sure why, but somehow using let(:tenant_names) memoizes for the whole example group, not just each test def tenant_names - ActiveRecord::Base.connection.execute("SELECT nspname FROM pg_namespace;").collect { |row| row['nspname'] } + ActiveRecord::Base.connection.execute('SELECT nspname FROM pg_namespace;').collect { |row| row['nspname'] } end let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.schema_search_path.gsub('"', '') } } - it_should_behave_like "a generic apartment adapter" - it_should_behave_like "a schema based apartment adapter" + it_should_behave_like 'a generic apartment adapter' + it_should_behave_like 'a schema based apartment adapter' end - context "using schemas with SQL dump" do - - before{ Apartment.use_schemas = true; Apartment.use_sql = true } + context 'using schemas with SQL dump' do + before do + Apartment.use_schemas = true + Apartment.use_sql = true + end # Not sure why, but somehow using let(:tenant_names) memoizes for the whole example group, not just each test def tenant_names - ActiveRecord::Base.connection.execute("SELECT nspname FROM pg_namespace;").collect { |row| row['nspname'] } + ActiveRecord::Base.connection.execute('SELECT nspname FROM pg_namespace;').collect { |row| row['nspname'] } end let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.schema_search_path.gsub('"', '') } } - it_should_behave_like "a generic apartment adapter" - it_should_behave_like "a schema based apartment adapter" + it_should_behave_like 'a generic apartment adapter' + it_should_behave_like 'a schema based apartment adapter' it 'allows for dashes in the schema name' do expect { Apartment::Tenant.create('has-dashes') }.to_not raise_error @@ -42,20 +45,19 @@ def tenant_names after { Apartment::Tenant.drop('has-dashes') if Apartment.connection.schema_exists? 'has-dashes' } end - context "using connections" do - - before{ Apartment.use_schemas = false } + context 'using connections' do + before { Apartment.use_schemas = false } # Not sure why, but somehow using let(:tenant_names) memoizes for the whole example group, not just each test def tenant_names - connection.execute("select datname from pg_database;").collect { |row| row['datname'] } + connection.execute('select datname from pg_database;').collect { |row| row['datname'] } end let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.current_database } } - it_should_behave_like "a generic apartment adapter" - it_should_behave_like "a generic apartment adapter able to handle custom configuration" - it_should_behave_like "a connection based apartment adapter" + it_should_behave_like 'a generic apartment adapter' + it_should_behave_like 'a generic apartment adapter able to handle custom configuration' + it_should_behave_like 'a connection based apartment adapter' end end end diff --git a/spec/adapters/sqlite3_adapter_spec.rb b/spec/adapters/sqlite3_adapter_spec.rb index 55004952..252cdb66 100644 --- a/spec/adapters/sqlite3_adapter_spec.rb +++ b/spec/adapters/sqlite3_adapter_spec.rb @@ -1,14 +1,16 @@ +# frozen_string_literal: true + require 'spec_helper' require 'apartment/adapters/sqlite3_adapter' describe Apartment::Adapters::Sqlite3Adapter, database: :sqlite do unless defined?(JRUBY_VERSION) - subject{ Apartment::Tenant.sqlite3_adapter config } + subject { Apartment::Tenant.sqlite3_adapter config } - context "using connections" do + context 'using connections' do def tenant_names - db_dir = File.expand_path("../../dummy/db", __FILE__) + db_dir = File.expand_path('../dummy/db', __dir__) Dir.glob("#{db_dir}/*.sqlite3").map { |file| File.basename(file, '.sqlite3') } end @@ -16,18 +18,18 @@ def tenant_names subject.switch { File.basename(Apartment::Test.config['connections']['sqlite']['database'], '.sqlite3') } end - it_should_behave_like "a generic apartment adapter" - it_should_behave_like "a connection based apartment adapter" + it_should_behave_like 'a generic apartment adapter' + it_should_behave_like 'a connection based apartment adapter' after(:all) do File.delete(Apartment::Test.config['connections']['sqlite']['database']) end end - context "with prepend and append" do + context 'with prepend and append' do let(:default_dir) { File.expand_path(File.dirname(config[:database])) } - describe "#prepend" do - let (:db_name) { "db_with_prefix" } + describe '#prepend' do + let(:db_name) { 'db_with_prefix' } before do Apartment.configure do |config| config.prepend_environment = true @@ -35,32 +37,44 @@ def tenant_names end end - after { subject.drop db_name rescue nil } + after do + begin + subject.drop db_name + rescue StandardError => _e + nil + end + end - it "should create a new database" do + it 'should create a new database' do subject.create db_name - expect(File.exists?("#{default_dir}/#{Rails.env}_#{db_name}.sqlite3")).to eq true + expect(File.exist?("#{default_dir}/#{Rails.env}_#{db_name}.sqlite3")).to eq true end end - describe "#neither" do - let (:db_name) { "db_without_prefix_suffix" } + describe '#neither' do + let(:db_name) { 'db_without_prefix_suffix' } before do Apartment.configure { |config| config.prepend_environment = config.append_environment = false } end - after { subject.drop db_name rescue nil } + after do + begin + subject.drop db_name + rescue StandardError => _e + nil + end + end - it "should create a new database" do + it 'should create a new database' do subject.create db_name - expect(File.exists?("#{default_dir}/#{db_name}.sqlite3")).to eq true + expect(File.exist?("#{default_dir}/#{db_name}.sqlite3")).to eq true end end - describe "#append" do - let (:db_name) { "db_with_suffix" } + describe '#append' do + let(:db_name) { 'db_with_suffix' } before do Apartment.configure do |config| config.prepend_environment = false @@ -68,16 +82,20 @@ def tenant_names end end - after { subject.drop db_name rescue nil } + after do + begin + subject.drop db_name + rescue StandardError => _e + nil + end + end - it "should create a new database" do + it 'should create a new database' do subject.create db_name - expect(File.exists?("#{default_dir}/#{db_name}_#{Rails.env}.sqlite3")).to eq true + expect(File.exist?("#{default_dir}/#{db_name}_#{Rails.env}.sqlite3")).to eq true end end - end - end end diff --git a/spec/apartment_spec.rb b/spec/apartment_spec.rb index b00e0b2d..f90a09f2 100644 --- a/spec/apartment_spec.rb +++ b/spec/apartment_spec.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + require 'spec_helper' describe Apartment do - it "should be valid" do + it 'should be valid' do expect(Apartment).to be_a(Module) end - it "should be a valid app" do + it 'should be a valid app' do expect(::Rails.application).to be_a(Dummy::Application) end end diff --git a/spec/dummy/app/controllers/application_controller.rb b/spec/dummy/app/controllers/application_controller.rb index 4c655b70..3615e013 100644 --- a/spec/dummy/app/controllers/application_controller.rb +++ b/spec/dummy/app/controllers/application_controller.rb @@ -1,6 +1,7 @@ +# frozen_string_literal: true + class ApplicationController < ActionController::Base protect_from_forgery - - def index - end + + def index; end end diff --git a/spec/dummy/app/helpers/application_helper.rb b/spec/dummy/app/helpers/application_helper.rb index de6be794..15b06f0f 100644 --- a/spec/dummy/app/helpers/application_helper.rb +++ b/spec/dummy/app/helpers/application_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module ApplicationHelper end diff --git a/spec/dummy/app/models/application_record.rb b/spec/dummy/app/models/application_record.rb new file mode 100644 index 00000000..1d405ba4 --- /dev/null +++ b/spec/dummy/app/models/application_record.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# NOTE: Dummy model base +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/spec/dummy/app/models/company.rb b/spec/dummy/app/models/company.rb index dd5bf8c7..96986b7d 100644 --- a/spec/dummy/app/models/company.rb +++ b/spec/dummy/app/models/company.rb @@ -1,3 +1,5 @@ -class Company < ActiveRecord::Base +# frozen_string_literal: true + +class Company < ApplicationRecord # Dummy models -end \ No newline at end of file +end diff --git a/spec/dummy/app/models/user.rb b/spec/dummy/app/models/user.rb index 145f27f9..463ce352 100644 --- a/spec/dummy/app/models/user.rb +++ b/spec/dummy/app/models/user.rb @@ -1,3 +1,5 @@ -class User < ActiveRecord::Base +# frozen_string_literal: true + +class User < ApplicationRecord # Dummy models -end \ No newline at end of file +end diff --git a/spec/dummy/config.ru b/spec/dummy/config.ru index 1989ed8d..989f7c64 100644 --- a/spec/dummy/config.ru +++ b/spec/dummy/config.ru @@ -1,4 +1,6 @@ +# frozen_string_literal: true + # This file is used by Rack-based servers to start the application. -require ::File.expand_path('../config/environment', __FILE__) +require ::File.expand_path('../config/environment', __FILE__) run Dummy::Application diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb index e8f51ed9..49b5d459 100644 --- a/spec/dummy/config/application.rb +++ b/spec/dummy/config/application.rb @@ -1,13 +1,15 @@ -require File.expand_path('../boot', __FILE__) +# frozen_string_literal: true -require "active_model/railtie" -require "active_record/railtie" -require "action_controller/railtie" -require "action_view/railtie" -require "action_mailer/railtie" +require File.expand_path('boot', __dir__) + +require 'active_model/railtie' +require 'active_record/railtie' +require 'action_controller/railtie' +require 'action_view/railtie' +require 'action_mailer/railtie' Bundler.require -require "apartment" +require 'apartment' module Dummy class Application < Rails::Application @@ -20,7 +22,7 @@ class Application < Rails::Application config.middleware.use Apartment::Elevators::Subdomain # Custom directories with classes and modules you want to be autoloadable. - config.autoload_paths += %W(#{config.root}/lib) + config.autoload_paths += %W[#{config.root}/lib] # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. @@ -41,7 +43,7 @@ class Application < Rails::Application # config.action_view.javascript_expansions[:defaults] = %w(jquery rails) # Configure the default encoding used in templates for Ruby 1.9. - config.encoding = "utf-8" + config.encoding = 'utf-8' # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters += [:password] diff --git a/spec/dummy/config/boot.rb b/spec/dummy/config/boot.rb index 490d7917..0c68bf2c 100644 --- a/spec/dummy/config/boot.rb +++ b/spec/dummy/config/boot.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require 'rubygems' -gemfile = File.expand_path('../../../../Gemfile', __FILE__) +gemfile = File.expand_path('../../../Gemfile', __dir__) if File.exist?(gemfile) ENV['BUNDLE_GEMFILE'] = gemfile @@ -8,4 +10,4 @@ Bundler.setup end -$:.unshift File.expand_path('../../../../lib', __FILE__) \ No newline at end of file +$LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) diff --git a/spec/dummy/config/environment.rb b/spec/dummy/config/environment.rb index 3da5eb91..65c03fc7 100644 --- a/spec/dummy/config/environment.rb +++ b/spec/dummy/config/environment.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + # Load the rails application -require File.expand_path('../application', __FILE__) +require File.expand_path('application', __dir__) # Initialize the rails application Dummy::Application.initialize! diff --git a/spec/dummy/config/environments/development.rb b/spec/dummy/config/environments/development.rb index c143a826..77567be6 100644 --- a/spec/dummy/config/environments/development.rb +++ b/spec/dummy/config/environments/development.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Dummy::Application.configure do # Settings specified here will take precedence over those in config/application.rb @@ -25,4 +27,3 @@ # Only use best-standards-support built into browsers config.action_dispatch.best_standards_support = :builtin end - diff --git a/spec/dummy/config/environments/production.rb b/spec/dummy/config/environments/production.rb index a71b06c4..1d9b71e1 100644 --- a/spec/dummy/config/environments/production.rb +++ b/spec/dummy/config/environments/production.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Dummy::Application.configure do # Settings specified here will take precedence over those in config/application.rb @@ -12,7 +14,7 @@ config.action_controller.perform_caching = true # Specifies the header that your server uses for sending files - config.action_dispatch.x_sendfile_header = "X-Sendfile" + config.action_dispatch.x_sendfile_header = 'X-Sendfile' # For nginx: # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' diff --git a/spec/dummy/config/environments/test.rb b/spec/dummy/config/environments/test.rb index 30879efd..3044c445 100644 --- a/spec/dummy/config/environments/test.rb +++ b/spec/dummy/config/environments/test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Dummy::Application.configure do # Settings specified here will take precedence over those in config/application.rb @@ -17,7 +19,7 @@ config.action_dispatch.show_exceptions = false # Disable request forgery protection in test environment - config.action_controller.allow_forgery_protection = false + config.action_controller.allow_forgery_protection = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the diff --git a/spec/dummy/config/initializers/apartment.rb b/spec/dummy/config/initializers/apartment.rb index a49dda91..7db9fd26 100644 --- a/spec/dummy/config/initializers/apartment.rb +++ b/spec/dummy/config/initializers/apartment.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + Apartment.configure do |config| - config.excluded_models = ["Company"] - config.tenant_names = lambda{ Company.pluck(:database) } + config.excluded_models = ['Company'] + config.tenant_names = -> { Company.pluck(:database) } end diff --git a/spec/dummy/config/initializers/backtrace_silencers.rb b/spec/dummy/config/initializers/backtrace_silencers.rb index 59385cdf..d0f0d3b5 100644 --- a/spec/dummy/config/initializers/backtrace_silencers.rb +++ b/spec/dummy/config/initializers/backtrace_silencers.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. diff --git a/spec/dummy/config/initializers/inflections.rb b/spec/dummy/config/initializers/inflections.rb index 9e8b0131..8138cabc 100644 --- a/spec/dummy/config/initializers/inflections.rb +++ b/spec/dummy/config/initializers/inflections.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # Add new inflection rules using the following format diff --git a/spec/dummy/config/initializers/mime_types.rb b/spec/dummy/config/initializers/mime_types.rb index 72aca7e4..f75864f9 100644 --- a/spec/dummy/config/initializers/mime_types.rb +++ b/spec/dummy/config/initializers/mime_types.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # Add new mime types for use in respond_to blocks: diff --git a/spec/dummy/config/initializers/secret_token.rb b/spec/dummy/config/initializers/secret_token.rb index 1c651c86..2c7f52bd 100644 --- a/spec/dummy/config/initializers/secret_token.rb +++ b/spec/dummy/config/initializers/secret_token.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Your secret key for verifying the integrity of signed cookies. diff --git a/spec/dummy/config/initializers/session_store.rb b/spec/dummy/config/initializers/session_store.rb index aa2f5129..66099cf5 100644 --- a/spec/dummy/config/initializers/session_store.rb +++ b/spec/dummy/config/initializers/session_store.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. -Dummy::Application.config.session_store :cookie_store, :key => '_dummy_session' +Dummy::Application.config.session_store :cookie_store, key: '_dummy_session' # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information diff --git a/spec/dummy/config/routes.rb b/spec/dummy/config/routes.rb index 99d3e5c1..d0be0e6d 100644 --- a/spec/dummy/config/routes.rb +++ b/spec/dummy/config/routes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Dummy::Application.routes.draw do - root :to => 'application#index' + root to: 'application#index' end diff --git a/spec/dummy/db/seeds/import.rb b/spec/dummy/db/seeds/import.rb index 8265d6be..10b479b9 100644 --- a/spec/dummy/db/seeds/import.rb +++ b/spec/dummy/db/seeds/import.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + def create_users - 6.times {|x| User.where(name: "Different User #{x}").first_or_create! } + 6.times { |x| User.where(name: "Different User #{x}").first_or_create! } end create_users diff --git a/spec/dummy/script/rails b/spec/dummy/script/rails index f8da2cff..e1068b28 100755 --- a/spec/dummy/script/rails +++ b/spec/dummy/script/rails @@ -1,6 +1,8 @@ #!/usr/bin/env ruby +# frozen_string_literal: true + # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. -APP_PATH = File.expand_path('../../config/application', __FILE__) -require File.expand_path('../../config/boot', __FILE__) +APP_PATH = File.expand_path('../config/application', __dir__) +require File.expand_path('../config/boot', __dir__) require 'rails/commands' diff --git a/spec/dummy_engine/config/initializers/apartment.rb b/spec/dummy_engine/config/initializers/apartment.rb index 611f5322..466f3d87 100644 --- a/spec/dummy_engine/config/initializers/apartment.rb +++ b/spec/dummy_engine/config/initializers/apartment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Require whichever elevator you're using below here... # # require 'apartment/elevators/generic' @@ -8,7 +10,6 @@ # Apartment Configuration # Apartment.configure do |config| - # These models will not be multi-tenanted, # but remain in the global (public) namespace # @@ -17,13 +18,13 @@ # # config.excluded_models = %w{Tenant} # - config.excluded_models = %w{} + config.excluded_models = %w[] # use postgres schemas? config.use_schemas = true # use raw SQL dumps for creating postgres schemas? (only appies with use_schemas set to true) - #config.use_sql = true + # config.use_sql = true # configure persistent schemas (E.g. hstore ) # config.persistent_schemas = %w{ hstore } diff --git a/spec/dummy_engine/lib/dummy_engine.rb b/spec/dummy_engine/lib/dummy_engine.rb index b1a14145..8f9c8111 100644 --- a/spec/dummy_engine/lib/dummy_engine.rb +++ b/spec/dummy_engine/lib/dummy_engine.rb @@ -1,4 +1,6 @@ -require "dummy_engine/engine" +# frozen_string_literal: true + +require 'dummy_engine/engine' module DummyEngine end diff --git a/spec/dummy_engine/lib/dummy_engine/engine.rb b/spec/dummy_engine/lib/dummy_engine/engine.rb index cc8821c3..d308ec0d 100644 --- a/spec/dummy_engine/lib/dummy_engine/engine.rb +++ b/spec/dummy_engine/lib/dummy_engine/engine.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DummyEngine class Engine < ::Rails::Engine end diff --git a/spec/dummy_engine/lib/dummy_engine/version.rb b/spec/dummy_engine/lib/dummy_engine/version.rb index 82d2c8b8..76d025df 100644 --- a/spec/dummy_engine/lib/dummy_engine/version.rb +++ b/spec/dummy_engine/lib/dummy_engine/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DummyEngine - VERSION = "0.0.1" + VERSION = '0.0.1' end diff --git a/spec/dummy_engine/test/dummy/config.ru b/spec/dummy_engine/test/dummy/config.ru index 5bc2a619..61c04e13 100644 --- a/spec/dummy_engine/test/dummy/config.ru +++ b/spec/dummy_engine/test/dummy/config.ru @@ -1,4 +1,6 @@ +# frozen_string_literal: true + # This file is used by Rack-based servers to start the application. -require ::File.expand_path('../config/environment', __FILE__) +require ::File.expand_path('../config/environment', __FILE__) run Rails.application diff --git a/spec/dummy_engine/test/dummy/config/application.rb b/spec/dummy_engine/test/dummy/config/application.rb index 5ef001e9..0984f6ce 100644 --- a/spec/dummy_engine/test/dummy/config/application.rb +++ b/spec/dummy_engine/test/dummy/config/application.rb @@ -1,9 +1,11 @@ -require File.expand_path('../boot', __FILE__) +# frozen_string_literal: true + +require File.expand_path('boot', __dir__) require 'rails/all' Bundler.require(*Rails.groups) -require "dummy_engine" +require 'dummy_engine' module Dummy class Application < Rails::Application diff --git a/spec/dummy_engine/test/dummy/config/boot.rb b/spec/dummy_engine/test/dummy/config/boot.rb index 6266cfc5..6d2cba07 100644 --- a/spec/dummy_engine/test/dummy/config/boot.rb +++ b/spec/dummy_engine/test/dummy/config/boot.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + # Set up gems listed in the Gemfile. -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) -$LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) +$LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) diff --git a/spec/dummy_engine/test/dummy/config/environment.rb b/spec/dummy_engine/test/dummy/config/environment.rb index ee8d90dc..32d57aa4 100644 --- a/spec/dummy_engine/test/dummy/config/environment.rb +++ b/spec/dummy_engine/test/dummy/config/environment.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + # Load the Rails application. -require File.expand_path('../application', __FILE__) +require File.expand_path('application', __dir__) # Initialize the Rails application. Rails.application.initialize! diff --git a/spec/dummy_engine/test/dummy/config/environments/development.rb b/spec/dummy_engine/test/dummy/config/environments/development.rb index ddf0e90c..8296624e 100644 --- a/spec/dummy_engine/test/dummy/config/environments/development.rb +++ b/spec/dummy_engine/test/dummy/config/environments/development.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. diff --git a/spec/dummy_engine/test/dummy/config/environments/production.rb b/spec/dummy_engine/test/dummy/config/environments/production.rb index b93a877c..1bd152f1 100644 --- a/spec/dummy_engine/test/dummy/config/environments/production.rb +++ b/spec/dummy_engine/test/dummy/config/environments/production.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. diff --git a/spec/dummy_engine/test/dummy/config/environments/test.rb b/spec/dummy_engine/test/dummy/config/environments/test.rb index 053f5b66..bd942389 100644 --- a/spec/dummy_engine/test/dummy/config/environments/test.rb +++ b/spec/dummy_engine/test/dummy/config/environments/test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. diff --git a/spec/dummy_engine/test/dummy/config/initializers/assets.rb b/spec/dummy_engine/test/dummy/config/initializers/assets.rb index d2f4ec33..761905a7 100644 --- a/spec/dummy_engine/test/dummy/config/initializers/assets.rb +++ b/spec/dummy_engine/test/dummy/config/initializers/assets.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Version of your assets, change this if you want to expire all your assets. diff --git a/spec/dummy_engine/test/dummy/config/initializers/backtrace_silencers.rb b/spec/dummy_engine/test/dummy/config/initializers/backtrace_silencers.rb index 59385cdf..d0f0d3b5 100644 --- a/spec/dummy_engine/test/dummy/config/initializers/backtrace_silencers.rb +++ b/spec/dummy_engine/test/dummy/config/initializers/backtrace_silencers.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. diff --git a/spec/dummy_engine/test/dummy/config/initializers/cookies_serializer.rb b/spec/dummy_engine/test/dummy/config/initializers/cookies_serializer.rb index 7a06a89f..0a23b25e 100644 --- a/spec/dummy_engine/test/dummy/config/initializers/cookies_serializer.rb +++ b/spec/dummy_engine/test/dummy/config/initializers/cookies_serializer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. -Rails.application.config.action_dispatch.cookies_serializer = :json \ No newline at end of file +Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/spec/dummy_engine/test/dummy/config/initializers/filter_parameter_logging.rb b/spec/dummy_engine/test/dummy/config/initializers/filter_parameter_logging.rb index 4a994e1e..7a4f47b4 100644 --- a/spec/dummy_engine/test/dummy/config/initializers/filter_parameter_logging.rb +++ b/spec/dummy_engine/test/dummy/config/initializers/filter_parameter_logging.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Configure sensitive parameters which will be filtered from the log file. diff --git a/spec/dummy_engine/test/dummy/config/initializers/inflections.rb b/spec/dummy_engine/test/dummy/config/initializers/inflections.rb index ac033bf9..aa7435fb 100644 --- a/spec/dummy_engine/test/dummy/config/initializers/inflections.rb +++ b/spec/dummy_engine/test/dummy/config/initializers/inflections.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # Add new inflection rules using the following format. Inflections diff --git a/spec/dummy_engine/test/dummy/config/initializers/mime_types.rb b/spec/dummy_engine/test/dummy/config/initializers/mime_types.rb index dc189968..6e1d16f0 100644 --- a/spec/dummy_engine/test/dummy/config/initializers/mime_types.rb +++ b/spec/dummy_engine/test/dummy/config/initializers/mime_types.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # Add new mime types for use in respond_to blocks: diff --git a/spec/dummy_engine/test/dummy/config/initializers/session_store.rb b/spec/dummy_engine/test/dummy/config/initializers/session_store.rb index e766b67b..969d977f 100644 --- a/spec/dummy_engine/test/dummy/config/initializers/session_store.rb +++ b/spec/dummy_engine/test/dummy/config/initializers/session_store.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. Rails.application.config.session_store :cookie_store, key: '_dummy_session' diff --git a/spec/dummy_engine/test/dummy/config/initializers/wrap_parameters.rb b/spec/dummy_engine/test/dummy/config/initializers/wrap_parameters.rb index 33725e95..246168a4 100644 --- a/spec/dummy_engine/test/dummy/config/initializers/wrap_parameters.rb +++ b/spec/dummy_engine/test/dummy/config/initializers/wrap_parameters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # This file contains settings for ActionController::ParamsWrapper which diff --git a/spec/dummy_engine/test/dummy/config/routes.rb b/spec/dummy_engine/test/dummy/config/routes.rb index 3f66539d..189947fc 100644 --- a/spec/dummy_engine/test/dummy/config/routes.rb +++ b/spec/dummy_engine/test/dummy/config/routes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Rails.application.routes.draw do # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". diff --git a/spec/examples/connection_adapter_examples.rb b/spec/examples/connection_adapter_examples.rb index a7d4ac9b..973ed1fa 100644 --- a/spec/examples/connection_adapter_examples.rb +++ b/spec/examples/connection_adapter_examples.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + require 'spec_helper' -shared_examples_for "a connection based apartment adapter" do +shared_examples_for 'a connection based apartment adapter' do include Apartment::Spec::AdapterRequirements - let(:default_tenant){ subject.switch{ ActiveRecord::Base.connection.current_database } } + let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.current_database } } - describe "#init" do + describe '#init' do after do # Apartment::Tenant.init creates per model connection. # Remove the connection after testing not to unintentionally keep the connection across tests. @@ -14,9 +16,9 @@ end end - it "should process model exclusions" do + it 'should process model exclusions' do Apartment.configure do |config| - config.excluded_models = ["Company"] + config.excluded_models = ['Company'] end Apartment::Tenant.init @@ -24,19 +26,19 @@ end end - describe "#drop" do - it "should raise an error for unknown database" do - expect { + describe '#drop' do + it 'should raise an error for unknown database' do + expect do subject.drop 'unknown_database' - }.to raise_error(Apartment::TenantNotFound) + end.to raise_error(Apartment::TenantNotFound) end end - describe "#switch!" do - it "should raise an error if database is invalid" do - expect { + describe '#switch!' do + it 'should raise an error if database is invalid' do + expect do subject.switch! 'unknown_database' - }.to raise_error(Apartment::TenantNotFound) + end.to raise_error(Apartment::TenantNotFound) end end end diff --git a/spec/examples/generic_adapter_custom_configuration_example.rb b/spec/examples/generic_adapter_custom_configuration_example.rb index a9f053a3..07e2c719 100644 --- a/spec/examples/generic_adapter_custom_configuration_example.rb +++ b/spec/examples/generic_adapter_custom_configuration_example.rb @@ -1,12 +1,13 @@ -require 'spec_helper' +# frozen_string_literal: true -shared_examples_for "a generic apartment adapter able to handle custom configuration" do +require 'spec_helper' +shared_examples_for 'a generic apartment adapter able to handle custom configuration' do let(:custom_tenant_name) { 'test_tenantwwww' } - let(:db) { |example| example.metadata[:database]} + let(:db) { |example| example.metadata[:database] } let(:custom_tenant_names) do { - custom_tenant_name => get_custom_db_conf + custom_tenant_name => custom_db_conf } end @@ -19,12 +20,11 @@ Apartment.with_multi_server_setup = false end - context "database key taken from specific config" do + context 'database key taken from specific config' do + let(:expected_args) { custom_db_conf } - let(:expected_args) { get_custom_db_conf } - - describe "#create" do - it "should establish_connection with the separate connection with expected args" do + describe '#create' do + it 'should establish_connection with the separate connection with expected args' do expect(Apartment::Adapters::AbstractAdapter::SeparateDbConnectionHandler).to receive(:establish_connection).with(expected_args).and_call_original # because we dont have another server to connect to it errors @@ -33,8 +33,8 @@ end end - describe "#drop" do - it "should establish_connection with the separate connection with expected args" do + describe '#drop' do + it 'should establish_connection with the separate connection with expected args' do expect(Apartment::Adapters::AbstractAdapter::SeparateDbConnectionHandler).to receive(:establish_connection).with(expected_args).and_call_original # because we dont have another server to connect to it errors @@ -44,15 +44,13 @@ end end - context "database key from tenant name" do - - let(:expected_args) { - get_custom_db_conf.tap {|args| args.delete(:database) } - } - - describe "#switch!" do + context 'database key from tenant name' do + let(:expected_args) do + custom_db_conf.tap { |args| args.delete(:database) } + end - it "should connect to new db" do + describe '#switch!' do + it 'should connect to new db' do expect(Apartment).to receive(:establish_connection) do |args| db_name = args.delete(:database) @@ -72,24 +70,24 @@ def specific_connection { postgresql: { - adapter: 'postgresql', + adapter: 'postgresql', database: 'override_database', password: 'override_password', username: 'overridepostgres' }, mysql: { - adapter: 'mysql2', + adapter: 'mysql2', database: 'override_database', username: 'root' }, sqlite: { - adapter: 'sqlite3', + adapter: 'sqlite3', database: 'override_database' } } end - def get_custom_db_conf + def custom_db_conf specific_connection[db.to_sym].with_indifferent_access end end diff --git a/spec/examples/generic_adapter_examples.rb b/spec/examples/generic_adapter_examples.rb index 6c1b32ac..252ac47c 100644 --- a/spec/examples/generic_adapter_examples.rb +++ b/spec/examples/generic_adapter_examples.rb @@ -1,15 +1,17 @@ +# frozen_string_literal: true + require 'spec_helper' -shared_examples_for "a generic apartment adapter" do +shared_examples_for 'a generic apartment adapter' do include Apartment::Spec::AdapterRequirements - before { + before do Apartment.prepend_environment = false Apartment.append_environment = false - } + end - describe "#init" do - it "should not retain a connection after railtie" do + describe '#init' do + it 'should not retain a connection after railtie' do # this test should work on rails >= 4, the connection pool code is # completely different for 3.2 so we'd have to have a messy conditional.. unless Rails::VERSION::MAJOR < 4 @@ -18,9 +20,9 @@ Apartment::Railtie.config.to_prepare_blocks.map(&:call) num_available_connections = Apartment.connection_class.connection_pool - .instance_variable_get(:@available) - .instance_variable_get(:@queue) - .size + .instance_variable_get(:@available) + .instance_variable_get(:@queue) + .size expect(num_available_connections).to eq(1) end @@ -30,23 +32,22 @@ # # Creates happen already in our before_filter # - describe "#create" do - - it "should create the new databases" do + describe '#create' do + it 'should create the new databases' do expect(tenant_names).to include(db1) expect(tenant_names).to include(db2) end - it "should load schema.rb to new schema" do + it 'should load schema.rb to new schema' do subject.switch(db1) do expect(connection.tables).to include('companies') end end - it "should yield to block if passed and reset" do + it 'should yield to block if passed and reset' do subject.drop(db2) # so we don't get errors on creation - @count = 0 # set our variable so its visible in and outside of blocks + @count = 0 # set our variable so its visible in and outside of blocks subject.create(db2) do @count = User.count @@ -56,19 +57,19 @@ expect(subject.current).not_to eq(db2) - subject.switch(db2){ expect(User.count).to eq(@count + 1) } + subject.switch(db2) { expect(User.count).to eq(@count + 1) } end - it "should raise error when the schema.rb is missing unless Apartment.use_sql is set to true" do + it 'should raise error when the schema.rb is missing unless Apartment.use_sql is set to true' do next if Apartment.use_sql subject.drop(db1) begin Dir.mktmpdir do |tmpdir| Apartment.database_schema_file = "#{tmpdir}/schema.rb" - expect { + expect do subject.create(db1) - }.to raise_error(Apartment::FileNotFound) + end.to raise_error(Apartment::FileNotFound) end ensure Apartment.remove_instance_variable(:@database_schema_file) @@ -76,33 +77,33 @@ end end - describe "#drop" do - it "should remove the db" do + describe '#drop' do + it 'should remove the db' do subject.drop db1 expect(tenant_names).not_to include(db1) end end - describe "#switch!" do - it "should connect to new db" do + describe '#switch!' do + it 'should connect to new db' do subject.switch!(db1) expect(subject.current).to eq(db1) end - it "should reset connection if database is nil" do + it 'should reset connection if database is nil' do subject.switch! expect(subject.current).to eq(default_tenant) end - it "should raise an error if database is invalid" do - expect { + it 'should raise an error if database is invalid' do + expect do subject.switch! 'unknown_database' - }.to raise_error(Apartment::ApartmentError) + end.to raise_error(Apartment::ApartmentError) end end - describe "#switch" do - it "connects and resets the tenant" do + describe '#switch' do + it 'connects and resets the tenant' do subject.switch(db1) do expect(subject.current).to eq(db1) end @@ -111,32 +112,32 @@ # We're often finding when using Apartment in tests, the `current` (ie the previously connect to db) # gets dropped, but switch will try to return to that db in a test. We should just reset if it doesn't exist - it "should not throw exception if current is no longer accessible" do + it 'should not throw exception if current is no longer accessible' do subject.switch!(db2) - expect { - subject.switch(db1){ subject.drop(db2) } - }.to_not raise_error + expect do + subject.switch(db1) { subject.drop(db2) } + end.to_not raise_error end end - describe "#reset" do - it "should reset connection" do + describe '#reset' do + it 'should reset connection' do subject.switch!(db1) subject.reset expect(subject.current).to eq(default_tenant) end end - describe "#current" do - it "should return the current db name" do + describe '#current' do + it 'should return the current db name' do subject.switch!(db1) expect(subject.current).to eq(db1) end end - describe "#each" do - it "iterates over each tenant by default" do + describe '#each' do + it 'iterates over each tenant by default' do result = [] Apartment.tenant_names = [db2, db1] @@ -148,7 +149,7 @@ expect(result).to eq([db2, db1]) end - it "iterates over the given tenants" do + it 'iterates over the given tenants' do result = [] Apartment.tenant_names = [db2] diff --git a/spec/examples/schema_adapter_examples.rb b/spec/examples/schema_adapter_examples.rb index 5eed5091..d253ced9 100644 --- a/spec/examples/schema_adapter_examples.rb +++ b/spec/examples/schema_adapter_examples.rb @@ -1,17 +1,19 @@ +# frozen_string_literal: true + require 'spec_helper' -shared_examples_for "a schema based apartment adapter" do +# rubocop:disable Metrics/BlockLength +shared_examples_for 'a schema based apartment adapter' do include Apartment::Spec::AdapterRequirements - let(:schema1){ db1 } - let(:schema2){ db2 } - let(:public_schema){ default_tenant } - - describe "#init" do + let(:schema1) { db1 } + let(:schema2) { db2 } + let(:public_schema) { default_tenant } + describe '#init' do before do Apartment.configure do |config| - config.excluded_models = ["Company"] + config.excluded_models = ['Company'] end end @@ -23,15 +25,14 @@ end end - it "should process model exclusions" do + it 'should process model exclusions' do Apartment::Tenant.init - expect(Company.table_name).to eq("public.companies") + expect(Company.table_name).to eq('public.companies') end - context "with a default_schema", :default_schema => true do - - it "should set the proper table_name on excluded_models" do + context 'with a default_schema', default_schema: true do + it 'should set the proper table_name on excluded_models' do Apartment::Tenant.init expect(Company.table_name).to eq("#{default_schema}.companies") @@ -40,14 +41,14 @@ it 'sets the search_path correctly' do Apartment::Tenant.init - expect(User.connection.schema_search_path).to match(%r|#{default_schema}|) + expect(User.connection.schema_search_path).to match(/|#{default_schema}|/) end end - context "persistent_schemas", :persistent_schemas => true do - it "sets the persistent schemas in the schema_search_path" do + context 'persistent_schemas', persistent_schemas: true do + it 'sets the persistent schemas in the schema_search_path' do Apartment::Tenant.init - expect(connection.schema_search_path).to end_with persistent_schemas.map { |schema| %{"#{schema}"} }.join(', ') + expect(connection.schema_search_path).to end_with persistent_schemas.map { |schema| %("#{schema}") }.join(', ') end end end @@ -55,180 +56,184 @@ # # Creates happen already in our before_filter # - describe "#create" do - - it "should load schema.rb to new schema" do + describe '#create' do + it 'should load schema.rb to new schema' do connection.schema_search_path = schema1 expect(connection.tables).to include('companies') end - it "should yield to block if passed and reset" do + it 'should yield to block if passed and reset' do subject.drop(schema2) # so we don't get errors on creation - @count = 0 # set our variable so its visible in and outside of blocks + @count = 0 # set our variable so its visible in and outside of blocks subject.create(schema2) do @count = User.count - expect(connection.schema_search_path).to start_with %{"#{schema2}"} + expect(connection.schema_search_path).to start_with %("#{schema2}") User.create end - expect(connection.schema_search_path).not_to start_with %{"#{schema2}"} + expect(connection.schema_search_path).not_to start_with %("#{schema2}") - subject.switch(schema2){ expect(User.count).to eq(@count + 1) } + subject.switch(schema2) { expect(User.count).to eq(@count + 1) } end - context "numeric database names" do - let(:db){ 1234 } - it "should allow them" do - expect { + context 'numeric database names' do + let(:db) { 1234 } + it 'should allow them' do + expect do subject.create(db) - }.to_not raise_error + end.to_not raise_error expect(tenant_names).to include(db.to_s) end - after{ subject.drop(db) } + after { subject.drop(db) } end - end - describe "#drop" do - it "should raise an error for unknown database" do - expect { - subject.drop "unknown_database" - }.to raise_error(Apartment::TenantNotFound) + describe '#drop' do + it 'should raise an error for unknown database' do + expect do + subject.drop 'unknown_database' + end.to raise_error(Apartment::TenantNotFound) end - context "numeric database names" do - let(:db){ 1234 } + context 'numeric database names' do + let(:db) { 1234 } - it "should be able to drop them" do + it 'should be able to drop them' do subject.create(db) - expect { + expect do subject.drop(db) - }.to_not raise_error + end.to_not raise_error expect(tenant_names).not_to include(db.to_s) end - after { subject.drop(db) rescue nil } + after do + begin + subject.drop(db) + rescue StandardError => _e + nil + end + end end end - describe "#switch" do - it "connects and resets" do + describe '#switch' do + it 'connects and resets' do subject.switch(schema1) do - expect(connection.schema_search_path).to start_with %{"#{schema1}"} + expect(connection.schema_search_path).to start_with %("#{schema1}") end - expect(connection.schema_search_path).to start_with %{"#{public_schema}"} + expect(connection.schema_search_path).to start_with %("#{public_schema}") end end - describe "#reset" do - it "should reset connection" do + describe '#reset' do + it 'should reset connection' do subject.switch!(schema1) subject.reset - expect(connection.schema_search_path).to start_with %{"#{public_schema}"} + expect(connection.schema_search_path).to start_with %("#{public_schema}") end - context "with default_schema", :default_schema => true do - it "should reset to the default schema" do + context 'with default_schema', default_schema: true do + it 'should reset to the default schema' do subject.switch!(schema1) subject.reset - expect(connection.schema_search_path).to start_with %{"#{default_schema}"} + expect(connection.schema_search_path).to start_with %("#{default_schema}") end end - context "persistent_schemas", :persistent_schemas => true do + context 'persistent_schemas', persistent_schemas: true do before do subject.switch!(schema1) subject.reset end - it "maintains the persistent schemas in the schema_search_path" do - expect(connection.schema_search_path).to end_with persistent_schemas.map { |schema| %{"#{schema}"} }.join(', ') + it 'maintains the persistent schemas in the schema_search_path' do + expect(connection.schema_search_path).to end_with persistent_schemas.map { |schema| %("#{schema}") }.join(', ') end - context "with default_schema", :default_schema => true do - it "prioritizes the switched schema to front of schema_search_path" do + context 'with default_schema', default_schema: true do + it 'prioritizes the switched schema to front of schema_search_path' do subject.reset # need to re-call this as the default_schema wasn't set at the time that the above reset ran - expect(connection.schema_search_path).to start_with %{"#{default_schema}"} + expect(connection.schema_search_path).to start_with %("#{default_schema}") end end end end - describe "#switch!" do - it "should connect to new schema" do + describe '#switch!' do + it 'should connect to new schema' do subject.switch!(schema1) - expect(connection.schema_search_path).to start_with %{"#{schema1}"} + expect(connection.schema_search_path).to start_with %("#{schema1}") end - it "should reset connection if database is nil" do + it 'should reset connection if database is nil' do subject.switch! - expect(connection.schema_search_path).to eq(%{"#{public_schema}"}) + expect(connection.schema_search_path).to eq(%("#{public_schema}")) end - it "should raise an error if schema is invalid" do - expect { + it 'should raise an error if schema is invalid' do + expect do subject.switch! 'unknown_schema' - }.to raise_error(Apartment::TenantNotFound) + end.to raise_error(Apartment::TenantNotFound) end - context "numeric databases" do - let(:db){ 1234 } + context 'numeric databases' do + let(:db) { 1234 } - it "should connect to them" do + it 'should connect to them' do subject.create(db) - expect { + expect do subject.switch!(db) - }.to_not raise_error + end.to_not raise_error - expect(connection.schema_search_path).to start_with %{"#{db.to_s}"} + expect(connection.schema_search_path).to start_with %("#{db}") end - after{ subject.drop(db) } + after { subject.drop(db) } end - describe "with default_schema specified", :default_schema => true do + describe 'with default_schema specified', default_schema: true do before do subject.switch!(schema1) end - it "should switch out the default schema rather than public" do + it 'should switch out the default schema rather than public' do expect(connection.schema_search_path).not_to include default_schema end - it "should still switch to the switched schema" do - expect(connection.schema_search_path).to start_with %{"#{schema1}"} + it 'should still switch to the switched schema' do + expect(connection.schema_search_path).to start_with %("#{schema1}") end end - context "persistent_schemas", :persistent_schemas => true do - - before{ subject.switch!(schema1) } + context 'persistent_schemas', persistent_schemas: true do + before { subject.switch!(schema1) } - it "maintains the persistent schemas in the schema_search_path" do - expect(connection.schema_search_path).to end_with persistent_schemas.map { |schema| %{"#{schema}"} }.join(', ') + it 'maintains the persistent schemas in the schema_search_path' do + expect(connection.schema_search_path).to end_with persistent_schemas.map { |schema| %("#{schema}") }.join(', ') end - it "prioritizes the switched schema to front of schema_search_path" do - expect(connection.schema_search_path).to start_with %{"#{schema1}"} + it 'prioritizes the switched schema to front of schema_search_path' do + expect(connection.schema_search_path).to start_with %("#{schema1}") end end end - describe "#current" do - it "should return the current schema name" do + describe '#current' do + it 'should return the current schema name' do subject.switch!(schema1) expect(subject.current).to eq(schema1) end - context "persistent_schemas", :persistent_schemas => true do - it "should exlude persistent_schemas" do + context 'persistent_schemas', persistent_schemas: true do + it 'should exlude persistent_schemas' do subject.switch!(schema1) expect(subject.current).to eq(schema1) end end end end +# rubocop:enable Metrics/BlockLength diff --git a/spec/integration/apartment_rake_integration_spec.rb b/spec/integration/apartment_rake_integration_spec.rb index 4b9b098d..fbfd0474 100644 --- a/spec/integration/apartment_rake_integration_spec.rb +++ b/spec/integration/apartment_rake_integration_spec.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rake' -describe "apartment rake tasks", database: :postgresql do - +describe 'apartment rake tasks', database: :postgresql do before do @rake = Rake::Application.new Rake.application = @rake @@ -18,8 +19,8 @@ Apartment.configure do |config| config.use_schemas = true - config.excluded_models = ["Company"] - config.tenant_names = lambda{ Company.pluck(:database) } + config.excluded_models = ['Company'] + config.tenant_names = -> { Company.pluck(:database) } end Apartment::Tenant.reload!(config) @@ -29,40 +30,39 @@ after { Rake.application = nil } - context "with x number of databases" do - - let(:x){ 1 + rand(5) } # random number of dbs to create - let(:db_names){ x.times.map{ Apartment::Test.next_db } } - let!(:company_count){ db_names.length } + context 'with x number of databases' do + let(:x) { rand(1..5) } # random number of dbs to create + let(:db_names) { x.times.map { Apartment::Test.next_db } } + let!(:company_count) { db_names.length } before do db_names.collect do |db_name| Apartment::Tenant.create(db_name) - Company.create :database => db_name + Company.create database: db_name end end after do - db_names.each{ |db| Apartment::Tenant.drop(db) } + db_names.each { |db| Apartment::Tenant.drop(db) } Company.delete_all end - context "with ActiveRecord below 5.2.0" do + context 'with ActiveRecord below 5.2.0' do before do - allow(ActiveRecord::Migrator).to receive(:migrations_paths) { %w(spec/dummy/db/migrate) } + allow(ActiveRecord::Migrator).to receive(:migrations_paths) { %w[spec/dummy/db/migrate] } allow(Apartment::Migrator).to receive(:activerecord_below_5_2?) { true } end - describe "#migrate" do - it "should migrate all databases" do + describe '#migrate' do + it 'should migrate all databases' do expect(ActiveRecord::Migrator).to receive(:migrate).exactly(company_count).times @rake['apartment:migrate'].invoke end end - describe "#rollback" do - it "should rollback all dbs" do + describe '#rollback' do + it 'should rollback all dbs' do expect(ActiveRecord::Migrator).to receive(:rollback).exactly(company_count).times @rake['apartment:rollback'].invoke @@ -70,15 +70,15 @@ end end - context "with ActiveRecord above or equal to 5.2.0" do + context 'with ActiveRecord above or equal to 5.2.0' do let(:migration_context_double) { double(:migration_context) } before do allow(Apartment::Migrator).to receive(:activerecord_below_5_2?) { false } end - describe "#migrate" do - it "should migrate all databases" do + describe '#migrate' do + it 'should migrate all databases' do allow(ActiveRecord::Base.connection).to receive(:migration_context) { migration_context_double } expect(migration_context_double).to receive(:migrate).exactly(company_count).times @@ -86,8 +86,8 @@ end end - describe "#rollback" do - it "should rollback all dbs" do + describe '#rollback' do + it 'should rollback all dbs' do allow(ActiveRecord::Base.connection).to receive(:migration_context) { migration_context_double } expect(migration_context_double).to receive(:rollback).exactly(company_count).times @@ -96,8 +96,8 @@ end end - describe "apartment:seed" do - it "should seed all databases" do + describe 'apartment:seed' do + it 'should seed all databases' do expect(Apartment::Tenant).to receive(:seed).exactly(company_count).times @rake['apartment:seed'].invoke diff --git a/spec/integration/query_caching_spec.rb b/spec/integration/query_caching_spec.rb index 7bf08996..6026e5a1 100644 --- a/spec/integration/query_caching_spec.rb +++ b/spec/integration/query_caching_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'query caching' do @@ -6,8 +8,8 @@ before do Apartment.configure do |config| - config.excluded_models = ["Company"] - config.tenant_names = lambda{ Company.pluck(:database) } + config.excluded_models = ['Company'] + config.tenant_names = -> { Company.pluck(:database) } config.use_schemas = true end @@ -20,7 +22,7 @@ end after do - db_names.each{ |db| Apartment::Tenant.drop(db) } + db_names.each { |db| Apartment::Tenant.drop(db) } Apartment::Tenant.reset Company.delete_all end @@ -34,10 +36,10 @@ ActiveRecord::Base.connection.enable_query_cache! Apartment::Tenant.switch! db_names.first - expect(User.find_by_name(db_names.first).name).to eq(db_names.first) + expect(User.find_by(name: db_names.first).name).to eq(db_names.first) Apartment::Tenant.switch! db_names.last - expect(User.find_by_name(db_names.first)).to be_nil + expect(User.find_by(name: db_names.first)).to be_nil end end @@ -46,8 +48,8 @@ before do Apartment.configure do |config| - config.excluded_models = ["Company"] - config.tenant_names = lambda{ Company.pluck(:database) } + config.excluded_models = ['Company'] + config.tenant_names = -> { Company.pluck(:database) } config.use_schemas = false end @@ -66,7 +68,7 @@ Company.delete_all end - it "configuration value is kept after switching databases" do + it 'configuration value is kept after switching databases' do ActiveRecord::Base.connection.enable_query_cache! Apartment::Tenant.switch! db_name diff --git a/spec/integration/use_within_an_engine_spec.rb b/spec/integration/use_within_an_engine_spec.rb index 904a9238..072efac6 100644 --- a/spec/integration/use_within_an_engine_spec.rb +++ b/spec/integration/use_within_an_engine_spec.rb @@ -1,7 +1,8 @@ -describe 'using apartment within an engine' do +# frozen_string_literal: true +describe 'using apartment within an engine' do before do - engine_path = Pathname.new(File.expand_path('../../dummy_engine', __FILE__)) + engine_path = Pathname.new(File.expand_path('../dummy_engine', __dir__)) require engine_path.join('test/dummy/config/application') @rake = Rake::Application.new Rake.application = @rake @@ -10,11 +11,11 @@ end it 'sucessfully runs rake db:migrate in the engine root' do - expect{ Rake::Task['db:migrate'].invoke }.to_not raise_error + expect { Rake::Task['db:migrate'].invoke }.to_not raise_error end it 'sucessfully runs rake app:db:migrate in the engine root' do - expect{ Rake::Task['app:db:migrate'].invoke }.to_not raise_error + expect { Rake::Task['app:db:migrate'].invoke }.to_not raise_error end context 'when Apartment.db_migrate_tenants is false' do @@ -24,5 +25,4 @@ Rake::Task['db:migrate'].invoke end end - end diff --git a/spec/schemas/v1.rb b/spec/schemas/v1.rb index b5e6a796..052f5663 100644 --- a/spec/schemas/v1.rb +++ b/spec/schemas/v1.rb @@ -1,4 +1,4 @@ -# encoding: UTF-8 +# frozen_string_literal: true # This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. @@ -11,6 +11,5 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 0) do - +ActiveRecord::Schema.define(version: 0) do end diff --git a/spec/schemas/v2.rb b/spec/schemas/v2.rb index c6eeaba1..baf7b998 100644 --- a/spec/schemas/v2.rb +++ b/spec/schemas/v2.rb @@ -1,4 +1,4 @@ -# encoding: UTF-8 +# frozen_string_literal: true # This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. @@ -11,33 +11,31 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20110613152810) do - - create_table "companies", :force => true do |t| - t.boolean "dummy" - t.string "database" +ActiveRecord::Schema.define(version: 20110613152810) do + create_table 'companies', force: true do |t| + t.boolean 'dummy' + t.string 'database' end - create_table "delayed_jobs", :force => true do |t| - t.integer "priority", :default => 0 - t.integer "attempts", :default => 0 - t.text "handler" - t.text "last_error" - t.datetime "run_at" - t.datetime "locked_at" - t.datetime "failed_at" - t.string "locked_by" - t.datetime "created_at" - t.datetime "updated_at" - t.string "queue" + create_table 'delayed_jobs', force: true do |t| + t.integer 'priority', default: 0 + t.integer 'attempts', default: 0 + t.text 'handler' + t.text 'last_error' + t.datetime 'run_at' + t.datetime 'locked_at' + t.datetime 'failed_at' + t.string 'locked_by' + t.datetime 'created_at' + t.datetime 'updated_at' + t.string 'queue' end - add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority" + add_index 'delayed_jobs', ['priority', 'run_at'], name: 'delayed_jobs_priority' - create_table "users", :force => true do |t| - t.string "name" - t.datetime "birthdate" - t.string "sex" + create_table 'users', force: true do |t| + t.string 'name' + t.datetime 'birthdate' + t.string 'sex' end - end diff --git a/spec/schemas/v3.rb b/spec/schemas/v3.rb index 4dbc011d..2cd09a57 100644 --- a/spec/schemas/v3.rb +++ b/spec/schemas/v3.rb @@ -1,4 +1,4 @@ -# encoding: UTF-8 +# frozen_string_literal: true # This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. @@ -11,39 +11,37 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20111202022214) do - - create_table "books", :force => true do |t| - t.string "name" - t.integer "pages" - t.datetime "published" +ActiveRecord::Schema.define(version: 20111202022214) do + create_table 'books', force: true do |t| + t.string 'name' + t.integer 'pages' + t.datetime 'published' end - create_table "companies", :force => true do |t| - t.boolean "dummy" - t.string "database" + create_table 'companies', force: true do |t| + t.boolean 'dummy' + t.string 'database' end - create_table "delayed_jobs", :force => true do |t| - t.integer "priority", :default => 0 - t.integer "attempts", :default => 0 - t.text "handler" - t.text "last_error" - t.datetime "run_at" - t.datetime "locked_at" - t.datetime "failed_at" - t.string "locked_by" - t.datetime "created_at" - t.datetime "updated_at" - t.string "queue" + create_table 'delayed_jobs', force: true do |t| + t.integer 'priority', default: 0 + t.integer 'attempts', default: 0 + t.text 'handler' + t.text 'last_error' + t.datetime 'run_at' + t.datetime 'locked_at' + t.datetime 'failed_at' + t.string 'locked_by' + t.datetime 'created_at' + t.datetime 'updated_at' + t.string 'queue' end - add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority" + add_index 'delayed_jobs', ['priority', 'run_at'], name: 'delayed_jobs_priority' - create_table "users", :force => true do |t| - t.string "name" - t.datetime "birthdate" - t.string "sex" + create_table 'users', force: true do |t| + t.string 'name' + t.datetime 'birthdate' + t.string 'sex' end - end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 73cca8f4..68b9c680 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + $LOAD_PATH.unshift(File.dirname(__FILE__)) # Configure Rails Environment -ENV["RAILS_ENV"] = "test" +ENV['RAILS_ENV'] = 'test' -require File.expand_path("../dummy/config/environment.rb", __FILE__) +require File.expand_path('dummy/config/environment.rb', __dir__) # Loading dummy applications affects table_name of each excluded models # defined in `spec/dummy/config/initializers/apartment.rb`. @@ -16,19 +18,20 @@ klass.reset_table_name end -require "rspec/rails" +require 'rspec/rails' require 'capybara/rspec' require 'capybara/rails' begin require 'pry' - silence_warnings{ IRB = Pry } + silence_warnings { IRB = Pry } rescue LoadError + nil end ActionMailer::Base.delivery_method = :test ActionMailer::Base.perform_deliveries = true -ActionMailer::Base.default_url_options[:host] = "test.com" +ActionMailer::Base.default_url_options[:host] = 'test.com' Rails.backtrace_cleaner.remove_silencers! @@ -36,7 +39,6 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } RSpec.configure do |config| - config.include RSpec::Integration::CapybaraSessions, type: :request config.include Apartment::Spec::Setup diff --git a/spec/support/apartment_helpers.rb b/spec/support/apartment_helpers.rb index 795f172a..d45ea1b3 100644 --- a/spec/support/apartment_helpers.rb +++ b/spec/support/apartment_helpers.rb @@ -1,7 +1,10 @@ +# frozen_string_literal: true + module Apartment module Test - + # rubocop:disable Style/ModuleFunction extend self + # rubocop:enable Style/ModuleFunction def reset Apartment.excluded_models = nil @@ -12,11 +15,13 @@ def reset def next_db @x ||= 0 - "db%d" % @x += 1 + format('db%d', db_idx: @x += 1) end def drop_schema(schema) - ActiveRecord::Base.connection.execute("DROP SCHEMA IF EXISTS #{schema} CASCADE") rescue true + ActiveRecord::Base.connection.execute("DROP SCHEMA IF EXISTS #{schema} CASCADE") + rescue StandardError => _e + true end # Use this if you don't want to import schema.rb etc... but need the postgres schema to exist @@ -28,7 +33,7 @@ def create_schema(schema) def load_schema(version = 3) file = File.expand_path("../../schemas/v#{version}.rb", __FILE__) - silence_warnings{ load(file) } + silence_warnings { load(file) } end def migrate @@ -38,6 +43,5 @@ def migrate def rollback ActiveRecord::Migrator.rollback(Rails.root + ActiveRecord::Migrator.migrations_path) end - end end diff --git a/spec/support/capybara_sessions.rb b/spec/support/capybara_sessions.rb index 727d6c07..def4985c 100644 --- a/spec/support/capybara_sessions.rb +++ b/spec/support/capybara_sessions.rb @@ -1,15 +1,15 @@ +# frozen_string_literal: true + module RSpec module Integration module CapybaraSessions - - def in_new_session(&block) + def in_new_session(&_block) yield new_session end - + def new_session Capybara::Session.new(Capybara.current_driver, Capybara.app) end - end end -end \ No newline at end of file +end diff --git a/spec/support/config.rb b/spec/support/config.rb index 999279e5..ce91ad1a 100644 --- a/spec/support/config.rb +++ b/spec/support/config.rb @@ -1,10 +1,13 @@ +# frozen_string_literal: true + require 'yaml' module Apartment module Test - def self.config + # rubocop:disable Security/YAMLLoad @config ||= YAML.load(ERB.new(IO.read('spec/config/database.yml')).result) + # rubocop:enable Security/YAMLLoad end end -end \ No newline at end of file +end diff --git a/spec/support/contexts.rb b/spec/support/contexts.rb index ffb10a04..9c63f0a1 100644 --- a/spec/support/contexts.rb +++ b/spec/support/contexts.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + # Some shared contexts for specs -shared_context "with default schema", :default_schema => true do - let(:default_schema){ Apartment::Test.next_db } +shared_context 'with default schema', default_schema: true do + let(:default_schema) { Apartment::Test.next_db } before do Apartment::Test.create_schema(default_schema) @@ -16,7 +18,7 @@ end # Some default setup for elevator specs -shared_context "elevators", elevator: true do +shared_context 'elevators', elevator: true do let(:company1) { mock_model(Company, database: db1).as_null_object } let(:company2) { mock_model(Company, database: db2).as_null_object } @@ -37,16 +39,16 @@ end end -shared_context "persistent_schemas", :persistent_schemas => true do - let(:persistent_schemas){ ['hstore', 'postgis'] } +shared_context 'persistent_schemas', persistent_schemas: true do + let(:persistent_schemas) { %w[hstore postgis] } before do - persistent_schemas.map{|schema| subject.create(schema) } + persistent_schemas.map { |schema| subject.create(schema) } Apartment.persistent_schemas = persistent_schemas end after do Apartment.persistent_schemas = [] - persistent_schemas.map{|schema| subject.drop(schema) } + persistent_schemas.map { |schema| subject.drop(schema) } end -end \ No newline at end of file +end diff --git a/spec/support/requirements.rb b/spec/support/requirements.rb index dc856c9e..0a5fdf7d 100644 --- a/spec/support/requirements.rb +++ b/spec/support/requirements.rb @@ -1,6 +1,7 @@ +# frozen_string_literal: true + module Apartment module Spec - # # Define the interface methods required to # use an adapter shared example @@ -19,16 +20,28 @@ module AdapterRequirements # Reset before dropping (can't drop a db you're connected to) subject.reset - # sometimes we manually drop these schemas in testing, don't care if we can't drop, hence rescue - subject.drop(db1) rescue true - subject.drop(db2) rescue true + # sometimes we manually drop these schemas in testing, don't care if + # we can't drop, hence rescue + begin + subject.drop(db1) + rescue StandardError => _e + true + end + + begin + subject.drop(db2) + rescue StandardError => _e + true + end end end - %w{subject tenant_names default_tenant}.each do |method| + %w[subject tenant_names default_tenant].each do |method| + next if defined?(method) + define_method method do raise "You must define a `#{method}` method in your host group" - end unless defined?(method) + end end end end diff --git a/spec/support/setup.rb b/spec/support/setup.rb index 8441da3d..ef650383 100644 --- a/spec/support/setup.rb +++ b/spec/support/setup.rb @@ -1,18 +1,18 @@ +# frozen_string_literal: true + module Apartment module Spec module Setup - def self.included(base) base.instance_eval do - let(:db1){ Apartment::Test.next_db } - let(:db2){ Apartment::Test.next_db } - let(:connection){ ActiveRecord::Base.connection } + let(:db1) { Apartment::Test.next_db } + let(:db2) { Apartment::Test.next_db } + let(:connection) { ActiveRecord::Base.connection } # This around ensures that we run these hooks before and after # any before/after hooks defined in individual tests # Otherwise these actually get run after test defined hooks around(:each) do |example| - def config db = RSpec.current_example.metadata.fetch(:database, :postgresql) diff --git a/spec/tasks/apartment_rake_spec.rb b/spec/tasks/apartment_rake_spec.rb index 0f86aeee..f71727a9 100644 --- a/spec/tasks/apartment_rake_spec.rb +++ b/spec/tasks/apartment_rake_spec.rb @@ -1,10 +1,11 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rake' require 'apartment/migrator' require 'apartment/tenant' -describe "apartment rake tasks" do - +describe 'apartment rake tasks' do before do @rake = Rake::Application.new Rake.application = @rake @@ -20,110 +21,104 @@ after do Rake.application = nil - ENV['VERSION'] = nil # linux users reported env variable carrying on between tests + ENV['VERSION'] = nil # linux users reported env variable carrying on between tests end after(:all) do Apartment::Test.load_schema end - let(:version){ '1234' } + let(:version) { '1234' } context 'database migration' do - - let(:tenant_names){ 3.times.map{ Apartment::Test.next_db } } - let(:tenant_count){ tenant_names.length } + let(:tenant_names) { 3.times.map { Apartment::Test.next_db } } + let(:tenant_count) { tenant_names.length } before do allow(Apartment).to receive(:tenant_names).and_return tenant_names end - describe "apartment:migrate" do + describe 'apartment:migrate' do before do - allow(ActiveRecord::Migrator).to receive(:migrate) # don't care about this + allow(ActiveRecord::Migrator).to receive(:migrate) # don't care about this end - it "should migrate public and all multi-tenant dbs" do + it 'should migrate public and all multi-tenant dbs' do expect(Apartment::Migrator).to receive(:migrate).exactly(tenant_count).times @rake['apartment:migrate'].invoke end end - describe "apartment:migrate:up" do - - context "without a version" do + describe 'apartment:migrate:up' do + context 'without a version' do before do ENV['VERSION'] = nil end - it "requires a version to migrate to" do - expect{ + it 'requires a version to migrate to' do + expect do @rake['apartment:migrate:up'].invoke - }.to raise_error("VERSION is required") + end.to raise_error('VERSION is required') end end - context "with version" do - + context 'with version' do before do ENV['VERSION'] = version end - it "migrates up to a specific version" do + it 'migrates up to a specific version' do expect(Apartment::Migrator).to receive(:run).with(:up, anything, version.to_i).exactly(tenant_count).times @rake['apartment:migrate:up'].invoke end end end - describe "apartment:migrate:down" do - - context "without a version" do + describe 'apartment:migrate:down' do + context 'without a version' do before do ENV['VERSION'] = nil end - it "requires a version to migrate to" do - expect{ + it 'requires a version to migrate to' do + expect do @rake['apartment:migrate:down'].invoke - }.to raise_error("VERSION is required") + end.to raise_error('VERSION is required') end end - context "with version" do - + context 'with version' do before do ENV['VERSION'] = version end - it "migrates up to a specific version" do + it 'migrates up to a specific version' do expect(Apartment::Migrator).to receive(:run).with(:down, anything, version.to_i).exactly(tenant_count).times @rake['apartment:migrate:down'].invoke end end end - describe "apartment:rollback" do - let(:step){ '3' } + describe 'apartment:rollback' do + let(:step) { '3' } - it "should rollback dbs" do + it 'should rollback dbs' do expect(Apartment::Migrator).to receive(:rollback).exactly(tenant_count).times @rake['apartment:rollback'].invoke end - it "should rollback dbs STEP amt" do + it 'should rollback dbs STEP amt' do expect(Apartment::Migrator).to receive(:rollback).with(anything, step.to_i).exactly(tenant_count).times ENV['STEP'] = step @rake['apartment:rollback'].invoke end end - describe "apartment:drop" do - it "should migrate public and all multi-tenant dbs" do + describe 'apartment:drop' do + it 'should migrate public and all multi-tenant dbs' do expect(Apartment::Tenant).to receive(:drop).exactly(tenant_count).times @rake['apartment:drop'].invoke end end - end end diff --git a/spec/tenant_spec.rb b/spec/tenant_spec.rb index 261185a6..aa32a0ff 100644 --- a/spec/tenant_spec.rb +++ b/spec/tenant_spec.rb @@ -1,24 +1,25 @@ +# frozen_string_literal: true + require 'spec_helper' describe Apartment::Tenant do - context "using mysql", database: :mysql do - + context 'using mysql', database: :mysql do before { subject.reload!(config) } - describe "#adapter" do - it "should load mysql adapter" do + describe '#adapter' do + it 'should load mysql adapter' do subject.adapter expect(Apartment::Adapters::Mysql2Adapter).to be_a(Class) end end - # TODO this doesn't belong here, but there aren't integration tests currently for mysql + # TODO: this doesn't belong here, but there aren't integration tests currently for mysql # where to put??? - describe "exception recovery", :type => :request do + describe 'exception recovery', type: :request do before do subject.create db1 end - after{ subject.drop db1 } + after { subject.drop db1 } # it "should recover from incorrect database" do # session = Capybara::Session.new(:rack_test, Capybara.app) @@ -30,9 +31,9 @@ # end end - # TODO re-organize these tests - context "with prefix and schemas" do - describe "#create" do + # TODO: re-organize these tests + context 'with prefix and schemas' do + describe '#create' do before do Apartment.configure do |config| config.prepend_environment = true @@ -42,35 +43,41 @@ subject.reload!(config) end - after { subject.drop "db_with_prefix" rescue nil } + after do + begin + subject.drop 'db_with_prefix' + rescue StandardError => _e + nil + end + end - it "should create a new database" do - subject.create "db_with_prefix" + it 'should create a new database' do + subject.create 'db_with_prefix' end end end end - context "using postgresql", database: :postgresql do + context 'using postgresql', database: :postgresql do before do Apartment.use_schemas = true subject.reload!(config) end - describe "#adapter" do - it "should load postgresql adapter" do + describe '#adapter' do + it 'should load postgresql adapter' do expect(subject.adapter).to be_a(Apartment::Adapters::PostgresqlSchemaAdapter) end - it "raises exception with invalid adapter specified" do + it 'raises exception with invalid adapter specified' do subject.reload!(config.merge(adapter: 'unknown')) - expect { + expect do Apartment::Tenant.adapter - }.to raise_error(RuntimeError) + end.to raise_error(RuntimeError) end - context "threadsafety" do + context 'threadsafety' do before { subject.create db1 } after { subject.drop db1 } @@ -83,8 +90,8 @@ end end - # TODO above spec are also with use_schemas=true - context "with schemas" do + # TODO: above spec are also with use_schemas=true + context 'with schemas' do before do Apartment.configure do |config| config.excluded_models = [] @@ -94,30 +101,28 @@ subject.create db1 end - after{ subject.drop db1 } + after { subject.drop db1 } - describe "#create" do - it "should seed data" do + describe '#create' do + it 'should seed data' do subject.switch! db1 expect(User.count).to be > 0 end end - describe "#switch!" do + describe '#switch!' do + let(:x) { rand(3) } - let(:x){ rand(3) } + context 'creating models' do + before { subject.create db2 } + after { subject.drop db2 } - context "creating models" do - - before{ subject.create db2 } - after{ subject.drop db2 } - - it "should create a model instance in the current schema" do + it 'should create a model instance in the current schema' do subject.switch! db2 - db2_count = User.count + x.times{ User.create } + db2_count = User.count + x.times { User.create } subject.switch! db1 - db_count = User.count + x.times{ User.create } + db_count = User.count + x.times { User.create } subject.switch! db2 expect(User.count).to eq(db2_count) @@ -127,11 +132,10 @@ end end - context "with excluded models" do - + context 'with excluded models' do before do Apartment.configure do |config| - config.excluded_models = ["Company"] + config.excluded_models = ['Company'] end subject.init end @@ -144,12 +148,12 @@ end end - it "should create excluded models in public schema" do + it 'should create excluded models in public schema' do subject.reset # ensure we're on public schema - count = Company.count + x.times{ Company.create } + count = Company.count + x.times { Company.create } subject.switch! db1 - x.times{ Company.create } + x.times { Company.create } expect(Company.count).to eq(count + x) subject.reset expect(Company.count).to eq(count + x) @@ -158,7 +162,7 @@ end end - context "seed paths" do + context 'seed paths' do before do Apartment.configure do |config| config.excluded_models = [] @@ -167,7 +171,7 @@ end end - after{ subject.drop db1 } + after { subject.drop db1 } it 'should seed from default path' do subject.create db1 @@ -178,7 +182,7 @@ it 'should seed from custom path' do Apartment.configure do |config| - config.seed_data_file = "#{Rails.root}/db/seeds/import.rb" + config.seed_data_file = Rails.root.join('db', 'seeds', 'import.rb') end subject.create db1 subject.switch! db1 diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb index 44901952..cceaa7e4 100644 --- a/spec/unit/config_spec.rb +++ b/spec/unit/config_spec.rb @@ -1,11 +1,11 @@ +# frozen_string_literal: true + require 'spec_helper' describe Apartment do - - describe "#config" do - - let(:excluded_models){ ["Company"] } - let(:seed_data_file_path){ "#{Rails.root}/db/seeds/import.rb" } + describe '#config' do + let(:excluded_models) { ['Company'] } + let(:seed_data_file_path) { Rails.root.join('db', 'seeds', 'import.rb') } def tenant_names_from_array(names) names.each_with_object({}) do |tenant, hash| @@ -13,21 +13,21 @@ def tenant_names_from_array(names) end.with_indifferent_access end - it "should yield the Apartment object" do + it 'should yield the Apartment object' do Apartment.configure do |config| config.excluded_models = [] expect(config).to eq(Apartment) end end - it "should set excluded models" do + it 'should set excluded models' do Apartment.configure do |config| config.excluded_models = excluded_models end expect(Apartment.excluded_models).to eq(excluded_models) end - it "should set use_schemas" do + it 'should set use_schemas' do Apartment.configure do |config| config.excluded_models = [] config.use_schemas = false @@ -35,14 +35,14 @@ def tenant_names_from_array(names) expect(Apartment.use_schemas).to be false end - it "should set seed_data_file" do + it 'should set seed_data_file' do Apartment.configure do |config| config.seed_data_file = seed_data_file_path end expect(Apartment.seed_data_file).to eq(seed_data_file_path) end - it "should set seed_after_create" do + it 'should set seed_after_create' do Apartment.configure do |config| config.excluded_models = [] config.seed_after_create = true @@ -50,7 +50,7 @@ def tenant_names_from_array(names) expect(Apartment.seed_after_create).to be true end - context "databases" do + context 'databases' do let(:users_conf_hash) { { port: 5444 } } before do @@ -59,54 +59,53 @@ def tenant_names_from_array(names) end end - context "tenant_names as string array" do - let(:tenant_names) { ['users', 'companies'] } + context 'tenant_names as string array' do + let(:tenant_names) { %w[users companies] } - it "should return object if it doesnt respond_to call" do + it 'should return object if it doesnt respond_to call' do expect(Apartment.tenant_names).to eq(tenant_names_from_array(tenant_names).keys) end - it "should set tenants_with_config" do + it 'should set tenants_with_config' do expect(Apartment.tenants_with_config).to eq(tenant_names_from_array(tenant_names)) end end - context "tenant_names as proc returning an array" do - let(:tenant_names) { lambda { ['users', 'companies'] } } + context 'tenant_names as proc returning an array' do + let(:tenant_names) { -> { %w[users companies] } } - it "should return object if it doesnt respond_to call" do + it 'should return object if it doesnt respond_to call' do expect(Apartment.tenant_names).to eq(tenant_names_from_array(tenant_names.call).keys) end - it "should set tenants_with_config" do + it 'should set tenants_with_config' do expect(Apartment.tenants_with_config).to eq(tenant_names_from_array(tenant_names.call)) end end - context "tenant_names as Hash" do + context 'tenant_names as Hash' do let(:tenant_names) { { users: users_conf_hash }.with_indifferent_access } - it "should return object if it doesnt respond_to call" do + it 'should return object if it doesnt respond_to call' do expect(Apartment.tenant_names).to eq(tenant_names.keys) end - it "should set tenants_with_config" do + it 'should set tenants_with_config' do expect(Apartment.tenants_with_config).to eq(tenant_names) end end - context "tenant_names as proc returning a Hash" do - let(:tenant_names) { lambda { { users: users_conf_hash }.with_indifferent_access } } + context 'tenant_names as proc returning a Hash' do + let(:tenant_names) { -> { { users: users_conf_hash }.with_indifferent_access } } - it "should return object if it doesnt respond_to call" do + it 'should return object if it doesnt respond_to call' do expect(Apartment.tenant_names).to eq(tenant_names.call.keys) end - it "should set tenants_with_config" do + it 'should set tenants_with_config' do expect(Apartment.tenants_with_config).to eq(tenant_names.call) end end end - end end diff --git a/spec/unit/elevators/domain_spec.rb b/spec/unit/elevators/domain_spec.rb index cbdf9fb2..520b315c 100644 --- a/spec/unit/elevators/domain_spec.rb +++ b/spec/unit/elevators/domain_spec.rb @@ -1,29 +1,30 @@ +# frozen_string_literal: true + require 'spec_helper' require 'apartment/elevators/domain' describe Apartment::Elevators::Domain do + subject(:elevator) { described_class.new(proc {}) } - subject(:elevator){ described_class.new(Proc.new{}) } - - describe "#parse_tenant_name" do - it "parses the host for a domain name" do + describe '#parse_tenant_name' do + it 'parses the host for a domain name' do request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com') expect(elevator.parse_tenant_name(request)).to eq('example') end - it "ignores a www prefix and domain suffix" do + it 'ignores a www prefix and domain suffix' do request = ActionDispatch::Request.new('HTTP_HOST' => 'www.example.bc.ca') expect(elevator.parse_tenant_name(request)).to eq('example') end - it "returns nil if there is no host" do + it 'returns nil if there is no host' do request = ActionDispatch::Request.new('HTTP_HOST' => '') expect(elevator.parse_tenant_name(request)).to be_nil end end - describe "#call" do - it "switches to the proper tenant" do + describe '#call' do + it 'switches to the proper tenant' do expect(Apartment::Tenant).to receive(:switch).with('example') elevator.call('HTTP_HOST' => 'www.example.com') diff --git a/spec/unit/elevators/first_subdomain_spec.rb b/spec/unit/elevators/first_subdomain_spec.rb index 899b7bba..f608d834 100644 --- a/spec/unit/elevators/first_subdomain_spec.rb +++ b/spec/unit/elevators/first_subdomain_spec.rb @@ -1,24 +1,26 @@ +# frozen_string_literal: true + require 'spec_helper' require 'apartment/elevators/first_subdomain' describe Apartment::Elevators::FirstSubdomain do - describe "subdomain" do - subject { described_class.new("test").parse_tenant_name(request) } - let(:request) { double(:request, :host => "#{subdomain}.example.com") } + describe 'subdomain' do + subject { described_class.new('test').parse_tenant_name(request) } + let(:request) { double(:request, host: "#{subdomain}.example.com") } - context "one subdomain" do - let(:subdomain) { "test" } - it { is_expected.to eq("test") } + context 'one subdomain' do + let(:subdomain) { 'test' } + it { is_expected.to eq('test') } end - context "nested subdomains" do - let(:subdomain) { "test1.test2" } - it { is_expected.to eq("test1") } + context 'nested subdomains' do + let(:subdomain) { 'test1.test2' } + it { is_expected.to eq('test1') } end - - context "no subdomain" do + + context 'no subdomain' do let(:subdomain) { nil } it { is_expected.to eq(nil) } end end -end \ No newline at end of file +end diff --git a/spec/unit/elevators/generic_spec.rb b/spec/unit/elevators/generic_spec.rb index 6278dfe7..b282a5af 100644 --- a/spec/unit/elevators/generic_spec.rb +++ b/spec/unit/elevators/generic_spec.rb @@ -1,49 +1,50 @@ +# frozen_string_literal: true + require 'spec_helper' require 'apartment/elevators/generic' describe Apartment::Elevators::Generic do - class MyElevator < described_class def parse_tenant_name(*) 'tenant2' end end - subject(:elevator){ described_class.new(Proc.new{}) } + subject(:elevator) { described_class.new(proc {}) } - describe "#call" do - it "calls the processor if given" do - elevator = described_class.new(Proc.new{}, Proc.new{'tenant1'}) + describe '#call' do + it 'calls the processor if given' do + elevator = described_class.new(proc {}, proc { 'tenant1' }) expect(Apartment::Tenant).to receive(:switch).with('tenant1') elevator.call('HTTP_HOST' => 'foo.bar.com') end - it "raises if parse_tenant_name not implemented" do - expect { + it 'raises if parse_tenant_name not implemented' do + expect do elevator.call('HTTP_HOST' => 'foo.bar.com') - }.to raise_error(RuntimeError) + end.to raise_error(RuntimeError) end - it "switches to the parsed db_name" do - elevator = MyElevator.new(Proc.new{}) + it 'switches to the parsed db_name' do + elevator = MyElevator.new(proc {}) expect(Apartment::Tenant).to receive(:switch).with('tenant2') elevator.call('HTTP_HOST' => 'foo.bar.com') end - it "calls the block implementation of `switch`" do - elevator = MyElevator.new(Proc.new{}, Proc.new{'tenant2'}) + it 'calls the block implementation of `switch`' do + elevator = MyElevator.new(proc {}, proc { 'tenant2' }) expect(Apartment::Tenant).to receive(:switch).with('tenant2').and_yield elevator.call('HTTP_HOST' => 'foo.bar.com') end - it "does not call `switch` if no database given" do - app = Proc.new{} - elevator = MyElevator.new(app, Proc.new{}) + it 'does not call `switch` if no database given' do + app = proc {} + elevator = MyElevator.new(app, proc {}) expect(Apartment::Tenant).not_to receive(:switch) expect(app).to receive :call diff --git a/spec/unit/elevators/host_hash_spec.rb b/spec/unit/elevators/host_hash_spec.rb index c748b70d..6fc2f72b 100644 --- a/spec/unit/elevators/host_hash_spec.rb +++ b/spec/unit/elevators/host_hash_spec.rb @@ -1,29 +1,30 @@ +# frozen_string_literal: true + require 'spec_helper' require 'apartment/elevators/host_hash' describe Apartment::Elevators::HostHash do + subject(:elevator) { Apartment::Elevators::HostHash.new(proc {}, 'example.com' => 'example_tenant') } - subject(:elevator){ Apartment::Elevators::HostHash.new(Proc.new{}, 'example.com' => 'example_tenant') } - - describe "#parse_tenant_name" do - it "parses the host for a domain name" do + describe '#parse_tenant_name' do + it 'parses the host for a domain name' do request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com') expect(elevator.parse_tenant_name(request)).to eq('example_tenant') end - it "raises TenantNotFound exception if there is no host" do + it 'raises TenantNotFound exception if there is no host' do request = ActionDispatch::Request.new('HTTP_HOST' => '') expect { elevator.parse_tenant_name(request) }.to raise_error(Apartment::TenantNotFound) end - it "raises TenantNotFound exception if there is no database associated to current host" do + it 'raises TenantNotFound exception if there is no database associated to current host' do request = ActionDispatch::Request.new('HTTP_HOST' => 'example2.com') expect { elevator.parse_tenant_name(request) }.to raise_error(Apartment::TenantNotFound) end end - describe "#call" do - it "switches to the proper tenant" do + describe '#call' do + it 'switches to the proper tenant' do expect(Apartment::Tenant).to receive(:switch).with('example_tenant') elevator.call('HTTP_HOST' => 'example.com') diff --git a/spec/unit/elevators/host_spec.rb b/spec/unit/elevators/host_spec.rb index 96ea057c..e0cb9c3c 100644 --- a/spec/unit/elevators/host_spec.rb +++ b/spec/unit/elevators/host_spec.rb @@ -1,87 +1,87 @@ +# frozen_string_literal: true + require 'spec_helper' require 'apartment/elevators/host' describe Apartment::Elevators::Host do + subject(:elevator) { described_class.new(proc {}) } - subject(:elevator){ described_class.new(Proc.new{}) } - - describe "#parse_tenant_name" do - - it "should return nil when no host" do + describe '#parse_tenant_name' do + it 'should return nil when no host' do request = ActionDispatch::Request.new('HTTP_HOST' => '') expect(elevator.parse_tenant_name(request)).to be_nil end - context "assuming no ignored_first_subdomains" do + context 'assuming no ignored_first_subdomains' do before { allow(described_class).to receive(:ignored_first_subdomains).and_return([]) } - context "with 3 parts" do - it "should return the whole host" do + context 'with 3 parts' do + it 'should return the whole host' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com') expect(elevator.parse_tenant_name(request)).to eq('foo.bar.com') end end - context "with 6 parts" do - it "should return the whole host" do + context 'with 6 parts' do + it 'should return the whole host' do request = ActionDispatch::Request.new('HTTP_HOST' => 'one.two.three.foo.bar.com') expect(elevator.parse_tenant_name(request)).to eq('one.two.three.foo.bar.com') end end end - context "assuming ignored_first_subdomains is set" do - before { allow(described_class).to receive(:ignored_first_subdomains).and_return(%w{www foo}) } + context 'assuming ignored_first_subdomains is set' do + before { allow(described_class).to receive(:ignored_first_subdomains).and_return(%w[www foo]) } - context "with 3 parts" do - it "should return host without www" do + context 'with 3 parts' do + it 'should return host without www' do request = ActionDispatch::Request.new('HTTP_HOST' => 'www.bar.com') expect(elevator.parse_tenant_name(request)).to eq('bar.com') end - it "should return host without foo" do + it 'should return host without foo' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com') expect(elevator.parse_tenant_name(request)).to eq('bar.com') end end - context "with 6 parts" do - it "should return host without www" do + context 'with 6 parts' do + it 'should return host without www' do request = ActionDispatch::Request.new('HTTP_HOST' => 'www.one.two.three.foo.bar.com') expect(elevator.parse_tenant_name(request)).to eq('one.two.three.foo.bar.com') end - it "should return host without www" do + it 'should return host without www' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.one.two.three.bar.com') expect(elevator.parse_tenant_name(request)).to eq('one.two.three.bar.com') end end end - context "assuming localhost" do - it "should return localhost" do + context 'assuming localhost' do + it 'should return localhost' do request = ActionDispatch::Request.new('HTTP_HOST' => 'localhost') expect(elevator.parse_tenant_name(request)).to eq('localhost') end end - context "assuming ip address" do - it "should return the ip address" do + context 'assuming ip address' do + it 'should return the ip address' do request = ActionDispatch::Request.new('HTTP_HOST' => '127.0.0.1') expect(elevator.parse_tenant_name(request)).to eq('127.0.0.1') end end end - describe "#call" do - it "switches to the proper tenant" do + describe '#call' do + it 'switches to the proper tenant' do allow(described_class).to receive(:ignored_first_subdomains).and_return([]) expect(Apartment::Tenant).to receive(:switch).with('foo.bar.com') elevator.call('HTTP_HOST' => 'foo.bar.com') end - it "ignores ignored_first_subdomains" do - allow(described_class).to receive(:ignored_first_subdomains).and_return(%w{foo}) + it 'ignores ignored_first_subdomains' do + allow(described_class).to receive(:ignored_first_subdomains).and_return(%w[foo]) expect(Apartment::Tenant).to receive(:switch).with('bar.com') elevator.call('HTTP_HOST' => 'foo.bar.com') end diff --git a/spec/unit/elevators/subdomain_spec.rb b/spec/unit/elevators/subdomain_spec.rb index 1df11466..4c66ce67 100644 --- a/spec/unit/elevators/subdomain_spec.rb +++ b/spec/unit/elevators/subdomain_spec.rb @@ -1,70 +1,71 @@ +# frozen_string_literal: true + require 'spec_helper' require 'apartment/elevators/subdomain' describe Apartment::Elevators::Subdomain do + subject(:elevator) { described_class.new(proc {}) } - subject(:elevator){ described_class.new(Proc.new{}) } - - describe "#parse_tenant_name" do - context "assuming one tld" do - it "should parse subdomain" do + describe '#parse_tenant_name' do + context 'assuming one tld' do + it 'should parse subdomain' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com') expect(elevator.parse_tenant_name(request)).to eq('foo') end - it "should return nil when no subdomain" do + it 'should return nil when no subdomain' do request = ActionDispatch::Request.new('HTTP_HOST' => 'bar.com') expect(elevator.parse_tenant_name(request)).to be_nil end end - context "assuming two tlds" do - it "should parse subdomain in the third level domain" do + context 'assuming two tlds' do + it 'should parse subdomain in the third level domain' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.co.uk') - expect(elevator.parse_tenant_name(request)).to eq("foo") + expect(elevator.parse_tenant_name(request)).to eq('foo') end - it "should return nil when no subdomain in the third level domain" do + it 'should return nil when no subdomain in the third level domain' do request = ActionDispatch::Request.new('HTTP_HOST' => 'bar.co.uk') expect(elevator.parse_tenant_name(request)).to be_nil end end - context "assuming two subdomains" do - it "should parse two subdomains in the two level domain" do + context 'assuming two subdomains' do + it 'should parse two subdomains in the two level domain' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.xyz.bar.com') - expect(elevator.parse_tenant_name(request)).to eq("foo") + expect(elevator.parse_tenant_name(request)).to eq('foo') end - it "should parse two subdomains in the third level domain" do + it 'should parse two subdomains in the third level domain' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.xyz.bar.co.uk') - expect(elevator.parse_tenant_name(request)).to eq("foo") + expect(elevator.parse_tenant_name(request)).to eq('foo') end end - context "assuming localhost" do - it "should return nil for localhost" do + context 'assuming localhost' do + it 'should return nil for localhost' do request = ActionDispatch::Request.new('HTTP_HOST' => 'localhost') expect(elevator.parse_tenant_name(request)).to be_nil end end - context "assuming ip address" do - it "should return nil for an ip address" do + context 'assuming ip address' do + it 'should return nil for an ip address' do request = ActionDispatch::Request.new('HTTP_HOST' => '127.0.0.1') expect(elevator.parse_tenant_name(request)).to be_nil end end end - describe "#call" do - it "switches to the proper tenant" do + describe '#call' do + it 'switches to the proper tenant' do expect(Apartment::Tenant).to receive(:switch).with('tenant1') elevator.call('HTTP_HOST' => 'tenant1.example.com') end - it "ignores excluded subdomains" do - described_class.excluded_subdomains = %w{foo} + it 'ignores excluded subdomains' do + described_class.excluded_subdomains = %w[foo] expect(Apartment::Tenant).not_to receive(:switch) diff --git a/spec/unit/migrator_spec.rb b/spec/unit/migrator_spec.rb index 242b6b97..8cbcb9e2 100644 --- a/spec/unit/migrator_spec.rb +++ b/spec/unit/migrator_spec.rb @@ -1,21 +1,22 @@ +# frozen_string_literal: true + require 'spec_helper' require 'apartment/migrator' describe Apartment::Migrator do - - let(:tenant){ Apartment::Test.next_db } + let(:tenant) { Apartment::Test.next_db } # Don't need a real switch here, just testing behaviour before { allow(Apartment::Tenant.adapter).to receive(:connect_to_new) } - context "with ActiveRecord below 5.2.0", skip: ActiveRecord.version >= Gem::Version.new("5.2.0") do + context 'with ActiveRecord below 5.2.0', skip: ActiveRecord.version >= Gem::Version.new('5.2.0') do before do - allow(ActiveRecord::Migrator).to receive(:migrations_paths) { %w(spec/dummy/db/migrate) } + allow(ActiveRecord::Migrator).to receive(:migrations_paths) { %w[spec/dummy/db/migrate] } allow(Apartment::Migrator).to receive(:activerecord_below_5_2?) { true } end - describe "::migrate" do - it "switches and migrates" do + describe '::migrate' do + it 'switches and migrates' do expect(Apartment::Tenant).to receive(:switch).with(tenant).and_call_original expect(ActiveRecord::Migrator).to receive(:migrate) @@ -23,8 +24,8 @@ end end - describe "::run" do - it "switches and runs" do + describe '::run' do + it 'switches and runs' do expect(Apartment::Tenant).to receive(:switch).with(tenant).and_call_original expect(ActiveRecord::Migrator).to receive(:run).with(:up, anything, 1234) @@ -32,8 +33,8 @@ end end - describe "::rollback" do - it "switches and rolls back" do + describe '::rollback' do + it 'switches and rolls back' do expect(Apartment::Tenant).to receive(:switch).with(tenant).and_call_original expect(ActiveRecord::Migrator).to receive(:rollback).with(anything, 2) @@ -42,13 +43,13 @@ end end - context "with ActiveRecord above or equal to 5.2.0", skip: ActiveRecord.version < Gem::Version.new("5.2.0") do + context 'with ActiveRecord above or equal to 5.2.0', skip: ActiveRecord.version < Gem::Version.new('5.2.0') do before do allow(Apartment::Migrator).to receive(:activerecord_below_5_2?) { false } end - describe "::migrate" do - it "switches and migrates" do + describe '::migrate' do + it 'switches and migrates' do expect(Apartment::Tenant).to receive(:switch).with(tenant).and_call_original expect_any_instance_of(ActiveRecord::MigrationContext).to receive(:migrate) @@ -56,8 +57,8 @@ end end - describe "::run" do - it "switches and runs" do + describe '::run' do + it 'switches and runs' do expect(Apartment::Tenant).to receive(:switch).with(tenant).and_call_original expect_any_instance_of(ActiveRecord::MigrationContext).to receive(:run).with(:up, 1234) @@ -65,8 +66,8 @@ end end - describe "::rollback" do - it "switches and rolls back" do + describe '::rollback' do + it 'switches and rolls back' do expect(Apartment::Tenant).to receive(:switch).with(tenant).and_call_original expect_any_instance_of(ActiveRecord::MigrationContext).to receive(:rollback).with(2) diff --git a/spec/unit/reloader_spec.rb b/spec/unit/reloader_spec.rb index ffe30988..54bd2ff7 100644 --- a/spec/unit/reloader_spec.rb +++ b/spec/unit/reloader_spec.rb @@ -1,24 +1,24 @@ +# frozen_string_literal: true + require 'spec_helper' describe Apartment::Reloader do - - context "using postgresql schemas" do - + context 'using postgresql schemas' do before do Apartment.configure do |config| - config.excluded_models = ["Company"] + config.excluded_models = ['Company'] config.use_schemas = true end Apartment::Tenant.reload!(config) - Company.reset_table_name # ensure we're clean + Company.reset_table_name # ensure we're clean end - subject{ Apartment::Reloader.new(double("Rack::Application", :call => nil)) } + subject { Apartment::Reloader.new(double('Rack::Application', call: nil)) } - it "should initialize apartment when called" do + it 'should initialize apartment when called' do expect(Company.table_name).not_to include('public.') subject.call(double('env')) expect(Company.table_name).to include('public.') end end -end \ No newline at end of file +end