-
-
Save gilesbowkett/1022355 to your computer and use it in GitHub Desktop.
# this monkey-patches code defined in railties-3.1.0.rc1/lib/rails/generators/migration.rb | |
# (obviously, this might differ very slightly in the latest release candidate) | |
module Rails | |
module Generators | |
module Migration | |
module ClassMethods | |
# differs from the "real" version by only one line | |
def migration_template(source, destination=nil, config={}) | |
destination = File.expand_path(destination || source, self.destination_root) | |
migration_dir = File.dirname(destination) | |
@migration_number = self.class.next_migration_number(migration_dir) | |
@migration_file_name = File.basename(destination).sub(/\.rb$/, '') | |
@migration_class_name = @migration_file_name.camelize | |
destination = self.class.migration_exists?(migration_dir, @migration_file_name) | |
if !(destination && options[:skip]) && behavior == :invoke | |
if destination && options.force? | |
remove_file(destination) | |
elsif destination | |
raise Error, "Another migration is already named #{@migration_file_name}: #{destination}" | |
end | |
destination = File.join(migration_dir, "#{@migration_number}_#{@migration_file_name}.rb") | |
system("printf #{destination} | pbcopy") # this is that one line | |
end | |
template(source, destination, config) | |
end | |
end | |
end | |
end | |
# note that if you change the line above, reversing the order of migration_number and | |
# migration_file_name, you can also get migration filenames which are not, from the perspective | |
# of experienced Unix users, completely fucking insane in their incomprehensible disregard | |
# for the incredible usefulness of tab completion (a baffling flaw also shared by Rails's | |
# config.ru default rackup file name). | |
# HOWEVER, making that change very likely breaks rake db:migrate, so I'm not going to advocate that | |
# unless I find time to make sure it works. :-) |
Actually, it looks like in Rails 3.1, the original file loads, then the init.rb loads and the monkeypatch happens as expected.
However, I was using Rails 3.0.7 which seems to load in the reverse order, so I had to use the self.method_added so I could redefine the method after the original was loaded. I think I have all the working parts for 3.0.7 and 3.1 (no tests, but the base case of swapping the name/version) but its all junk right now and I'm working to clean it up, then fork your project and send a pull request.
If you want to wait for tomorrow or Saturday, I can do that. If you'd rather hack on it now, here's the other monkey patches that I found to be needed:
module Rails
module Generators
module Migration
module ClassMethods
def migration_exists?(dirname, file_name) #:nodoc:
migration_lookup_at(dirname).grep(/#{file_name}_\d+.rb$/).first
end
def migration_lookup_at(dirname) #:nodoc:
Dir.glob("#{dirname}/*_[0-9]*.rb")
end
(then back out of the ends) ....
Your migration_template method needed to swap the name and number.
module ActiveRecord
class Migrator
def migrations
@migrations ||= begin
files = Dir["#{@migrations_path}/*_[0-9]*.rb"] #swapped order of search pattern
migrations = files.inject([]) do |klasses, file|
name, version = file.scan(/([_a-z0-9]*)_([0-9]+).rb/).first #swapped order of search pattern
raise IllegalMigrationNameError.new(file) unless version
version = version.to_i
if klasses.detect { |m| m.version == version }
raise DuplicateMigrationVersionError.new(version)
end
if klasses.detect { |m| m.name == name.camelize }
raise DuplicateMigrationNameError.new(name.camelize)
end
migration = MigrationProxy.new
migration.name = name.camelize
migration.version = version
migration.filename = file
klasses << migration
end
migrations = migrations.sort_by { |m| m.version }
down? ? migrations.reverse : migrations
end
end
... and back out of the ends.
I think that's it.
I'll take a look tomorrow. It looks pretty straight forward but I'm pretty tired.
Forked (the project, not the gist =)) and sent you a pull request. Let me know what you think, how it can be improved, etc.
merged. before I forget: I think the method_added comment got copy/pasted to a file which doesn't actually use method_added. I'll take that out later tonight or on the weekend, and then see if I have any other tweaks.
Oops. Yeah, I just figured since the other places needed it, it'd be needed there. In fact it's not, so nice catch.
yeah, it needs some actual tests at this point, but first I just want to be able to install it and get the base use case happening.
I didn't get this part:
You can get around that by using method added. While it generated the file correctly, when I ran the migrations, it did not run.
does that mean you got around it with method added, or you just tried? curious.