sskirby-activerecord 3.2.1

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 (150) hide show
  1. data/CHANGELOG.md +6749 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +222 -0
  4. data/examples/associations.png +0 -0
  5. data/examples/performance.rb +177 -0
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record.rb +147 -0
  8. data/lib/active_record/aggregations.rb +255 -0
  9. data/lib/active_record/associations.rb +1604 -0
  10. data/lib/active_record/associations/alias_tracker.rb +79 -0
  11. data/lib/active_record/associations/association.rb +239 -0
  12. data/lib/active_record/associations/association_scope.rb +119 -0
  13. data/lib/active_record/associations/belongs_to_association.rb +79 -0
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +34 -0
  15. data/lib/active_record/associations/builder/association.rb +55 -0
  16. data/lib/active_record/associations/builder/belongs_to.rb +85 -0
  17. data/lib/active_record/associations/builder/collection_association.rb +75 -0
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -0
  19. data/lib/active_record/associations/builder/has_many.rb +71 -0
  20. data/lib/active_record/associations/builder/has_one.rb +62 -0
  21. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  22. data/lib/active_record/associations/collection_association.rb +574 -0
  23. data/lib/active_record/associations/collection_proxy.rb +132 -0
  24. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +62 -0
  25. data/lib/active_record/associations/has_many_association.rb +108 -0
  26. data/lib/active_record/associations/has_many_through_association.rb +180 -0
  27. data/lib/active_record/associations/has_one_association.rb +73 -0
  28. data/lib/active_record/associations/has_one_through_association.rb +36 -0
  29. data/lib/active_record/associations/join_dependency.rb +214 -0
  30. data/lib/active_record/associations/join_dependency/join_association.rb +154 -0
  31. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  32. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  33. data/lib/active_record/associations/join_helper.rb +55 -0
  34. data/lib/active_record/associations/preloader.rb +177 -0
  35. data/lib/active_record/associations/preloader/association.rb +127 -0
  36. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  37. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  38. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  39. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  40. data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
  41. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  42. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  43. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  44. data/lib/active_record/associations/preloader/through_association.rb +67 -0
  45. data/lib/active_record/associations/singular_association.rb +64 -0
  46. data/lib/active_record/associations/through_association.rb +83 -0
  47. data/lib/active_record/attribute_assignment.rb +221 -0
  48. data/lib/active_record/attribute_methods.rb +272 -0
  49. data/lib/active_record/attribute_methods/before_type_cast.rb +31 -0
  50. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  51. data/lib/active_record/attribute_methods/dirty.rb +101 -0
  52. data/lib/active_record/attribute_methods/primary_key.rb +114 -0
  53. data/lib/active_record/attribute_methods/query.rb +39 -0
  54. data/lib/active_record/attribute_methods/read.rb +135 -0
  55. data/lib/active_record/attribute_methods/serialization.rb +93 -0
  56. data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -0
  57. data/lib/active_record/attribute_methods/write.rb +69 -0
  58. data/lib/active_record/autosave_association.rb +422 -0
  59. data/lib/active_record/base.rb +716 -0
  60. data/lib/active_record/callbacks.rb +275 -0
  61. data/lib/active_record/coders/yaml_column.rb +41 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +188 -0
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +58 -0
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +388 -0
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -0
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +115 -0
  68. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +492 -0
  69. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +598 -0
  70. data/lib/active_record/connection_adapters/abstract_adapter.rb +296 -0
  71. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +653 -0
  72. data/lib/active_record/connection_adapters/column.rb +270 -0
  73. data/lib/active_record/connection_adapters/mysql2_adapter.rb +288 -0
  74. data/lib/active_record/connection_adapters/mysql_adapter.rb +426 -0
  75. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1261 -0
  76. data/lib/active_record/connection_adapters/schema_cache.rb +50 -0
  77. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -0
  78. data/lib/active_record/connection_adapters/sqlite_adapter.rb +577 -0
  79. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  80. data/lib/active_record/counter_cache.rb +119 -0
  81. data/lib/active_record/dynamic_finder_match.rb +56 -0
  82. data/lib/active_record/dynamic_matchers.rb +79 -0
  83. data/lib/active_record/dynamic_scope_match.rb +23 -0
  84. data/lib/active_record/errors.rb +195 -0
  85. data/lib/active_record/explain.rb +85 -0
  86. data/lib/active_record/explain_subscriber.rb +21 -0
  87. data/lib/active_record/fixtures.rb +906 -0
  88. data/lib/active_record/fixtures/file.rb +65 -0
  89. data/lib/active_record/identity_map.rb +156 -0
  90. data/lib/active_record/inheritance.rb +167 -0
  91. data/lib/active_record/integration.rb +49 -0
  92. data/lib/active_record/locale/en.yml +40 -0
  93. data/lib/active_record/locking/optimistic.rb +183 -0
  94. data/lib/active_record/locking/pessimistic.rb +77 -0
  95. data/lib/active_record/log_subscriber.rb +68 -0
  96. data/lib/active_record/migration.rb +765 -0
  97. data/lib/active_record/migration/command_recorder.rb +105 -0
  98. data/lib/active_record/model_schema.rb +366 -0
  99. data/lib/active_record/nested_attributes.rb +469 -0
  100. data/lib/active_record/observer.rb +121 -0
  101. data/lib/active_record/persistence.rb +372 -0
  102. data/lib/active_record/query_cache.rb +74 -0
  103. data/lib/active_record/querying.rb +58 -0
  104. data/lib/active_record/railtie.rb +119 -0
  105. data/lib/active_record/railties/console_sandbox.rb +6 -0
  106. data/lib/active_record/railties/controller_runtime.rb +49 -0
  107. data/lib/active_record/railties/databases.rake +620 -0
  108. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  109. data/lib/active_record/readonly_attributes.rb +26 -0
  110. data/lib/active_record/reflection.rb +534 -0
  111. data/lib/active_record/relation.rb +534 -0
  112. data/lib/active_record/relation/batches.rb +90 -0
  113. data/lib/active_record/relation/calculations.rb +354 -0
  114. data/lib/active_record/relation/delegation.rb +49 -0
  115. data/lib/active_record/relation/finder_methods.rb +398 -0
  116. data/lib/active_record/relation/predicate_builder.rb +58 -0
  117. data/lib/active_record/relation/query_methods.rb +417 -0
  118. data/lib/active_record/relation/spawn_methods.rb +148 -0
  119. data/lib/active_record/result.rb +34 -0
  120. data/lib/active_record/sanitization.rb +194 -0
  121. data/lib/active_record/schema.rb +58 -0
  122. data/lib/active_record/schema_dumper.rb +204 -0
  123. data/lib/active_record/scoping.rb +152 -0
  124. data/lib/active_record/scoping/default.rb +142 -0
  125. data/lib/active_record/scoping/named.rb +202 -0
  126. data/lib/active_record/serialization.rb +18 -0
  127. data/lib/active_record/serializers/xml_serializer.rb +202 -0
  128. data/lib/active_record/session_store.rb +358 -0
  129. data/lib/active_record/store.rb +50 -0
  130. data/lib/active_record/test_case.rb +73 -0
  131. data/lib/active_record/timestamp.rb +113 -0
  132. data/lib/active_record/transactions.rb +360 -0
  133. data/lib/active_record/translation.rb +22 -0
  134. data/lib/active_record/validations.rb +83 -0
  135. data/lib/active_record/validations/associated.rb +43 -0
  136. data/lib/active_record/validations/uniqueness.rb +180 -0
  137. data/lib/active_record/version.rb +10 -0
  138. data/lib/rails/generators/active_record.rb +25 -0
  139. data/lib/rails/generators/active_record/migration.rb +15 -0
  140. data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
  141. data/lib/rails/generators/active_record/migration/templates/migration.rb +31 -0
  142. data/lib/rails/generators/active_record/model/model_generator.rb +43 -0
  143. data/lib/rails/generators/active_record/model/templates/migration.rb +15 -0
  144. data/lib/rails/generators/active_record/model/templates/model.rb +7 -0
  145. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  146. data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
  147. data/lib/rails/generators/active_record/observer/templates/observer.rb +4 -0
  148. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +25 -0
  149. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +12 -0
  150. metadata +242 -0
