roomer 0.0.8

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 (102) hide show
  1. data/.autotest +17 -0
  2. data/.gitignore +9 -0
  3. data/.rvmrc +2 -0
  4. data/.travis.yml +2 -0
  5. data/Gemfile +31 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +116 -0
  8. data/Rakefile +16 -0
  9. data/TODO.md +10 -0
  10. data/doc/ActiveRecord/Base.html +328 -0
  11. data/doc/ApplicationController.html +116 -0
  12. data/doc/Roomer/Engine.html +116 -0
  13. data/doc/Roomer/Generators/InstallGenerator.html +419 -0
  14. data/doc/Roomer/Generators/SetupGenerator.html +209 -0
  15. data/doc/Roomer/Generators.html +108 -0
  16. data/doc/Roomer/Tools.html +702 -0
  17. data/doc/Roomer/VERSION.html +149 -0
  18. data/doc/Roomer.html +533 -0
  19. data/doc/RoomerCreate.html +121 -0
  20. data/doc/_index.html +232 -0
  21. data/doc/class_list.html +47 -0
  22. data/doc/css/common.css +1 -0
  23. data/doc/css/full_list.css +53 -0
  24. data/doc/css/style.css +320 -0
  25. data/doc/file.README.html +146 -0
  26. data/doc/file_list.html +49 -0
  27. data/doc/frames.html +13 -0
  28. data/doc/index.html +146 -0
  29. data/doc/js/app.js +205 -0
  30. data/doc/js/full_list.js +150 -0
  31. data/doc/js/jquery.js +16 -0
  32. data/doc/method_list.html +182 -0
  33. data/doc/top-level-namespace.html +105 -0
  34. data/lib/generators/roomer/install/install_generator.rb +39 -0
  35. data/lib/generators/roomer/install/templates/README +15 -0
  36. data/lib/generators/roomer/install/templates/roomer.rb +68 -0
  37. data/lib/generators/roomer/migration/migration_generator.rb +35 -0
  38. data/lib/generators/roomer/migration/templates/migration.rb +17 -0
  39. data/lib/generators/roomer/model/model_generator.rb +45 -0
  40. data/lib/generators/roomer/model/templates/migration.rb +16 -0
  41. data/lib/generators/roomer/setup/setup_generator.rb +38 -0
  42. data/lib/generators/roomer/setup/templates/global_migration.rb +20 -0
  43. data/lib/roomer/extensions/controller.rb +36 -0
  44. data/lib/roomer/extensions/model.rb +72 -0
  45. data/lib/roomer/helpers/generator_helper.rb +30 -0
  46. data/lib/roomer/helpers/migration_helper.rb +7 -0
  47. data/lib/roomer/helpers/postgres_helper.rb +75 -0
  48. data/lib/roomer/rails.rb +24 -0
  49. data/lib/roomer/schema.rb +63 -0
  50. data/lib/roomer/schema_dumper.rb +36 -0
  51. data/lib/roomer/tasks/migrate.rake +85 -0
  52. data/lib/roomer/utils.rb +68 -0
  53. data/lib/roomer/version.rb +14 -0
  54. data/lib/roomer.rb +125 -0
  55. data/roomer.gemspec +22 -0
  56. data/test/config.rb +3 -0
  57. data/test/config.yml +7 -0
  58. data/test/generators/install_generator_test.rb +13 -0
  59. data/test/generators/migration_generator_test.rb +33 -0
  60. data/test/generators/model_generator_test.rb +25 -0
  61. data/test/generators/setup_generator_test.rb +25 -0
  62. data/test/rails_app/app/controllers/application_controller.rb +3 -0
  63. data/test/rails_app/app/helpers/application_helper.rb +2 -0
  64. data/test/rails_app/app/models/tenant.rb +12 -0
  65. data/test/rails_app/app/views/layouts/application.html.erb +14 -0
  66. data/test/rails_app/config/application.rb +50 -0
  67. data/test/rails_app/config/boot.rb +6 -0
  68. data/test/rails_app/config/database.yml +2 -0
  69. data/test/rails_app/config/environment.rb +5 -0
  70. data/test/rails_app/config/environments/development.rb +26 -0
  71. data/test/rails_app/config/environments/production.rb +49 -0
  72. data/test/rails_app/config/environments/test.rb +35 -0
  73. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  74. data/test/rails_app/config/initializers/inflections.rb +10 -0
  75. data/test/rails_app/config/initializers/mime_types.rb +5 -0
  76. data/test/rails_app/config/initializers/roomer.rb +68 -0
  77. data/test/rails_app/config/initializers/secret_token.rb +7 -0
  78. data/test/rails_app/config/initializers/session_store.rb +8 -0
  79. data/test/rails_app/config/locales/en.yml +5 -0
  80. data/test/rails_app/config/routes.rb +58 -0
  81. data/test/rails_app/config.ru +4 -0
  82. data/test/rails_app/db/migrate/global/20110825231409_roomer_create_tenants.rb +20 -0
  83. data/test/rails_app/db/seeds.rb +7 -0
  84. data/test/rails_app/lib/tasks/.gitkeep +0 -0
  85. data/test/rails_app/public/404.html +26 -0
  86. data/test/rails_app/public/422.html +26 -0
  87. data/test/rails_app/public/500.html +26 -0
  88. data/test/rails_app/public/favicon.ico +0 -0
  89. data/test/rails_app/public/images/rails.png +0 -0
  90. data/test/rails_app/public/index.html +239 -0
  91. data/test/rails_app/public/javascripts/application.js +2 -0
  92. data/test/rails_app/public/javascripts/controls.js +965 -0
  93. data/test/rails_app/public/javascripts/dragdrop.js +974 -0
  94. data/test/rails_app/public/javascripts/effects.js +1123 -0
  95. data/test/rails_app/public/javascripts/prototype.js +6001 -0
  96. data/test/rails_app/public/javascripts/rails.js +191 -0
  97. data/test/rails_app/public/robots.txt +5 -0
  98. data/test/rails_app/public/stylesheets/.gitkeep +0 -0
  99. data/test/roomer/helpers/postgres_helper_test.rb +62 -0
  100. data/test/roomer/roomer_test.rb +37 -0
  101. data/test/test_helper.rb +23 -0
  102. metadata +228 -0
