multitenant-mysql 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. data/.travis.yml +4 -0
  2. data/Gemfile +1 -0
  3. data/README.rdoc +19 -3
  4. data/lib/generators/multitenant/triggers/create_generator.rb +15 -0
  5. data/lib/generators/multitenant/triggers/drop_generator.rb +14 -0
  6. data/lib/generators/multitenant/triggers/refresh_generator.rb +17 -0
  7. data/lib/generators/multitenant/triggers/sql/create.rb +33 -0
  8. data/lib/generators/multitenant/triggers/sql/drop.rb +23 -0
  9. data/lib/generators/multitenant/views/create_generator.rb +15 -0
  10. data/lib/generators/multitenant/views/drop_generator.rb +14 -0
  11. data/lib/generators/multitenant/views/refresh_generator.rb +17 -0
  12. data/lib/generators/multitenant/views/sql/create.rb +33 -0
  13. data/lib/generators/multitenant/views/sql/drop.rb +24 -0
  14. data/lib/generators/multitenant/views_and_triggers/create_generator.rb +22 -0
  15. data/lib/generators/multitenant/views_and_triggers/list/list.rb +17 -0
  16. data/lib/generators/multitenant/views_and_triggers/list/sql.rb +6 -0
  17. data/lib/generators/multitenant/views_and_triggers/refresh_generator.rb +26 -0
  18. data/lib/multitenant-mysql/connection_switcher.rb +2 -15
  19. data/lib/multitenant-mysql/db.rb +22 -0
  20. data/lib/multitenant-mysql/version.rb +1 -1
  21. data/spec/arc_spec.rb +3 -1
  22. data/spec/generators/list_spec.rb +33 -0
  23. data/spec/generators/triggers/sql/create_spec.rb +14 -0
  24. data/spec/generators/triggers/sql/drop_spec.rb +15 -0
  25. data/spec/generators/views/sql/create_spec.rb +14 -0
  26. data/spec/generators/views/sql/drop_spec.rb +15 -0
  27. data/spec/{action_controller_extension_spec.rb → rails/action_controller_extension_spec.rb} +0 -0
  28. data/spec/rails/active_record_base_spec.rb +0 -1
  29. data/spec/spec_helper.rb +54 -2
  30. metadata +29 -7
  31. data/lib/generators/multitenant/views_and_triggers/trigger_generator.rb +0 -38
  32. data/lib/generators/multitenant/views_and_triggers/view_generator.rb +0 -28
  33. data/lib/generators/multitenant/views_and_triggers/views_and_triggers_generator.rb +0 -20
@@ -1,4 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
+ env:
5
+ - DB=mysql
6
+ before_script:
7
+ - "mysql -e 'create database tenant_test;'"
4
8
  script: bundle exec rspec spec
data/Gemfile CHANGED
@@ -4,3 +4,4 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
  gem 'rails'
6
6
  gem 'rspec'
7
+ gem 'mysql2'
@@ -37,7 +37,7 @@ this will create a sample of config file in "rails_root/config/multitenant_mysql
37
37
  This is the place where you list all your tenant dependent models and the model which contains all the tenants.
38
38
  E.g:
39
39
 