@@ -0,0 +1,74 @@
1
+ require 'active_support/core_ext/object/blank'
2
+
3
+ module ActiveRecord
4
+ # = Active Record Query Cache
5
+ class QueryCache
6
+ module ClassMethods
7
+ # Enable the query cache within the block if Active Record is configured.
8
+ def cache(&block)
9
+ if ActiveRecord::Base.configurations.blank?
10
+ yield
11
+ else
12
+ connection.cache(&block)
13
+ end
14
+ end
15
+
16
+ # Disable the query cache within the block if Active Record is configured.
17
+ def uncached(&block)
18
+ if ActiveRecord::Base.configurations.blank?
19
+ yield
20
+ else
21
+ connection.uncached(&block)
22
+ end
23
+ end
24
+ end
25
+
26
+ def initialize(app)
27
+ @app = app
28
+ end
29
+
30
+ class BodyProxy # :nodoc:
31
+ def initialize(original_cache_value, target, connection_id)
32
+ @original_cache_value = original_cache_value
33
+ @target = target
34
+ @connection_id = connection_id
35
+ end
36
+
37
+ def method_missing(method_sym, *arguments, &block)
38
+ @target.send(method_sym, *arguments, &block)
39
+ end
40
+
41
+ def respond_to?(method_sym, include_private = false)
42
+ super || @target.respond_to?(method_sym)
43
+ end
44
+
45
+ def each(&block)
46
+ @target.each(&block)
47
+ end
48
+
49
+ def close
50
+ @target.close if @target.respond_to?(:close)
51
+ ensure
52
+ ActiveRecord::Base.connection_id = @connection_id
53
+ ActiveRecord::Base.connection.clear_query_cache
54
+ unless @original_cache_value
55
+ ActiveRecord::Base.connection.disable_query_cache!
56
+ end
57
+ end
58
+ end
59
+
60
+ def call(env)
61
+ old = ActiveRecord::Base.connection.query_cache_enabled
62
+ ActiveRecord::Base.connection.enable_query_cache!
63
+
64
+ status, headers, body = @app.call(env)
65
+ [status, headers, BodyProxy.new(old, body, ActiveRecord::Base.connection_id)]
66
+ rescue Exception => e
67
+ ActiveRecord::Base.connection.clear_query_cache
68
+ unless old
69
+ ActiveRecord::Base.connection.disable_query_cache!
70
+ end
71
+ raise e
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,58 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
3
+ module ActiveRecord
4
+ module Querying
5
+ delegate :find, :first, :first!, :last, :last!, :all, :exists?, :any?, :many?, :to => :scoped
6
+ delegate :first_or_create, :first_or_create!, :first_or_initialize, :to => :scoped
7
+ delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :scoped
8
+ delegate :find_each, :find_in_batches, :to => :scoped
9
+ delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins,
10
+ :where, :preload, :eager_load, :includes, :from, :lock, :readonly,
11
+ :having, :create_with, :uniq, :to => :scoped
12
+ delegate :count, :average, :minimum, :maximum, :sum, :calculate, :pluck, :to => :scoped
13
+
14
+ # Executes a custom SQL query against your database and returns all the results. The results will
15
+ # be returned as an array with columns requested encapsulated as attributes of the model you call
16
+ # this method from. If you call <tt>Product.find_by_sql</tt> then the results will be returned in
17
+ # a Product object with the attributes you specified in the SQL query.
18
+ #
19
+ # If you call a complicated SQL query which spans multiple tables the columns specified by the
20
+ # SELECT will be attributes of the model, whether or not they are columns of the corresponding
21
+ # table.
22
+ #
23
+ # The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be
24
+ # no database agnostic conversions performed. This should be a last resort because using, for example,
25
+ # MySQL specific terms will lock you to using that particular database engine or require you to
26
+ # change your call if you switch engines.
27
+ #
28
+ # ==== Examples
29
+ # # A simple SQL query spanning multiple tables
30
+ # Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
31
+ # > [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
32
+ #
33
+ # # You can use the same string replacement techniques as you can with ActiveRecord#find
34
+ # Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
35
+ # > [#<Post:0x36bff9c @attributes={"title"=>"The Cheap Man Buys Twice"}>, ...]
36
+ def find_by_sql(sql, binds = [])
37
+ logging_query_plan do
38
+ connection.select_all(sanitize_sql(sql), "#{name} Load", binds).collect! { |record| instantiate(record) }
39
+ end
40
+ end
41
+
42
+ # Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
43
+ # The use of this method should be restricted to complicated SQL queries that can't be executed
44
+ # using the ActiveRecord::Calculations class methods. Look into those before using this.
45
+ #
46
+ # ==== Parameters
47
+ #
48
+ # * +sql+ - An SQL statement which should return a count query from the database, see the example below.
49
+ #
50
+ # ==== Examples
51
+ #
52
+ # Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
53
+ def count_by_sql(sql)
54
+ sql = sanitize_conditions(sql)
55
+ connection.select_value(sql, "#{name} Count").to_i
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,119 @@
1
+ require "active_record"
2
+ require "rails"
3
+ require "active_model/railtie"
4
+
5
+ # For now, action_controller must always be present with
6
+ # rails, so let's make sure that it gets required before
7
+ # here. This is needed for correctly setting up the middleware.
8
+ # In the future, this might become an optional require.
9
+ require "action_controller/railtie"
10
+
11
+ module ActiveRecord
12
+ # = Active Record Railtie
13
+ class Railtie < Rails::Railtie
14
+ config.active_record = ActiveSupport::OrderedOptions.new
15
+
16
+ config.app_generators.orm :active_record, :migration => true,
17
+ :timestamps => true
18
+
19
+ config.app_middleware.insert_after "::ActionDispatch::Callbacks",
20
+ "ActiveRecord::QueryCache"
21
+
22
+ config.app_middleware.insert_after "::ActionDispatch::Callbacks",
23
+ "ActiveRecord::ConnectionAdapters::ConnectionManagement"
24
+
25
+ config.action_dispatch.rescue_responses.merge!(
26
+ 'ActiveRecord::RecordNotFound' => :not_found,
27
+ 'ActiveRecord::StaleObjectError' => :conflict,
28
+ 'ActiveRecord::RecordInvalid' => :unprocessable_entity,
29
+ 'ActiveRecord::RecordNotSaved' => :unprocessable_entity
30
+ )
31
+
32
+ rake_tasks do
33
+ load "active_record/railties/databases.rake"
34
+ end
35
+
36
+ # When loading console, force ActiveRecord::Base to be loaded
37
+ # to avoid cross references when loading a constant for the
38
+ # first time. Also, make it output to STDERR.
39
+ console do |app|
40
+ require "active_record/railties/console_sandbox" if app.sandbox?
41
+ ActiveRecord::Base.logger = Logger.new(STDERR)
42
+ end
43
+
44
+ initializer "active_record.initialize_timezone" do
45
+ ActiveSupport.on_load(:active_record) do
46
+ self.time_zone_aware_attributes = true
47
+ self.default_timezone = :utc
48
+ end
49
+ end
50
+
51
+ initializer "active_record.logger" do
52
+ ActiveSupport.on_load(:active_record) { self.logger ||= ::Rails.logger }
53
+ end
54
+
55
+ initializer "active_record.identity_map" do |app|
56
+ config.app_middleware.insert_after "::ActionDispatch::Callbacks",
57
+ "ActiveRecord::IdentityMap::Middleware" if config.active_record.delete(:identity_map)
58
+ end
59
+
60
+ initializer "active_record.set_configs" do |app|
61
+ ActiveSupport.on_load(:active_record) do
62
+ if app.config.active_record.delete(:whitelist_attributes)
63
+ attr_accessible(nil)
64
+ end
65
+ app.config.active_record.each do |k,v|
66
+ send "#{k}=", v
67
+ end
68
+ end
69
+ end
70
+
71
+ # This sets the database configuration from Configuration#database_configuration
72
+ # and then establishes the connection.
73
+ initializer "active_record.initialize_database" do |app|
74
+ ActiveSupport.on_load(:active_record) do
75
+ self.configurations = app.config.database_configuration
76
+ establish_connection
77
+ end
78
+ end
79
+
80
+ # Expose database runtime to controller for logging.
81
+ initializer "active_record.log_runtime" do |app|
82
+ require "active_record/railties/controller_runtime"
83
+ ActiveSupport.on_load(:action_controller) do
84
+ include ActiveRecord::Railties::ControllerRuntime
85
+ end
86
+ end
87
+
88
+ initializer "active_record.set_reloader_hooks" do |app|
89
+ hook = lambda do
90
+ ActiveRecord::Base.clear_reloadable_connections!
91
+ ActiveRecord::Base.clear_cache!
92
+ end
93
+
94
+ if app.config.reload_classes_only_on_change
95
+ ActiveSupport.on_load(:active_record) do
96
+ ActionDispatch::Reloader.to_prepare(&hook)
97
+ end
98
+ else
99
+ ActiveSupport.on_load(:active_record) do
100
+ ActionDispatch::Reloader.to_cleanup(&hook)
101
+ end
102
+ end
103
+ end
104
+
105
+ initializer "active_record.add_watchable_files" do |app|
106
+ config.watchable_files.concat ["#{app.root}/db/schema.rb", "#{app.root}/db/structure.sql"]
107
+ end
108
+
109
+ config.after_initialize do
110
+ ActiveSupport.on_load(:active_record) do
111
+ instantiate_observers
112
+
113
+ ActionDispatch::Reloader.to_prepare do
114
+ ActiveRecord::Base.instantiate_observers
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,6 @@
1
+ ActiveRecord::Base.connection.increment_open_transactions
2
+ ActiveRecord::Base.connection.begin_db_transaction
3
+ at_exit do
4
+ ActiveRecord::Base.connection.rollback_db_transaction
5
+ ActiveRecord::Base.connection.decrement_open_transactions
6
+ end
@@ -0,0 +1,49 @@
1
+ require 'active_support/core_ext/module/attr_internal'
2
+ require 'active_record/log_subscriber'
3
+
4
+ module ActiveRecord
5
+ module Railties
6
+ module ControllerRuntime #:nodoc:
7
+ extend ActiveSupport::Concern
8
+
9
+ protected
10
+
11
+ attr_internal :db_runtime
12
+
13
+ def process_action(action, *args)
14
+ # We also need to reset the runtime before each action
15
+ # because of queries in middleware or in cases we are streaming
16
+ # and it won't be cleaned up by the method below.
17
+ ActiveRecord::LogSubscriber.reset_runtime
18
+ super
19
+ end
20
+
21
+ def cleanup_view_runtime
22
+ if ActiveRecord::Base.connected?
23
+ db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
24
+ runtime = super
25
+ db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime
26
+ self.db_runtime = db_rt_before_render + db_rt_after_render
27
+ runtime - db_rt_after_render
28
+ else
29
+ super
30
+ end
31
+ end
32
+
33
+ def append_info_to_payload(payload)
34
+ super
35
+ if ActiveRecord::Base.connected?
36
+ payload[:db_runtime] = (db_runtime || 0) + ActiveRecord::LogSubscriber.reset_runtime
37
+ end
38
+ end
39
+
40
+ module ClassMethods
41
+ def log_process_action(payload)
42
+ messages, db_runtime = super, payload[:db_runtime]
43
+ messages << ("ActiveRecord: %.1fms" % db_runtime.to_f) if db_runtime
44
+ messages
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,620 @@
1
+ require 'active_support/core_ext/object/inclusion'
2
+ require 'active_record'
3
+
4
+ db_namespace = namespace :db do
5
+ task :load_config => :rails_env do
6
+ ActiveRecord::Base.configurations = Rails.application.config.database_configuration
7
+ ActiveRecord::Migrator.migrations_paths = Rails.application.paths['db/migrate'].to_a
8
+
9
+ if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH)
10
+ if engine.paths['db/migrate'].existent
11
+ ActiveRecord::Migrator.migrations_paths += engine.paths['db/migrate'].to_a
12
+ end
13
+ end
14
+ end
15
+
16
+ namespace :create do
17
+ # desc 'Create all the local databases defined in config/database.yml'
18
+ task :all => :load_config do
19
+ ActiveRecord::Base.configurations.each_value do |config|
20
+ # Skip entries that don't have a database key, such as the first entry here:
21
+ #
22
+ # defaults: &defaults
23
+ # adapter: mysql
24
+ # username: root
25
+ # password:
26
+ # host: localhost
27
+ #
28
+ # development:
29
+ # database: blog_development
30
+ # *defaults
31
+ next unless config['database']
32
+ # Only connect to local databases
33
+ local_database?(config) { create_database(config) }
34
+ end
35
+ end
36
+ end
37
+
38
+ desc 'Create the database from config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)'
39
+ task :create => :load_config do
40
+ configs_for_environment.each { |config| create_database(config) }
41
+ ActiveRecord::Base.establish_connection(configs_for_environment.first)
42
+ end
43
+
44
+ def mysql_creation_options(config)
45
+ @charset = ENV['CHARSET'] || 'utf8'
46
+ @collation = ENV['COLLATION'] || 'utf8_unicode_ci'
47
+ {:charset => (config['charset'] || @charset), :collation => (config['collation'] || @collation)}
48
+ end
49
+
50
+ def create_database(config)
51
+ begin
52
+ if config['adapter'] =~ /sqlite/
53
+ if File.exist?(config['database'])
54
+ $stderr.puts "#{config['database']} already exists"
55
+ else
56
+ begin
57
+ # Create the SQLite database
58
+ ActiveRecord::Base.establish_connection(config)
59
+ ActiveRecord::Base.connection
60
+ rescue Exception => e
61
+ $stderr.puts e, *(e.backtrace)
62
+ $stderr.puts "Couldn't create database for #{config.inspect}"
63
+ end
64
+ end
65
+ return # Skip the else clause of begin/rescue
66
+ else
67
+ ActiveRecord::Base.establish_connection(config)
68
+ ActiveRecord::Base.connection
69
+ end
70
+ rescue
71
+ case config['adapter']
72
+ when /mysql/
73
+ if config['adapter'] =~ /jdbc/
74
+ #FIXME After Jdbcmysql gives this class
75
+ require 'active_record/railties/jdbcmysql_error'
76
+ error_class = ArJdbcMySQL::Error
77
+ else
78
+ error_class = config['adapter'] =~ /mysql2/ ? Mysql2::Error : Mysql::Error
79
+ end
80
+ access_denied_error = 1045
81
+ begin
82
+ ActiveRecord::Base.establish_connection(config.merge('database' => nil))
83
+ ActiveRecord::Base.connection.create_database(config['database'], mysql_creation_options(config))
84
+ ActiveRecord::Base.establish_connection(config)
85
+ rescue error_class => sqlerr
86
+ if sqlerr.errno == access_denied_error
87
+ print "#{sqlerr.error}. \nPlease provide the root password for your mysql installation\n>"
88
+ root_password = $stdin.gets.strip
89
+ grant_statement = "GRANT ALL PRIVILEGES ON #{config['database']}.* " \
90
+ "TO '#{config['username']}'@'localhost' " \
91
+ "IDENTIFIED BY '#{config['password']}' WITH GRANT OPTION;"
92
+ ActiveRecord::Base.establish_connection(config.merge(
93
+ 'database' => nil, 'username' => 'root', 'password' => root_password))
94
+ ActiveRecord::Base.connection.create_database(config['database'], mysql_creation_options(config))
95
+ ActiveRecord::Base.connection.execute grant_statement
96
+ ActiveRecord::Base.establish_connection(config)
97
+ else
98
+ $stderr.puts sqlerr.error
99
+ $stderr.puts "Couldn't create database for #{config.inspect}, charset: #{config['charset'] || @charset}, collation: #{config['collation'] || @collation}"
100
+ $stderr.puts "(if you set the charset manually, make sure you have a matching collation)" if config['charset']
101
+ end
102
+ end
103
+ when /postgresql/
104
+ @encoding = config['encoding'] || ENV['CHARSET'] || 'utf8'
105
+ begin
106
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
107
+ ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding))
108
+ ActiveRecord::Base.establish_connection(config)
109
+ rescue Exception => e
110
+ $stderr.puts e, *(e.backtrace)
111
+ $stderr.puts "Couldn't create database for #{config.inspect}"
112
+ end
113
+ end
114
+ else
115
+ # Bug with 1.9.2 Calling return within begin still executes else
116
+ $stderr.puts "#{config['database']} already exists" unless config['adapter'] =~ /sqlite/
117
+ end
118
+ end
119
+
120
+ namespace :drop do
121
+ # desc 'Drops all the local databases defined in config/database.yml'
122
+ task :all => :load_config do
123
+ ActiveRecord::Base.configurations.each_value do |config|
124
+ # Skip entries that don't have a database key
125
+ next unless config['database']
126
+ begin
127
+ # Only connect to local databases
128
+ local_database?(config) { drop_database(config) }
129
+ rescue Exception => e
130
+ $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ desc 'Drops the database for the current Rails.env (use db:drop:all to drop all databases)'
137
+ task :drop => :load_config do
138
+ configs_for_environment.each { |config| drop_database_and_rescue(config) }
139
+ end
140
+
141
+ def local_database?(config, &block)
142
+ if config['host'].in?(['127.0.0.1', 'localhost']) || config['host'].blank?
143
+ yield
144
+ else
145
+ $stderr.puts "This task only modifies local databases. #{config['database']} is on a remote host."
146
+ end
147
+ end
148
+
149
+
150
+ desc "Migrate the database (options: VERSION=x, VERBOSE=false)."
151
+ task :migrate => [:environment, :load_config] do
152
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
153
+ ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) do |migration|
154
+ ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
155
+ end
156
+ db_namespace['_dump'].invoke
157
+ end
158
+
159
+ task :_dump do
160
+ case ActiveRecord::Base.schema_format
161
+ when :ruby then db_namespace["schema:dump"].invoke
162
+ when :sql then db_namespace["structure:dump"].invoke
163
+ else
164
+ raise "unknown schema format #{ActiveRecord::Base.schema_format}"
165
+ end
166
+ end
167
+
168
+ namespace :migrate do
169
+ # desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
170
+ task :redo => [:environment, :load_config] do
171
+ if ENV['VERSION']
172
+ db_namespace['migrate:down'].invoke
173
+ db_namespace['migrate:up'].invoke
174
+ else
175
+ db_namespace['rollback'].invoke
176
+ db_namespace['migrate'].invoke
177
+ end
178
+ end
179
+
180
+ # desc 'Resets your database using your migrations for the current environment'
181
+ task :reset => ['db:drop', 'db:create', 'db:migrate']
182
+
183
+ # desc 'Runs the "up" for a given migration VERSION.'
184
+ task :up => [:environment, :load_config] do
185
+ version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
186
+ raise 'VERSION is required' unless version
187
+ ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, version)
188
+ db_namespace['_dump'].invoke
189
+ end
190
+
191
+ # desc 'Runs the "down" for a given migration VERSION.'
192
+ task :down => [:environment, :load_config] do
193
+ version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
194
+ raise 'VERSION is required' unless version
195
+ ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version)
196
+ db_namespace['_dump'].invoke
197
+ end
198
+
199
+ desc 'Display status of migrations'
200
+ task :status => [:environment, :load_config] do
201
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
202
+ ActiveRecord::Base.establish_connection(config)
203
+ unless ActiveRecord::Base.connection.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name)
204
+ puts 'Schema migrations table does not exist yet.'
205
+ next # means "return" for rake task
206
+ end
207
+ db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}")
208
+ file_list = []
209
+ ActiveRecord::Migrator.migrations_paths.each do |path|
210
+ Dir.foreach(path) do |file|
211
+ # only files matching "20091231235959_some_name.rb" pattern
212
+ if match_data = /^(\d{14})_(.+)\.rb$/.match(file)
213
+ status = db_list.delete(match_data[1]) ? 'up' : 'down'
214
+ file_list << [status, match_data[1], match_data[2].humanize]
215
+ end
216
+ end
217
+ end
218
+ db_list.map! do |version|
219
+ ['up', version, '********** NO FILE **********']
220
+ end
221
+ # output
222
+ puts "\ndatabase: #{config['database']}\n\n"
223
+ puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
224
+ puts "-" * 50
225
+ (db_list + file_list).sort_by {|migration| migration[1]}.each do |migration|
226
+ puts "#{migration[0].center(8)} #{migration[1].ljust(14)} #{migration[2]}"
227
+ end
228
+ puts
229
+ end
230
+ end
231
+
232
+ desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
233
+ task :rollback => [:environment, :load_config] do
234
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
235
+ ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
236
+ db_namespace['_dump'].invoke
237
+ end
238
+
239
+ # desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
240
+ task :forward => [:environment, :load_config] do
241
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
242
+ ActiveRecord::Migrator.forward(ActiveRecord::Migrator.migrations_paths, step)
243
+ db_namespace['_dump'].invoke
244
+ end
245
+
246
+ # desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
247
+ task :reset => :environment do
248
+ db_namespace["drop"].invoke
249
+ db_namespace["setup"].invoke
250
+ end
251
+
252
+ # desc "Retrieves the charset for the current environment's database"
253
+ task :charset => :environment do
254
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
255
+ case config['adapter']
256
+ when /mysql/
257
+ ActiveRecord::Base.establish_connection(config)
258
+ puts ActiveRecord::Base.connection.charset
259
+ when /postgresql/
260
+ ActiveRecord::Base.establish_connection(config)
261
+ puts ActiveRecord::Base.connection.encoding
262
+ when /sqlite/
263
+ ActiveRecord::Base.establish_connection(config)
264
+ puts ActiveRecord::Base.connection.encoding
265
+ else
266
+ $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
267
+ end
268
+ end
269
+
270
+ # desc "Retrieves the collation for the current environment's database"
271
+ task :collation => :environment do
272
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
273
+ case config['adapter']
274
+ when /mysql/
275
+ ActiveRecord::Base.establish_connection(config)
276
+ puts ActiveRecord::Base.connection.collation
277
+ else
278
+ $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
279
+ end
280
+ end
281
+
282
+ desc 'Retrieves the current schema version number'
283
+ task :version => :environment do
284
+ puts "Current version: #{ActiveRecord::Migrator.current_version}"
285
+ end
286
+
287
+ # desc "Raises an error if there are pending migrations"
288
+ task :abort_if_pending_migrations => :environment do
289
+ pending_migrations = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations_paths).pending_migrations
290
+
291
+ if pending_migrations.any?
292
+ puts "You have #{pending_migrations.size} pending migrations:"
293
+ pending_migrations.each do |pending_migration|
294
+ puts ' %4d %s' % [pending_migration.version, pending_migration.name]
295
+ end
296
+ abort %{Run `rake db:migrate` to update your database then try again.}
297
+ end
298
+ end
299
+
300
+ desc 'Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)'
301
+ task :setup => ['db:schema:load_if_ruby', 'db:structure:load_if_sql', :seed]
302
+
303
+ desc 'Load the seed data from db/seeds.rb'
304
+ task :seed do
305
+ db_namespace['abort_if_pending_migrations'].invoke
306
+ Rails.application.load_seed
307
+ end
308
+
309
+ namespace :fixtures do
310
+ desc "Load fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
311
+ task :load => :environment do
312
+ require 'active_record/fixtures'
313
+
314
+ ActiveRecord::Base.establish_connection(Rails.env)
315
+ base_dir = File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
316
+ fixtures_dir = File.join [base_dir, ENV['FIXTURES_DIR']].compact
317
+
318
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir["#{fixtures_dir}/**/*.{yml,csv}"].map {|f| f[(fixtures_dir.size + 1)..-5] }).each do |fixture_file|
319
+ ActiveRecord::Fixtures.create_fixtures(fixtures_dir, fixture_file)
320
+ end
321
+ end
322
+
323
+ # desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
324
+ task :identify => :environment do
325
+ require 'active_record/fixtures'
326
+
327
+ label, id = ENV['LABEL'], ENV['ID']
328
+ raise 'LABEL or ID required' if label.blank? && id.blank?
329
+
330
+ puts %Q(The fixture ID for "#{label}" is #{ActiveRecord::Fixtures.identify(label)}.) if label
331
+
332
+ base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures')
333
+ Dir["#{base_dir}/**/*.yml"].each do |file|
334
+ if data = YAML::load(ERB.new(IO.read(file)).result)
335
+ data.keys.each do |key|
336
+ key_id = ActiveRecord::Fixtures.identify(key)
337
+
338
+ if key == label || key_id == id.to_i
339
+ puts "#{file}: #{key} (#{key_id})"
340
+ end
341
+ end
342
+ end
343
+ end
344
+ end
345
+ end
346
+
347
+ namespace :schema do
348
+ desc 'Create a db/schema.rb file that can be portably used against any DB supported by AR'
349
+ task :dump => [:environment, :load_config] do
350
+ require 'active_record/schema_dumper'
351
+ filename = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
352
+ File.open(filename, "w:utf-8") do |file|
353
+ ActiveRecord::Base.establish_connection(Rails.env)
354
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
355
+ end
356
+ db_namespace['schema:dump'].reenable
357
+ end
358
+
359
+ desc 'Load a schema.rb file into the database'
360
+ task :load => :environment do
361
+ file = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
362
+ if File.exists?(file)
363
+ load(file)
364
+ else
365
+ abort %{#{file} doesn't exist yet. Run `rake db:migrate` to create it then try again. If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded}
366
+ end
367
+ end
368
+
369
+ task :load_if_ruby => 'db:create' do
370
+ db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :ruby
371
+ end
372
+ end
373
+
374
+ namespace :structure do
375
+ desc 'Dump the database structure to db/structure.sql. Specify another file with DB_STRUCTURE=db/my_structure.sql'
376
+ task :dump => :environment do
377
+ abcs = ActiveRecord::Base.configurations
378
+ filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
379
+ case abcs[Rails.env]['adapter']
380
+ when /mysql/, 'oci', 'oracle'
381
+ ActiveRecord::Base.establish_connection(abcs[Rails.env])
382
+ File.open(filename, "w:utf-8") { |f| f << ActiveRecord::Base.connection.structure_dump }
383
+ when /postgresql/
384
+ set_psql_env(abcs[Rails.env])
385
+ search_path = abcs[Rails.env]['schema_search_path']
386
+ unless search_path.blank?
387
+ search_path = search_path.split(",").map{|search_path_part| "--schema=#{search_path_part.strip}" }.join(" ")
388
+ end
389
+ `pg_dump -i -s -x -O -f #{filename} #{search_path} #{abcs[Rails.env]['database']}`
390
+ raise 'Error dumping database' if $?.exitstatus == 1
391
+ when /sqlite/
392
+ dbfile = abcs[Rails.env]['database']
393
+ `sqlite3 #{dbfile} .schema > #{filename}`
394
+ when 'sqlserver'
395
+ `smoscript -s #{abcs[Rails.env]['host']} -d #{abcs[Rails.env]['database']} -u #{abcs[Rails.env]['username']} -p #{abcs[Rails.env]['password']} -f #{filename} -A -U`
396
+ when "firebird"
397
+ set_firebird_env(abcs[Rails.env])
398
+ db_string = firebird_db_string(abcs[Rails.env])
399
+ sh "isql -a #{db_string} > #{filename}"
400
+ else
401
+ raise "Task not supported by '#{abcs[Rails.env]["adapter"]}'"
402
+ end
403
+
404
+ if ActiveRecord::Base.connection.supports_migrations?
405
+ File.open(filename, "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
406
+ end
407
+ end
408
+
409
+ # desc "Recreate the databases from the structure.sql file"
410
+ task :load => [:environment, :load_config] do
411
+ env = ENV['RAILS_ENV'] || 'test'
412
+
413
+ abcs = ActiveRecord::Base.configurations
414
+ filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
415
+ case abcs[env]['adapter']
416
+ when /mysql/
417
+ ActiveRecord::Base.establish_connection(abcs[env])
418
+ ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
419
+ IO.read(filename).split("\n\n").each do |table|
420
+ ActiveRecord::Base.connection.execute(table)
421
+ end
422
+ when /postgresql/
423
+ set_psql_env(abcs[env])
424
+ `psql -f "#{filename}" #{abcs[env]['database']}`
425
+ when /sqlite/
426
+ dbfile = abcs[env]['database']
427
+ `sqlite3 #{dbfile} < "#{filename}"`
428
+ when 'sqlserver'
429
+ `sqlcmd -S #{abcs[env]['host']} -d #{abcs[env]['database']} -U #{abcs[env]['username']} -P #{abcs[env]['password']} -i #{filename}`
430
+ when 'oci', 'oracle'
431
+ ActiveRecord::Base.establish_connection(abcs[env])
432
+ IO.read(filename).split(";\n\n").each do |ddl|
433
+ ActiveRecord::Base.connection.execute(ddl)
434
+ end
435
+ when 'firebird'
436
+ set_firebird_env(abcs[env])
437
+ db_string = firebird_db_string(abcs[env])
438
+ sh "isql -i #{filename} #{db_string}"
439
+ else
440
+ raise "Task not supported by '#{abcs[env]['adapter']}'"
441
+ end
442
+ end
443
+
444
+ task :load_if_sql => 'db:create' do
445
+ db_namespace["structure:load"].invoke if ActiveRecord::Base.schema_format == :sql
446
+ end
447
+ end
448
+
449
+ namespace :test do
450
+
451
+ # desc "Recreate the test database from the current schema"
452
+ task :load => 'db:test:purge' do
453
+ case ActiveRecord::Base.schema_format
454
+ when :ruby
455
+ db_namespace["test:load_schema"].invoke
456
+ when :sql
457
+ db_namespace["test:load_structure"].invoke
458
+ end
459
+ end
460
+
461
+ # desc "Recreate the test database from an existent structure.sql file"
462
+ task :load_structure => 'db:test:purge' do
463
+ begin
464
+ old_env, ENV['RAILS_ENV'] = ENV['RAILS_ENV'], 'test'
465
+ db_namespace["structure:load"].invoke
466
+ ensure
467
+ ENV['RAILS_ENV'] = old_env
468
+ end
469
+ end
470
+
471
+ # desc "Recreate the test database from an existent schema.rb file"
472
+ task :load_schema => 'db:test:purge' do
473
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
474
+ ActiveRecord::Schema.verbose = false
475
+ db_namespace["schema:load"].invoke
476
+ end
477
+
478
+ # desc "Recreate the test database from a fresh schema.rb file"
479
+ task :clone => %w(db:schema:dump db:test:load_schema)
480
+
481
+ # desc "Recreate the test database from a fresh structure.sql file"
482
+ task :clone_structure => [ "db:structure:dump", "db:test:load_structure" ]
483
+
484
+ # desc "Empty the test database"
485
+ task :purge => :environment do
486
+ abcs = ActiveRecord::Base.configurations
487
+ case abcs['test']['adapter']
488
+ when /mysql/
489
+ ActiveRecord::Base.establish_connection(:test)
490
+ ActiveRecord::Base.connection.recreate_database(abcs['test']['database'], mysql_creation_options(abcs['test']))
491
+ when /postgresql/
492
+ ActiveRecord::Base.clear_active_connections!
493
+ drop_database(abcs['test'])
494
+ create_database(abcs['test'])
495
+ when /sqlite/
496
+ dbfile = abcs['test']['database']
497
+ File.delete(dbfile) if File.exist?(dbfile)
498
+ when 'sqlserver'
499
+ test = abcs.deep_dup['test']
500
+ test_database = test['database']
501
+ test['database'] = 'master'
502
+ ActiveRecord::Base.establish_connection(test)
503
+ ActiveRecord::Base.connection.recreate_database!(test_database)
504
+ when "oci", "oracle"
505
+ ActiveRecord::Base.establish_connection(:test)
506
+ ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl|
507
+ ActiveRecord::Base.connection.execute(ddl)
508
+ end
509
+ when 'firebird'
510
+ ActiveRecord::Base.establish_connection(:test)
511
+ ActiveRecord::Base.connection.recreate_database!
512
+ else
513
+ raise "Task not supported by '#{abcs['test']['adapter']}'"
514
+ end
515
+ end
516
+
517
+ # desc 'Check for pending migrations and load the test schema'
518
+ task :prepare => 'db:abort_if_pending_migrations' do
519
+ unless ActiveRecord::Base.configurations.blank?
520
+ db_namespace[{ :sql => 'test:clone_structure', :ruby => 'test:load' }[ActiveRecord::Base.schema_format]].invoke
521
+ end
522
+ end
523
+ end
524
+
525
+ namespace :sessions do
526
+ # desc "Creates a sessions migration for use with ActiveRecord::SessionStore"
527
+ task :create => :environment do
528
+ raise 'Task unavailable to this database (no migration support)' unless ActiveRecord::Base.connection.supports_migrations?
529
+ Rails.application.load_generators
530
+ require 'rails/generators/rails/session_migration/session_migration_generator'
531
+ Rails::Generators::SessionMigrationGenerator.start [ ENV['MIGRATION'] || 'add_sessions_table' ]
532
+ end
533
+
534
+ # desc "Clear the sessions table"
535
+ task :clear => :environment do
536
+ ActiveRecord::Base.connection.execute "DELETE FROM #{session_table_name}"
537
+ end
538
+ end
539
+ end
540
+
541
+ namespace :railties do
542
+ namespace :install do
543
+ # desc "Copies missing migrations from Railties (e.g. plugins, engines). You can specify Railties to use with FROM=railtie1,railtie2"
544
+ task :migrations => :'db:load_config' do
545
+ to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map {|n| n.strip }
546
+ railties = ActiveSupport::OrderedHash.new
547
+ Rails.application.railties.all do |railtie|
548
+ next unless to_load == :all || to_load.include?(railtie.railtie_name)
549
+
550
+ if railtie.respond_to?(:paths) && (path = railtie.paths['db/migrate'].first)
551
+ railties[railtie.railtie_name] = path
552
+ end
553
+ end
554
+
555
+ on_skip = Proc.new do |name, migration|
556
+ puts "NOTE: Migration #{migration.basename} from #{name} has been skipped. Migration with the same name already exists."
557
+ end
558
+
559
+ on_copy = Proc.new do |name, migration, old_path|
560
+ puts "Copied migration #{migration.basename} from #{name}"
561
+ end
562
+
563
+ ActiveRecord::Migration.copy( ActiveRecord::Migrator.migrations_paths.first, railties,
564
+ :on_skip => on_skip, :on_copy => on_copy)
565
+ end
566
+ end
567
+ end
568
+
569
+ task 'test:prepare' => 'db:test:prepare'
570
+
571
+ def drop_database(config)
572
+ case config['adapter']
573
+ when /mysql/
574
+ ActiveRecord::Base.establish_connection(config)
575
+ ActiveRecord::Base.connection.drop_database config['database']
576
+ when /sqlite/
577
+ require 'pathname'
578
+ path = Pathname.new(config['database'])
579
+ file = path.absolute? ? path.to_s : File.join(Rails.root, path)
580
+
581
+ FileUtils.rm(file)
582
+ when /postgresql/
583
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
584
+ ActiveRecord::Base.connection.drop_database config['database']
585
+ end
586
+ end
587
+
588
+ def drop_database_and_rescue(config)
589
+ begin
590
+ drop_database(config)
591
+ rescue Exception => e
592
+ $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
593
+ end
594
+ end
595
+
596
+ def configs_for_environment
597
+ environments = [Rails.env]
598
+ environments << 'test' if Rails.env.development?
599
+ ActiveRecord::Base.configurations.values_at(*environments).compact.reject { |config| config['database'].blank? }
600
+ end
601
+
602
+ def session_table_name
603
+ ActiveRecord::SessionStore::Session.table_name
604
+ end
605
+
606
+ def set_firebird_env(config)
607
+ ENV['ISC_USER'] = config['username'].to_s if config['username']
608
+ ENV['ISC_PASSWORD'] = config['password'].to_s if config['password']
609
+ end
610
+
611
+ def firebird_db_string(config)
612
+ FireRuby::Database.db_string_for(config.symbolize_keys)
613
+ end
614
+
615
+ def set_psql_env(config)
616
+ ENV['PGHOST'] = config['host'] if config['host']
617
+ ENV['PGPORT'] = config['port'].to_s if config['port']
618
+ ENV['PGPASSWORD'] = config['password'].to_s if config['password']
619
+ ENV['PGUSER'] = config['username'].to_s if config['username']
620
+ end