@@ -0,0 +1,72 @@
1
+ module Roomer
2
+ module Extensions
3
+ module Model
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ # Sets the roomer scope for the model and changes the model's table_name_prefix
10
+ # Sets the table name prefix (schema name) to current_tenant's
11
+ # If :shared is passed, the global schema will be used as the table name prefix
12
+ # if :tenanted is pased, the current tenant's schema will be used as the table name prefix
13
+ # @return [Symbol] :shared or :tenanted
14
+ def roomer(scope)
15
+ case scope
16
+ when :shared
17
+ @roomer_scope = :shared
18
+ when :tenanted
19
+ @roomer_scope = :tenanted
20
+ else
21
+ raise "Invalid roomer model scope. Choose :shared or :tenanted"
22
+ end
23
+ roomer_set_table_name_prefix
24
+ end
25
+
26
+ # Confirms if model is shared
27
+ # @return [True,False]
28
+ def shared?
29
+ @roomer_scope == :shared
30
+ end
31
+
32
+ # Confirms if model is scoped by tenant
33
+ # @return [True,False]
34
+ def tenanted?
35
+ @roomer_scope == :tenanted
36
+ end
37
+
38
+ # Resets model's cached table_name and
39
+ # column information.
40
+ # This method needs to get called whenever
41
+ # the current tenant changes
42
+ def roomer_reset
43
+ roomer_set_table_name_prefix
44
+ reset_table_name
45
+ reset_column_information
46
+ end
47
+
48
+ protected
49
+ # Resolves the full table name prefix
50
+ def roomer_full_table_name_prefix(schema_name)
51
+ "#{schema_name.to_s}#{Roomer.schema_seperator}"
52
+ end
53
+
54
+ # Sets the model's table name prefix to the current tenant's schema name
55
+ # Defaults to public if model is marked as tenanted but tenant table
56
+ # hasn't been populated
57
+ def roomer_set_table_name_prefix
58
+ self.table_name_prefix = begin
59
+ case @roomer_scope
60
+ when :shared
61
+ roomer_full_table_name_prefix(Roomer.shared_schema_name)
62
+ when :tenanted
63
+ roomer_full_table_name_prefix(Roomer.current_tenant.try(Roomer.tenant_schema_name_column))
64
+ else
65
+ ""
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,30 @@
1
+ module Roomer
2
+ module Helpers
3
+ module GeneratorHelper
4
+
5
+ # Check to see if the model file exists, should be used in a Generator
6
+ # @return [True,False]
7
+ def model_exists?
8
+ File.exists?(File.join(destination_root, model_path))
9
+ end
10
+
11
+ # Returns the path of the model
12
+ # @return [String] model_path string representing the model location
13
+ def model_path
14
+ @model_path ||= File.join("app", "models", "#{file_path}.rb")
15
+ end
16
+
17
+ # Reads the --shared option specified when running "rails generate roomer:model"
18
+ # @return [True,False]
19
+ def shared?
20
+ @shared ||= options[:shared]
21
+ end
22
+
23
+ # Fetchs the migration directory for the migrations
24
+ def migration_dir
25
+ return Roomer.shared_migrations_directory if shared?
26
+ return Roomer.tenanted_migrations_directory
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ module Roomer
2
+ module Helpers
3
+ module MigrationHelper
4
+ # Migration Helper Methods go here
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,75 @@
1
+ module Roomer
2
+ module Helpers
3
+ module PostgresHelper
4
+
5
+ # Creates a schema in PostgreSQL
6
+ # @param [#to_s] schema_name declaring the name of the schema
7
+ def create_schema(schema_name)
8
+ ActiveRecord::Base.connection.execute "CREATE SCHEMA \"#{schema_name.to_s}\""
9
+ end
10
+
11
+ # Drops a schema and all it's objects (Cascades)
12
+ # @param [#to_s] schema_name declaring the name of the schema to drop
13
+ def drop_schema(schema_name)
14
+ ActiveRecord::Base.connection.execute("DROP SCHEMA IF EXISTS \"#{schema_name.to_s}\" CASCADE")
15
+ end
16
+
17
+ # lists the schemas available
18
+ # @return [Array] list of schemas
19
+ def schemas
20
+ ActiveRecord::Base.connection.query("SELECT nspname FROM pg_namespace WHERE nspname !~ '^pg_.*'").flatten.map(&:to_s)
21
+ end
22
+
23
+ # Ensures the schema and schema_migrations exist(creates them otherwise)
24
+ # and executes the code block
25
+ # @param [#to_s] schema_name declaring name to ensure
26
+ # @param [#call] &block code to execute
27
+ #
28
+ # Example:
29
+ #
30
+ # ensuring_schema(:global) do
31
+ # ActiveRecord::Migrator.migrate('/db/migrate', '20110812012536')
32
+ # end
33
+ def ensuring_schema(schema_name, &block)
34
+ raise ArgumentError.new("schema_name not present") unless schema_name
35
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
36
+ create_schema(schema_name) unless schemas.include?(schema_name.to_s)
37
+ ensure_prefix(schema_name) do
38
+ ensure_schema_migrations
39
+ yield
40
+ end
41
+ end
42
+
43
+ # Ensures the same ActiveRecord::Base#table_name_prefix for all the
44
+ # models executed in the block
45
+ # @param [#to_s] A Symbol declaring the table name prefix
46
+ # @param [#call] code to execute
47
+ # @note All the Models will have the same prefix, caution is advised
48
+ #
49
+ # Example:
50
+ #
51
+ # ensure_prefix(:global) do
52
+ # Person.find(1) # => will execute "SELECT id FROM 'global.person' where 'id' = 1"
53
+ # end
54
+ def ensure_prefix(prefix, &block)
55
+ @old_prefix = ActiveRecord::Base.table_name_prefix
56
+ ActiveRecord::Base.table_name_prefix = "#{prefix.to_s}#{Roomer.schema_seperator.to_s}"
57
+ yield
58
+ ActiveRecord::Base.table_name_prefix = @old_prefix
59
+ end
60
+
61
+ # Ensures schema_migrations table exists and creates otherwise
62
+ # @see ActiveRecord::Base.connection#initialize_schema_migrations_table
63
+ def ensure_schema_migrations
64
+ ActiveRecord::Base.connection.initialize_schema_migrations_table
65
+ end
66
+
67
+ # Determine if there are any pending migrations in the shared migrations directory
68
+ # @returns true if migrations are pending
69
+ def shared_migrations_pending?
70
+ ActiveRecord::Migrator.new(:up,Roomer.shared_migrations_directory)
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,24 @@
1
+ module Roomer
2
+ class RoomerEngine < ::Rails::Engine
3
+
4
+ initializer 'roomer.extensions' do |app|
5
+ # load model extensions
6
+ ActiveSupport.on_load(:active_record) do
7
+ include Roomer::Extensions::Model
8
+ end
9
+
10
+ # load controller extensions
11
+ ActiveSupport.on_load(:action_controller) do
12
+ include Roomer::Extensions::Controller
13
+ end
14
+ end
15
+
16
+ # load all the rake tasks
17
+ rake_tasks do
18
+ Dir[File.expand_path("../tasks/*.rake", __FILE__)].each do |file|
19
+ load file
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,63 @@
1
+ require 'active_support/core_ext/object/blank'
2
+
3
+ module Roomer
4
+ # Roomer::Schema extends ActiveRecord::Schema
5
+ # Roomer::Schema is currently only supported by the Postgres database adapter
6
+
7
+ class Schema < ActiveRecord::Migration
8
+ extend Roomer::Helpers::PostgresHelper
9
+
10
+ def self.migrations_path(scope=:tenanted)
11
+ case scope
12
+ when :shared
13
+ return Roomer.shared_migrations_directory
14
+ when :tenanted
15
+ return Roomer.tenanted_migrations_directory
16
+ else
17
+ raise 'Invalid scope parameter'
18
+ end
19
+ end
20
+
21
+ def self.dump(scope=:tenanted)
22
+ case scope
23
+ when :shared
24
+ schema_name = Roomer.shared_schema_name.to_s
25
+ filename = Roomer.shared_schema_filename
26
+ when :tenanted
27
+ tenant = Tenant.first
28
+ return if tenant.blank?
29
+
30
+ schema_name = Tenant.first.schema_name.to_s
31
+ filename = Roomer.tenanted_schema_filename
32
+ end
33
+ FileUtils.mkdir_p(Roomer.schemas_directory) unless File.exists?(Roomer.schemas_directory)
34
+ filepath = File.expand_path(File.join(Roomer.schemas_directory, filename))
35
+ ActiveRecord::Base.connection.schema_search_path = schema_name
36
+ ActiveRecord::Base.table_name_prefix = "#{schema_name}."
37
+ Roomer::SchemaDumper.dump(ActiveRecord::Base.connection, File.new(filepath, "w"))
38
+ end
39
+
40
+ def self.load(schema_name, scope=:tenanted)
41
+ filename = begin
42
+ if scope == :shared
43
+ Roomer.shared_schema_filename
44
+ elsif scope == :tenanted
45
+ Roomer.tenanted_schema_filename
46
+ end
47
+ end
48
+ filepath = File.expand_path(File.join(Roomer.schemas_directory, filename))
49
+ return unless File.exists?(filepath)
50
+
51
+ ensuring_schema(schema_name) do
52
+ Object.load(filepath)
53
+ end
54
+ end
55
+
56
+ def self.define(info={}, &block)
57
+ instance_eval(&block)
58
+ unless info[:version].blank?
59
+ ActiveRecord::Base.connection.assume_migrated_upto_version(info[:version], migrations_path)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,36 @@
1
+ module Roomer
2
+ class SchemaDumper < ActiveRecord::SchemaDumper
3
+
4
+ protected
5
+ def header(stream)
6
+ define_params = @version ? ":version => #{@version}" : ""
7
+ stream.puts <<HEADER
8
+ # It's strongly recommended to check this file into your version control system.
9
+
10
+ Roomer::Schema.define(#{define_params}) do
11
+
12
+ HEADER
13
+ end
14
+
15
+ def indexes(table, stream)
16
+ if (indexes = @connection.indexes(table)).any?
17
+ add_index_statements = indexes.map do |index|
18
+ statement_parts = [ ('add_index ' + index.table.inspect) ]
19
+ statement_parts << index.columns.inspect
20
+ statement_parts << (':name => "' + index.columns.first.to_s.split('.').last + '"')
21
+ statement_parts << ':unique => true' if index.unique
22
+
23
+ index_lengths = index.lengths.compact if index.lengths.is_a?(Array)
24
+ if index_lengths.present?
25
+ statement_parts << (':length => ' + Hash[*index.columns.zip(index.lengths).flatten].inspect)
26
+ end
27
+
28
+ ' ' + statement_parts.join(', ')
29
+ end
30
+
31
+ stream.puts add_index_statements.sort.join("\n")
32
+ stream.puts
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,85 @@
1
+ include Roomer::Helpers::PostgresHelper
2
+ include Roomer::Helpers::GeneratorHelper
3
+
4
+ namespace :roomer do
5
+ namespace :shared do
6
+ desc "Migrates the shared tables. Target specific version with VERSION=x"
7
+ task :migrate => :environment do
8
+ version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
9
+ ensuring_schema(Roomer.shared_schema_name) do
10
+ ActiveRecord::Migrator.migrate(Roomer.shared_migrations_directory, version)
11
+ end
12
+ Roomer::Schema.dump(:shared)
13
+ end
14
+
15
+ desc "Rolls back shared tables. Target specific version with STEP=x"
16
+ task :rollback => :environment do
17
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
18
+ ensuring_schema(Roomer.shared_schema_name) do
19
+ ActiveRecord::Migrator.rollback(Roomer.shared_migrations_directory, step)
20
+ end
21
+ Roomer::Schema.dump(:shared)
22
+ end
23
+
24
+ namespace :schema do
25
+ desc "Load shared schema into database"
26
+ task :load => :environment do
27
+ Roomer::Schema.load(Roomer.shared_schema_name, :shared)
28
+ end
29
+
30
+ desc "Dumps the shared schema to shared/schema.rb. This file can be portably used against any DB supported by AR"
31
+ task :dump => :environment do
32
+ Roomer::Schema.dump(:shared)
33
+ end
34
+ end
35
+ end
36
+
37
+ namespace :tenanted do
38
+ desc "Migrates the tenanted tables. Target specific version with VERSION=x"
39
+ task :migrate => :environment do
40
+ version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
41
+ Roomer.tenant_model.find(:all).each do |tenant|
42
+ ensuring_schema(tenant.try(Roomer.tenant_schema_name_column)) do
43
+ ActiveRecord::Migrator.migrate(Roomer.tenanted_migrations_directory, version)
44
+ end
45
+ end
46
+ Roomer::Schema.dump(:tenanted)
47
+ end
48
+
49
+ desc "Rolls back tenanted tables. Target specific version with STEP=x"
50
+ task :rollback => :environment do
51
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
52
+ Roomer.tenant_model.find(:all).each do |tenant|
53
+ ensuring_schema(tenant.try(Roomer.tenant_schema_name_column)) do
54
+ ActiveRecord::Migrator.rollback(Roomer.tenanted_migrations_directory, step)
55
+ end
56
+ end
57
+ Roomer::Schema.dump(:tenanted)
58
+ end
59
+
60
+ namespace :schema do
61
+ desc "Load tenanted schema into database"
62
+ task :load => :environment do
63
+ schema_name = ENV['SCHEMA_NAME']
64
+ raise "No schema name provided. Try: env SCHEMA_NAME=" if schema_name.blank?
65
+ Roomer::Schema.load(schema_name)
66
+ end
67
+
68
+ desc "Dumps tenanted schema file to migrate/schema.rb. This file can be portably used against any DB supported by AR"
69
+ task :dump => :environment do
70
+ Roomer::Schema.dump
71
+ end
72
+ end
73
+ end
74
+
75
+ desc "Runs shared and tenanted migrations"
76
+ task :migrate do
77
+ if ENV["VERSION"].blank?
78
+ Rake::Task["roomer:shared:migrate"].invoke
79
+ Rake::Task["roomer:tenanted:migrate"].invoke
80
+ else
81
+ Rake::Task["roomer:tenanted:migrate"].invoke
82
+ Rake::Task["roomer:shared:migrate"].invoke
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,68 @@
1
+ module Roomer
2
+ module Utils
3
+
4
+ # Rails DB Migrations Directory
5
+ # @return [String] full path to the current migrations directory
6
+ def migrations_directory
7
+ ActiveRecord::Migrator.migrations_path
8
+ end
9
+
10
+ # Directory where the models are stored
11
+ # @return [String] path of the directory where the models are stored
12
+ def model_directory
13
+ File.join("app","models")
14
+ end
15
+
16
+ # Consutructs the full name for the tenants table with schema
17
+ # Example: 'global.tenant'
18
+ # @return [String] full name of the tenant table
19
+ def full_tenants_table_name
20
+ "#{shared_schema_name}#{schema_seperator}#{tenants_table}"
21
+ end
22
+
23
+ # Constructs the full path to the shared schema directory
24
+ # Example: /Users/Greg/Projects/roomer/db/migrate/global
25
+ # @return [String] full path to the shared schema directory
26
+ def full_shared_schema_migration_path
27
+ "#{Rails.root}/#{shared_migrations_directory}"
28
+ end
29
+
30
+ # Returns tenant model as a constant
31
+ # Example: Tenant
32
+ # @return Object
33
+ def tenant_model
34
+ Roomer.tenants_table.to_s.classify.constantize
35
+ end
36
+
37
+ # Sets current tenant from ApplicationController into a Thread
38
+ # local variable. Works only with thread-safe Rails as long as
39
+ # it gets set on every request
40
+ # @return [Symbol] the current tenant key in the thread
41
+ def current_tenant=(val)
42
+ key = :"roomer_current_tenant"
43
+ Thread.current[key] = val
44
+ ensure_tenant_model_reset
45
+ end
46
+
47
+ # Fetches the current tenant
48
+ # @return [Symbol] the current tenant key in the thread
49
+ def current_tenant
50
+ key = :"roomer_current_tenant"
51
+ Thread.current[key]
52
+ end
53
+
54
+ # Reset current tenant
55
+ # @return [Nil]
56
+ def reset_current_tenant
57
+ key = :"roomer_current_tenant"
58
+ Thread.current[key] = nil
59
+ end
60
+
61
+ # Reset cached data in tenanted models
62
+ def ensure_tenant_model_reset
63
+ ActiveRecord::Base.descendants.each do |model|
64
+ model.roomer_reset if model.tenanted?
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,14 @@
1
+ module Roomer
2
+ module VERSION # :nodoc:
3
+ unless defined? MAJOR
4
+ MAJOR = 0
5
+ MINOR = 0
6
+ TINY = 8
7
+ PRE = nil
8
+
9
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
10
+
11
+ SUMMARY = "roomer #{STRING}"
12
+ end
13
+ end
14
+ end
data/lib/roomer.rb ADDED
@@ -0,0 +1,125 @@
1
+ require 'rails'
2
+ require 'active_support'
3
+ require 'active_support/dependencies'
4
+ require 'active_record'
5
+ require 'roomer/version'
6
+
7
+ module ActiveRecord
8
+ autoload :Migration, 'active_record/migration'
9
+ end
10
+
11
+ module Roomer
12
+ autoload :Utils, 'roomer/utils'
13
+
14
+ module Helpers
15
+ autoload :GeneratorHelper, 'roomer/helpers/generator_helper'
16
+ autoload :PostgresHelper, 'roomer/helpers/postgres_helper'
17
+ autoload :MigrationHelper, 'roomer/helpers/migration_helper'
18
+ end
19
+
20
+ module Extensions
21
+ autoload :Model, 'roomer/extensions/model'
22
+ autoload :Controller, 'roomer/extensions/controller'
23
+ end
24
+
25
+ autoload :SchemaDumper, 'roomer/schema_dumper'
26
+ autoload :Schema, 'roomer/schema'
27
+
28
+ extend Utils
29
+
30
+ # The URL routing strategy. Roomer currently supports two routing strategies (:domain and :path)
31
+ # * :domain - Using domain name to identify the tenant. This could include a subdomain
32
+ # * :path - identifying the tenant by the path
33
+ # Example:
34
+ # Domain
35
+ # ------
36
+ # http://mytenant.myapp.com - If you tenant has a subdomain under your domain
37
+ # http://mytenant.com - If the tenant choose to use their own top level domain name
38
+ # http://myapp.mytenant.com If the tenant chooses to use their own subdomain under thier TLD
39
+ # Path
40
+ # ----
41
+ # http://yourapp.com/tenant
42
+ mattr_accessor :url_routing_strategy
43
+ @@url_routing_strategy = :domain
44
+
45
+ # name of the shared schema where all the shared tables are be present
46
+ mattr_accessor :shared_schema_name
47
+ @@shared_schema_name = :global
48
+
49
+ # The name of the table where the tenants are stored, this table must
50
+ # contain two required columns configured under tenant_url_identifier_column and
51
+ # tenant_schema_name_column
52
+ mattr_accessor :tenants_table
53
+ @@tenants_table = :tenants
54
+
55
+ # The column name that stores the url identfier in the tenants tables.
56
+ # A url idenfier is a unique value that identifies the tenant from the URL.
57
+ # For e.g: if you use domains and the url is http://mytenant.myapp.com,
58
+ # the url identifier would "mytenant"
59
+ mattr_accessor :tenant_url_identifier_column
60
+ @@tenant_url_identifier_column = :url_identifier
61
+
62
+ # The column name that strores the schema name in the tenants tables.
63
+ mattr_accessor :tenant_schema_name_column
64
+ @@tenant_schema_name_column = :schema_name
65
+
66
+ # The schema seperator. This is used when generating the table name.
67
+ # The default is set to "."
68
+ # Example: tenant's table by default will be global.tenants
69
+ mattr_accessor :schema_seperator
70
+ @@schema_seperator = '.'
71
+
72
+ # Directory where schema files will be stored.
73
+ mattr_accessor :schemas_directory
74
+ @@schemas_directory = File.expand_path(File.join("db", "schemas"))
75
+
76
+ # Tenanted schema filename.
77
+ mattr_accessor :tenanted_schema_filename
78
+ @@tenanted_schema_filename = "tenanted_schema.rb"
79
+
80
+ # Shared schema filename.
81
+ mattr_accessor :shared_schema_filename
82
+ @@shared_schema_filename = "shared_schema.rb"
83
+
84
+ # Use Tentant migrations directory?
85
+ # Default is set to false
86
+ mattr_accessor :use_tenanted_migrations_directory
87
+ alias_method :use_tenanted_migrations_directory?,
88
+ :use_tenanted_migrations_directory
89
+ @@use_tenanted_migrations_directory = false
90
+
91
+ # Directory where the tenanted migrations are stored.
92
+ # This will be used only if use_tenanted_migration_directory is set to
93
+ # true if not usual rails migraiton directory db/migrate will be used
94
+ mattr_writer :tenanted_migrations_directory
95
+ @@tenanted_migrations_directory = File.join(migrations_directory,tenants_table.to_s)
96
+
97
+
98
+ # Directory where shared migrations are stored.
99
+ mattr_accessor :shared_migrations_directory
100
+ @@shared_migrations_directory = File.join(migrations_directory,shared_schema_name.to_s)
101
+
102
+ # Fetches the migrations directory for Tenanted migrations.
103
+ # returns the standard rails migration directory "db/migrate" is the
104
+ # use_tenanted_migrations_directory is set to false
105
+ # @return [String] String representing the tenanted migrations
106
+ def self.tenanted_migrations_directory
107
+ if self.use_tenanted_migrations_directory
108
+ return @@tenanted_migrations_directory
109
+ end
110
+ return migrations_directory
111
+ end
112
+
113
+ # Default way to setup Roomer. Run rails generate roomer:install to create
114
+ # a fresh initializer with all configuration values.
115
+ # @example
116
+ # Roomer.setup do |config|
117
+ # config.url_routing_strategy = :domain
118
+ # end
119
+ def self.setup
120
+ yield self
121
+ end
122
+
123
+ end
124
+
125
+ require 'roomer/rails'
data/roomer.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "roomer/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "roomer"
7
+ s.version = Roomer::VERSION::STRING
8
+ s.platform = Gem::Platform::RUBY
9
+ s.homepage = "https://github.com/gosuri/roomer"
10
+ s.summary = "Roomer is a multitenant framework for Rails using PostgreSQL"
11
+ s.description = Roomer::VERSION::SUMMARY
12
+
13
+ s.authors = ["Greg Osuri","Daniel Ceballos"]
14
+ s.email = ["gosuri@gmail.com","dceballos@gmail.com"]
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'rails','~> 3.0.9'
22
+ end
data/test/config.rb ADDED
@@ -0,0 +1,3 @@
1
+ require
2
+ TEST_ROOT = File.expand_path(File.dirname(__FILE__))
3
+
data/test/config.yml ADDED
@@ -0,0 +1,7 @@
1
+ postgresql: &postgresql
2
+ adapter: postgresql
3
+ encoding: unicode
4
+ database: roomer_test
5
+ username: postgres
6
+
7
+
@@ -0,0 +1,13 @@
1
+ require "test_helper"
2
+ require "generators/roomer/install/install_generator"
3
+
4
+ class InstallGeneratorTest < Rails::Generators::TestCase
5
+ tests Roomer::Generators::InstallGenerator
6
+ destination File.expand_path("../../tmp", __FILE__)
7
+ setup :prepare_destination
8
+
9
+ test "assert initializer file created" do
10
+ run_generator
11
+ assert_file "config/initializers/roomer.rb"
12
+ end
13
+ end