40
- Multitenant::Mysql.active_record_configs = {
40
+ Multitenant::Mysql.arc = {
41
41
  models: ['Book', 'Task'],
42
42
  tenant_model: { name: 'Subdomain' }
43
43
  }
@@ -51,7 +51,7 @@ Important: Before moving on you have to update this file as all further steps us
51
51
  rake db:migrate
52
52
 
53
53
  4 generate mysql views and triggers
54
- rails g multitenant:views_and_triggers
54
+ rails g multitenant:views_and_triggers:create
55
55
 
56
56
  5 in ApplicationController
57
57
  set_current_tenant :tenant_method
@@ -71,7 +71,23 @@ E.g.
71
71
 
72
72
  if method used by `set_current_tenant` returns blank name then `root` account is used
73
73
 
74
- Note: if you want to use subdomain as a tenant name then you can use `set_current_tenant_by_subdomain` method. Just add it into your application_controller. In this case `set_current_tenant` is not needed.
74
+ == Options and Notes
75
+
76
+ - if you have changed columns for tenant dependend models then you need to regenerate views, you could use generator
77
+ multitenant:views_and_triggers:refresh
78
+
79
+ - if you want to use subdomain as a tenant name then you can use metho
80
+ set_current_tenant_by_subdomain
81
+
82
+ - list of available generators to manage views and triggers
83
+ multitenant:triggers:create
84
+ multitenant:triggers:drop
85
+ multitenant:triggers:refresh
86
+ multitenant:views:create
87
+ multitenant:views:drop
88
+ multitenant:views:refresh
89
+ multitenant:views_and_triggers:create
90
+ multitenant:views_and_triggers:refresh
75
91
 
76
92
  == How It Works
77
93
 
@@ -0,0 +1,15 @@
1
+ require 'rails/generators'
2
+ require_relative './sql/create'
3
+ require Rails.root.to_s + '/config/multitenant_mysql_conf'
4
+
5
+ module Multitenant
6
+ module Triggers
7
+ class Create < Rails::Generators::Base
8
+ desc 'create triggers for all tenant depended models'
9
+
10
+ def generate_mysql_triggers
11
+ Multitenant::Triggers::SQL::Create.run
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails/generators'
2
+ require_relative './sql/drop'
3
+
4
+ module Multitenant
5
+ module Triggers
6
+ class Drop < Rails::Generators::Base
7
+ desc 'drops all triggers in db'
8
+
9
+ def drop_all_triggers
10
+ Multitenant::Triggers::SQL::Drop.run
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ require 'rails/generators'
2
+ require_relative './sql/drop'
3
+ require_relative './sql/create'
4
+ require Rails.root.to_s + '/config/multitenant_mysql_conf'
5
+
6
+ module Multitenant
7
+ module Triggers
8
+ class Refresh < Rails::Generators::Base
9
+ desc 'drops all triggers and creates new ones based on configs'
10
+
11
+ def refresh_all_triggers
12
+ Multitenant::Triggers::SQL::Drop.run
13
+ Multitenant::Triggers::SQL::Create.run
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ require_relative '../../views_and_triggers/list/list'
2
+ require_relative '../../views_and_triggers/list/sql'
3
+
4
+ module Multitenant
5
+ module Triggers
6
+ module SQL
7
+
8
+ class Create
9
+ def self.run
10
+ Multitenant::Mysql.models.each do |model_name|
11
+ model = model_name.constantize
12
+ trigger_name = model.original_table_name + '_tenant_trigger'
13
+
14
+ return if Multitenant::List.new(Multitenant::SQL::TRIGGERS).exists?(trigger_name)
15
+
16
+ trigger_sql = %Q(
17
+ CREATE TRIGGER #{trigger_name}
18
+ BEFORE INSERT ON #{model.original_table_name}
19
+ FOR EACH ROW
20
+ SET new.tenant = SUBSTRING_INDEX(USER(), '@', 1);
21
+ )
22
+
23
+ p trigger_sql
24
+ ActiveRecord::Base.connection.execute(trigger_sql)
25
+ p "==================== Generated Trigger: #{trigger_name} =================="
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ require_relative '../../views_and_triggers/list/list'
2
+ require_relative '../../views_and_triggers/list/sql'
3
+
4
+ module Multitenant
5
+ module Triggers
6
+ module SQL
7
+
8
+ class Drop
9
+
10
+ def self.run
11
+ list = Multitenant::List.new
12
+ list.sql = Multitenant::SQL::TRIGGERS
13
+ list.to_a.each do |trigger|
14
+ ActiveRecord::Base.connection.execute("DROP TRIGGER #{trigger};")
15
+ p "==================== Dropped Trigger: #{trigger} =================="
16
+ end
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ require 'rails/generators'
2
+ require_relative './sql/create'
3
+ require Rails.root.to_s + '/config/multitenant_mysql_conf'
4
+
5
+ module Multitenant
6
+ module Views
7
+ class Create < Rails::Generators::Base
8
+ desc 'create views for all tenant depended models'
9
+
10
+ def generate_mysql_views
11
+ Multitenant::Views::SQL::Create.run
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails/generators'
2
+ require_relative './sql/drop'
3
+
4
+ module Multitenant
5
+ module Views
6
+ class Drop < Rails::Generators::Base
7
+ desc 'drop all views in db'
8
+
9
+ def drop_all_views
10
+ Multitenant::Views::SQL::Drop.run
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ require 'rails/generators'
2
+ require_relative './sql/drop'
3
+ require_relative './sql/create'
4
+ require Rails.root.to_s + '/config/multitenant_mysql_conf'
5
+
6
+ module Multitenant
7
+ module Views
8
+ class Refresh < Rails::Generators::Base
9
+ desc 'drops all views and creates new ones based on configs'
10
+
11
+ def refresh_all_views
12
+ Multitenant::Views::SQL::Drop.run
13
+ Multitenant::Views::SQL::Create.run
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ require_relative '../../views_and_triggers/list/list'
2
+ require_relative '../../views_and_triggers/list/sql'
3
+
4
+ module Multitenant
5
+ module Views
6
+ module SQL
7
+ class Create
8
+
9
+ def self.run
10
+ Multitenant::Mysql.models.each do |model_name|
11
+ model = model_name.constantize
12
+ columns = model.column_names.join(', ')
13
+ view_name = model_name.to_s.downcase.pluralize + "_view"
14
+
15
+ # stop if view already exists
16
+ return if Multitenant::List.new(Multitenant::SQL::VIEWS).exists?(view_name)
17
+
18
+ view_sql = %Q(
19
+ CREATE VIEW #{view_name} AS
20
+ SELECT #{columns}
21
+ FROM #{model.table_name}
22
+ WHERE tenant = SUBSTRING_INDEX(USER(), '@', 1);
23
+ )
24
+
25
+ ActiveRecord::Base.connection.execute(view_sql)
26
+ p "==================== Generated View: #{view_name} =================="
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,24 @@
1
+ require_relative '../../views_and_triggers/list/list'
2
+ require_relative '../../views_and_triggers/list/sql'
3
+
4
+ module Multitenant
5
+ module Views
6
+ module SQL
7
+
8
+ class Drop
9
+
10
+ def self.run
11
+ list = Multitenant::List.new
12
+ list.sql = Multitenant::SQL::VIEWS
13
+
14
+ list.to_a.each do |view|
15
+ ActiveRecord::Base.connection.execute("DROP VIEW #{view};")
16
+ p "==================== Dropped View: #{view} =================="
17
+ end
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ require 'rails/generators'
2
+
3
+ require_relative '../views/sql/create'
4
+ require_relative '../triggers/sql/create'
5
+
6
+ require Rails.root.to_s + '/config/multitenant_mysql_conf'
7
+
8
+ module Multitenant
9
+ module ViewsAndTriggers
10
+ class CreateGenerator < Rails::Generators::Base
11
+ desc "based on specified models creates appropriate mysql views and triggers"
12
+
13
+ def generate_mysql_views
14
+ Multitenant::Views::SQL::Create.run
15
+ end
16
+
17
+ def generate_mysql_triggers
18
+ Multitenant::Triggers::SQL::Create.run
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ module Multitenant
2
+ class List
3
+ attr_accessor :sql
4
+
5
+ def initialize(sql = nil)
6
+ @sql = sql
7
+ end
8
+
9
+ def to_a
10
+ ActiveRecord::Base.connection.execute(sql).to_a.flatten
11
+ end
12
+
13
+ def exists?(name)
14
+ to_a.include?(name)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ module Multitenant
2
+ module SQL
3
+ VIEWS = "SELECT TABLE_NAME FROM information_schema.`TABLES` WHERE TABLE_TYPE LIKE 'VIEW' AND TABLE_SCHEMA LIKE '#{Multitenant::Mysql::DB.configs['database']}';"
4
+ TRIGGERS = "SELECT trigger_name FROM information_schema.TRIGGERS where trigger_schema = '#{Multitenant::Mysql::DB.configs['database']}';"
5
+ end
6
+ end
@@ -0,0 +1,26 @@
1
+ require 'rails/generators'
2
+
3
+ require_relative '../views/sql/create'
4
+ require_relative '../views/sql/drop'
5
+ require_relative '../triggers/sql/create'
6
+ require_relative '../triggers/sql/drop'
7
+
8
+ require Rails.root.to_s + '/config/multitenant_mysql_conf'
9
+
10
+ module Multitenant
11
+ module ViewsAndTriggers
12
+ class RefreshGenerator < Rails::Generators::Base
13
+ desc "drops all views and triggers and creates new ones based on configs"
14
+
15
+ def generate_mysql_views
16
+ Multitenant::Views::SQL::Drop.run
17
+ Multitenant::Views::SQL::Create.run
18
+ end
19
+
20
+ def generate_mysql_triggers
21
+ Multitenant::Triggers::SQL::Drop.run
22
+ Multitenant::Triggers::SQL::Create.run
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,22 +1,9 @@
1
+ require_relative './db'
2
+
1
3
  module Multitenant
2
4
  module Mysql
3
5
  class NoTenantRegistratedError < StandardError; end;
4
6
 
5
- class DB
6
- class << self
7
- def configs
8
- Rails.configuration.database_configuration[Rails.env]
9
- end
10
-
11
- def establish_connection_for tenant_name
12
- config = configs
13
- config['username'] = tenant_name.blank? ? 'root' : tenant_name
14
- ActiveRecord::Base.establish_connection(config)
15
- true
16
- end
17
- end
18
- end
19
-
20
7
  class Tenant
21
8
  def self.exists? tenant_name
22
9
  return true if tenant_name.blank?
@@ -0,0 +1,22 @@
1
+ module Multitenant
2
+ module Mysql
3
+ class DB
4
+ class << self
5
+ def configs
6
+ @configs ||= Rails.configuration.database_configuration[Rails.env]
7
+ end
8
+
9
+ def configs=(configs)
10
+ @configs = configs
11
+ end
12
+
13
+ def establish_connection_for tenant_name
14
+ config = configs
15
+ config['username'] = tenant_name.blank? ? 'root' : tenant_name
16
+ ActiveRecord::Base.establish_connection(config)
17
+ true
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  module Multitenant
2
2
  module Mysql
3
- VERSION = "1.0.2"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
@@ -31,7 +31,9 @@ describe Multitenant::Mysql do
31
31
  end
32
32
 
33
33
  context '.tenant' do
34
- Subdomain = :constant
34
+ before do
35
+ Subdomain = :constant
36
+ end
35
37
 
36
38
  it 'should find and return appropriate model' do
37
39
  subject.active_record_configs = { tenant_model: { name: 'Subdomain' } }
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Multitenant::List do
4
+
5
+ context 'views' do
6
+ subject { Multitenant::List.new(Multitenant::SQL::VIEWS) }
7
+
8
+ it 'should find all views' do
9
+ create_view_for_table('books')
10
+ expect(subject.to_a).to eq(['books_view'])
11
+ end
12
+
13
+ it 'should exist' do
14
+ create_view_for_table('books')
15
+ expect(subject.exists?('books_view')).to be
16
+ end
17
+ end
18
+
19
+ context 'triggers' do
20
+ subject { Multitenant::List.new(Multitenant::SQL::TRIGGERS) }
21
+
22
+ it 'should find all triggers' do
23
+ create_trigger_for_table('books')
24
+ expect(subject.to_a).to eq(['books_tenant_trigger'])
25
+ end
26
+
27
+ it 'should exist' do
28
+ create_trigger_for_table('books')
29
+ expect(subject.exists?('books_tenant_trigger')).to be
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Multitenant::Triggers::SQL::Create do
4
+ subject { Multitenant::Triggers::SQL::Create }
5
+
6
+ it 'should generate trigger' do
7
+ create_table('books')
8
+ class Subdomain < ActiveRecord::Base; end;
9
+ class Book < ActiveRecord::Base; end;
10
+ subject.run
11
+ expect( Multitenant::List.new(Multitenant::SQL::TRIGGERS).to_a ).to eq(['books_tenant_trigger'])
12
+ end
13
+
14
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Multitenant::Triggers::SQL::Drop do
4
+ subject { Multitenant::Triggers::SQL::Drop }
5
+
6
+ it 'should drop trigger' do
7
+ create_trigger_for_table('books')
8
+ class Subdomain < ActiveRecord::Base; end;
9
+ class Book < ActiveRecord::Base; end;
10
+ expect( Multitenant::List.new(Multitenant::SQL::TRIGGERS).to_a ).to eq(['books_tenant_trigger'])
11
+ subject.run
12
+ expect( Multitenant::List.new(Multitenant::SQL::TRIGGERS).to_a ).to be_empty
13
+ end
14
+
15
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Multitenant::Views::SQL::Create do
4
+ subject { Multitenant::Views::SQL::Create }
5
+
6
+ it 'should generate view' do
7
+ create_table('books')
8
+ class Subdomain < ActiveRecord::Base; end;
9
+ class Book < ActiveRecord::Base; end;
10
+ subject.run
11
+ expect( Multitenant::List.new(Multitenant::SQL::VIEWS).to_a ).to eq(['books_view'])
12
+ end
13
+
14
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Multitenant::Views::SQL::Drop do
4
+ subject { Multitenant::Views::SQL::Drop }
5
+
6
+ it 'should drop view' do
7
+ create_view_for_table('books')
8
+ class Subdomain < ActiveRecord::Base; end;
9
+ class Book < ActiveRecord::Base; end;
10
+ expect( Multitenant::List.new(Multitenant::SQL::VIEWS).to_a ).to eq(['books_view'])
11
+ subject.run
12
+ expect( Multitenant::List.new(Multitenant::SQL::VIEWS).to_a ).to be_empty
13
+ end
14
+
15
+ end
@@ -4,7 +4,6 @@ describe ActiveRecord::Base do
4
4
  subject { ActiveRecord::Base }
5
5
 
6
6
  before do
7
- Multitenant::Mysql::ConfFile.path = CONF_FILE_PATH
8
7
  Multitenant::Mysql.arc = { models: ['Book', 'Task'] }
9
8
  end
10
9
 
@@ -5,7 +5,59 @@ require 'active_record'
5
5
  require 'action_controller'
6
6
  require 'multitenant-mysql'
7
7
 
8
+
9
+ GEM_ROOT_PATH = File.expand_path('../../', __FILE__)
10
+ CONF_FILE_PATH = GEM_ROOT_PATH + '/spec/support/multitenant_mysql_conf'
11
+
8
12
  RSpec.configure do |config|
9
- Multitenant::Mysql::ConfFile.path = File.expand_path('../', __FILE__) + '/support/multitenant_mysql_conf'
10
- CONF_FILE_PATH = File.expand_path('../', __FILE__) + '/support/multitenant_mysql_conf'
13
+ config.before do
14
+ Multitenant::Mysql::ConfFile.path = CONF_FILE_PATH
15
+
16
+ ActiveRecord::Base.establish_connection({
17
+ adapter: 'mysql2',
18
+ username: 'root',
19
+ password: ''
20
+ })
21
+ ActiveRecord::Base.connection.execute('drop database if exists `tenant_test`;')
22
+ ActiveRecord::Base.connection.execute('create database `tenant_test`;')
23
+ ActiveRecord::Base.connection.execute('use `tenant_test`;')
24
+ end
25
+
26
+ config.after do
27
+ Object.send(:remove_const, :Subdomain) if defined?(Subdomain)
28
+ Object.send(:remove_const, :Book) if defined?(Book)
29
+ end
30
+ end
31
+
32
+ def create_table(name)
33
+ ActiveRecord::Base.connection.execute("drop table if exists `#{name}`;")
34
+ ActiveRecord::Base.connection.execute("create table `#{name}`
35
+ (`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
36
+ `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
37
+ `tenant` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL);")
11
38
  end
39
+
40
+ def create_view_for_table(name)
41
+ create_table(name)
42
+ ActiveRecord::Base.connection.execute("
43
+ CREATE VIEW #{name}_view AS
44
+ SELECT id, name, tenant FROM #{name}
45
+ ")
46
+ end
47
+
48
+ def create_trigger_for_table(name)
49
+ create_table(name)
50
+ ActiveRecord::Base.connection.execute("
51
+ CREATE TRIGGER #{name}_tenant_trigger
52
+ BEFORE INSERT ON #{name}
53
+ FOR EACH ROW
54
+ SET new.tenant = SUBSTRING_INDEX(USER(), '@', 1);
55
+ ")
56
+ end
57
+
58
+ Multitenant::Mysql::DB.configs = { 'username' => 'root', 'database' => 'tenant_test' }
59
+
60
+ require GEM_ROOT_PATH + '/lib/generators/multitenant/views/sql/create'
61
+ require GEM_ROOT_PATH + '/lib/generators/multitenant/views/sql/drop'
62
+ require GEM_ROOT_PATH + '/lib/generators/multitenant/triggers/sql/create'
63
+ require GEM_ROOT_PATH + '/lib/generators/multitenant/triggers/sql/drop'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multitenant-mysql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-06 00:00:00.000000000 Z
12
+ date: 2013-03-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -45,22 +45,39 @@ files:
45
45
  - lib/generators/multitenant/install/templates/multitenant_mysql_conf.rb
46
46
  - lib/generators/multitenant/migrations/migration_builder.rb
47
47
  - lib/generators/multitenant/migrations/migrations_generator.rb
48
- - lib/generators/multitenant/views_and_triggers/trigger_generator.rb
49
- - lib/generators/multitenant/views_and_triggers/view_generator.rb
50
- - lib/generators/multitenant/views_and_triggers/views_and_triggers_generator.rb
48
+ - lib/generators/multitenant/triggers/create_generator.rb
49
+ - lib/generators/multitenant/triggers/drop_generator.rb
50
+ - lib/generators/multitenant/triggers/refresh_generator.rb
51
+ - lib/generators/multitenant/triggers/sql/create.rb
52
+ - lib/generators/multitenant/triggers/sql/drop.rb
53
+ - lib/generators/multitenant/views/create_generator.rb
54
+ - lib/generators/multitenant/views/drop_generator.rb
55
+ - lib/generators/multitenant/views/refresh_generator.rb
56
+ - lib/generators/multitenant/views/sql/create.rb
57
+ - lib/generators/multitenant/views/sql/drop.rb
58
+ - lib/generators/multitenant/views_and_triggers/create_generator.rb
59
+ - lib/generators/multitenant/views_and_triggers/list/list.rb
60
+ - lib/generators/multitenant/views_and_triggers/list/sql.rb
61
+ - lib/generators/multitenant/views_and_triggers/refresh_generator.rb
51
62
  - lib/multitenant-mysql.rb
52
63
  - lib/multitenant-mysql/action_controller_extension.rb
53
64
  - lib/multitenant-mysql/active_record_extension.rb
54
65
  - lib/multitenant-mysql/arc.rb
55
66
  - lib/multitenant-mysql/conf_file.rb
56
67
  - lib/multitenant-mysql/connection_switcher.rb
68
+ - lib/multitenant-mysql/db.rb
57
69
  - lib/multitenant-mysql/version.rb
58
70
  - multitenant-mysql.gemspec
59
71
  - rails/init.rb
60
- - spec/action_controller_extension_spec.rb
61
72
  - spec/arc_spec.rb
62
73
  - spec/conf_file_spec.rb
63
74
  - spec/connection_switcher_spec.rb
75
+ - spec/generators/list_spec.rb
76
+ - spec/generators/triggers/sql/create_spec.rb
77
+ - spec/generators/triggers/sql/drop_spec.rb
78
+ - spec/generators/views/sql/create_spec.rb
79
+ - spec/generators/views/sql/drop_spec.rb
80
+ - spec/rails/action_controller_extension_spec.rb
64
81
  - spec/rails/active_record_base_spec.rb
65
82
  - spec/spec_helper.rb
66
83
  - spec/support/multitenant_mysql_conf.rb
@@ -89,10 +106,15 @@ signing_key:
89
106
  specification_version: 3
90
107
  summary: Add multi-tenancy to Rails application using MySql views
91
108
  test_files:
92
- - spec/action_controller_extension_spec.rb
93
109
  - spec/arc_spec.rb
94
110
  - spec/conf_file_spec.rb
95
111
  - spec/connection_switcher_spec.rb
112
+ - spec/generators/list_spec.rb
113
+ - spec/generators/triggers/sql/create_spec.rb
114
+ - spec/generators/triggers/sql/drop_spec.rb
115
+ - spec/generators/views/sql/create_spec.rb
116
+ - spec/generators/views/sql/drop_spec.rb
117
+ - spec/rails/action_controller_extension_spec.rb
96
118
  - spec/rails/active_record_base_spec.rb
97
119
  - spec/spec_helper.rb
98
120
  - spec/support/multitenant_mysql_conf.rb
@@ -1,38 +0,0 @@
1
- module Multitenant
2
- class TriggerGenerator
3
-
4
- class << self
5
- def run
6
- Multitenant::Mysql.models.each do |model_name|
7
- model = model_name.constantize
8
- trigger_name = model.original_table_name + '_tenant_trigger'
9
-
10
- return if trigger_exists?(trigger_name)
11
-
12
- trigger_sql = %Q(
13
- CREATE TRIGGER #{trigger_name}
14
- BEFORE INSERT ON #{model.original_table_name}
15
- FOR EACH ROW
16
- SET new.tenant = SUBSTRING_INDEX(USER(), '@', 1);
17
- )
18
-
19
- p trigger_sql
20
- ActiveRecord::Base.connection.execute(trigger_sql)
21
- p "==================== Generated Trigger: #{trigger_name} =================="
22
- end
23
-
24
- end
25
-
26
- def trigger_exists?(trigger_name)
27
- config = Rails.configuration.database_configuration[Rails.env]
28
- db_name = config['database']
29
-
30
- find_trigger_sql = "SELECT trigger_name FROM information_schema.TRIGGERS where trigger_schema = '#{db_name}';"
31
- result = ActiveRecord::Base.connection.execute(find_trigger_sql).to_a.flatten
32
-
33
- result.include?(trigger_name)
34
- end
35
- end
36
- end
37
-
38
- end
@@ -1,28 +0,0 @@
1
- module Multitenant
2
- class ViewGenerator
3
-
4
- def self.run
5
- Multitenant::Mysql.models.each do |model_name|
6
- model = model_name.constantize
7
- columns = model.column_names.join(', ')
8
- view_name = model_name.to_s.downcase.pluralize + "_view"
9
-
10
- # stop if view already exists
11
- return if ActiveRecord::Base.connection.table_exists?(view_name)
12
-
13
- view_sql = %Q(
14
- CREATE VIEW #{view_name} AS
15
- SELECT #{columns}
16
- FROM #{model.table_name}
17
- WHERE tenant = SUBSTRING_INDEX(USER(), '@', 1);
18
- )
19
-
20
- p view_sql
21
-
22
- ActiveRecord::Base.connection.execute(view_sql)
23
- p "==================== Generated View: #{view_name} =================="
24
- end
25
- end
26
-
27
- end
28
- end
@@ -1,20 +0,0 @@
1
- require 'rails/generators'
2
-
3
- require_relative './trigger_generator'
4
- require_relative './view_generator'
5
-
6
- require Rails.root.to_s + '/config/multitenant_mysql_conf'
7
-
8
- module Multitenant
9
- class ViewsAndTriggersGenerator < Rails::Generators::Base
10
- desc "based on specified models will create appropriate mysql views, triggers and migrations"
11
-
12
- def generate_mysql_views
13
- Multitenant::ViewGenerator.run
14
- end
15
-
16
- def generate_mysql_triggers
17
- Multitenant::TriggerGenerator.run
18
- end
19
- end
20
- end