Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #11608 (new defect)

Opened 7 months ago

Last modified 6 months ago

[PATCH] Can't have 2 migrations in same plugin - timestamped migrations have version collision

Reported by: cnk Assigned to: core
Priority: normal Milestone: 2.1
Component: Railties Version: edge
Severity: normal Keywords: timestamp migration
Cc:

Description

If you have 2 migrations within a plugin, they end up with different file names but the same version number. So rake db:migrate fails with "Multiple migrations have the version number 20080422212223".

In railties/lib/rails_generator/commands.rb migration_template checks for file name collisions - but only for the name portion of the full file name. Something needs to check for version (timestamp) collisions but I am not sure whether to do that by adding a version_exists? method and calling that from migration_template - or should I augment next_migration_string to check for collisions before returning the timestamp as version number?

This was probably broken in commit c00de99f69358b58ca2bd6bc732e2de1b667800e and is definitely broken as of svn revision 9248.

Change History

(follow-up: ↓ 2 ) 04/23/08 22:27:22 changed by cnk

Sorry no test to submit yet - still sorting through the testing DSL. In the mean time, my fix. I don't love this solution - it could probably be more succinct- but for what it's worth:

diff --git a/railties/lib/rails_generator/commands.rb b/railties/lib/rails_generator/commands.rb
index 440bab2..e5d0dc1 100644
--- a/railties/lib/rails_generator/commands.rb
+++ b/railties/lib/rails_generator/commands.rb
@@ -69,8 +69,22 @@ module Rails
             not existing_migrations(file_name).empty?
           end

+          def existing_versions(version_string)
+            Dir.glob("#{@migration_directory}/[0-9]*_*.rb").grep(/#{version_string}/)
+          end
+
+          def version_exists?(version_string)
+            not existing_versions(version_string).empty?
+          end
+
           def next_migration_string(padding = 3)
-            Time.now.utc.strftime("%Y%m%d%H%M%S")
+            thetime = Time.now.utc
+            version_string = thetime.strftime("%Y%m%d%H%M%S")
+            while version_exists?(version_string)
+              thetime = thetime.succ
+              version_string = thetime.strftime("%Y%m%d%H%M%S")
+            end
+            return version_string
           end

           def gsub_file(relative_destination, regexp, *args, &block)


(in reply to: ↑ 1 ) 04/24/08 02:14:33 changed by cnk

darn it. error

diff --git a/railties/lib/rails_generator/commands.rb b/railties/lib/rails_generator/commands.rb
index 440bab2..e5d0dc1 100644
--- a/railties/lib/rails_generator/commands.rb
+++ b/railties/lib/rails_generator/commands.rb
@@ -69,8 +69,22 @@ module Rails
             not existing_migrations(file_name).empty?
           end

+          def existing_versions(version_string)
+            Dir.glob("#{@migration_directory}/[0-9]*_*.rb").grep(/#{version_string}/)
+          end
+
+          def version_exists?(version_string)
+            not existing_versions(version_string).empty?
+          end
+
           def next_migration_string(padding = 3)
-            Time.now.utc.strftime("%Y%m%d%H%M%S")
+            thetime = Time.now.utc
+            version_string = thetime.strftime("%Y%m%d%H%M%S")
+            while version_exists?(version_string)
+              thetime = thetime.succ.utc
+              version_string = thetime.strftime("%Y%m%d%H%M%S")
+            end
+            return version_string
           end

           def gsub_file(relative_destination, regexp, *args, &block)

06/04/08 10:46:09 changed by zephyrjk

  • keywords set to timestamp migration.
  • milestone changed from 2.x to 2.1.

Here's my version of the fix:

  def version_exists?(version_string)
    Dir.glob("#{RAILS_ROOT}/#{@migration_directory}/[0-9]*_*.rb").inject(false) do |matched, file_path|
      matched || (File.basename(file_path).split('_', 2).first == version_string)
    end
  end
  
  def check_available_version(version_string)
    version_exists?(version_string) ? check_available_version(version_string.succ) : version_string
  end

  def next_migration_string(padding = 3)
    check_available_version(Time.now.utc.strftime("%Y%m%d%H%M%S"))
  end

06/06/08 07:04:24 changed by zephyrjk

  • summary changed from Can't have 2 migrations in same plugin - timestamped migrations have version collision to [PATCH] Can't have 2 migrations in same plugin - timestamped migrations have version collision.

@@ -69,8 +69,20 @@

not existing_migrations(file_name).empty?

end

+ def existing_versions(version_string) + Dir.glob("#{RAILS_ROOT}/#{@migration_directory}/[0-9]*_*.rb").grep(/#{version_string}_[\w_]+.rb$/) + end + + def version_exists?(version_string) + not existing_versons(version_string).empty? + end + + def check_migration_version(version_string) + version_exists?(version_string) ? check_migration_version(version_string.succ) : version_string + end +

def next_migration_string(padding = 3)

- Time.now.utc.strftime("%Y%m%d%H%M%S") + check_migration_version(Time.now.utc.strftime("%Y%m%d%H%M%S"))

end

def gsub_file(relative_destination, regexp, *args, &block)

06/06/08 07:14:45 changed by zephyrjk

oops... let's try again

--- /opt/local/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/rails_generator/commands.rb	2008-06-02 11:53:25.000000000 +0800
+++ /opt/local/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/rails_generator/commands_new.rb	2008-06-06 15:09:22.000000000 +0800
@@ -69,8 +69,20 @@
             not existing_migrations(file_name).empty?
           end
 
+          def existing_versions(version_string)
+            Dir.glob("#{RAILS_ROOT}/#{@migration_directory}/[0-9]*_*.rb").grep(/#{version_string}_[\w_]+.rb$/)
+          end
+
+          def version_exists?(version_string)
+            not existing_versons(version_string).empty?
+          end
+
+          def check_migration_version(version_string)
+            version_exists?(version_string) ? check_migration_version(version_string.succ) : version_string
+          end
+
           def next_migration_string(padding = 3)
-            Time.now.utc.strftime("%Y%m%d%H%M%S")
+            check_migration_version(Time.now.utc.strftime("%Y%m%d%H%M%S"))
           end
 
           def gsub_file(relative_destination, regexp, *args, &block)