10

I am simply trying to create a plugin migration generator without any parameters, like : $rails generate yaffle and this should copy the migration file (lib/generators/yaffle/template/create_yaffle.rb) to db/migrate/[timestamp]_create_yaffle.rb.

  1. The problem I am facing here is, its copying, but without timestamp.
  2. Also, when I run $rails generate yaffle it gives me a message that arguments are not provided, it expects to be in this format rails generate yaffle NAME [options]. I dont want to have any options/arguments, it should just be rails generate yaffle.

What should I do?

I followed the generator used in acts_as_commentable , it looks pretty simple, but I don't know where to modify these settings... can anybody help?

Generator Code:

require 'rails/generators'
require 'rails/generators/migration'

class ThumbitGenerator  Rails::Generators::NamedBase
  source_root File.expand_path('../templates', __FILE__)

  def self.next_migration_number(path)
    Time.now.utc.strftime("%Y%m%d%H%M%S")
  end

  def create_model_file
    template "like.rb", "app/models/like.rb"
    template "liking.rb", "app/models/liking.rb"
    template "create_likes.rb", "db/migrate/create_likes.rb"
    template "create_likings.rb", "db/migrate/create_likings.rb"
  end

end
Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307
Madhusudhan
  • 8,374
  • 12
  • 47
  • 68

3 Answers3

22

Ok, I found the answer...

  1. I was using Rails::Generators::NamedBase instead of Rails::Generators::Base in my generator file! When you use NamedBase, it always expects an argument to be passed (which is the name of initializer)

    Explanation : guides.rubyonrails.org/generators

  2. And I was using template method instead of migration_template because of which migration files din't produce any migration number

    Explanation: Rails::Generators::Migration.migration_template

So finally, this worked!

require 'rails/generators'
require 'rails/generators/migration'

class ThumbitGenerator < Rails::Generators::Base
  include Rails::Generators::Migration
  source_root File.expand_path('../templates', __FILE__)

  def self.next_migration_number(path)
    Time.now.utc.strftime("%Y%m%d%H%M%S")
  end

  def create_model_file
    template "like.rb", "app/models/like.rb"
    template "liking.rb", "app/models/liking.rb"
    migration_template "create_likes.rb", "db/migrate/create_likes.rb"
    migration_template "create_likings.rb", "db/migrate/create_likings.rb"
  end
end
Madhusudhan
  • 8,374
  • 12
  • 47
  • 68
  • When I do this with multiple migrations and run rake db:migrate I get: Multiple migrations have the version number 20110413160337, which makes sense because both migrations are created with the same timestamp. Did you run across this? – Mike Farmer Apr 13 '11 at 16:05
  • 2
    @Mike Farmer: Append `%6N` to the strftime format string to get the microseconds and you should be good to go. Like this: https://gist.github.com/1110373 – davemyron Jul 27 '11 at 21:09
  • 4
    You can `require 'rails/generators/active_record'` and then use `ActiveRecord::Generators::Base.next_migration_number(path)` for next_migration_number – NARKOZ Dec 21 '12 at 14:44
  • guys is it possible if I want to use something like rails generate yaffle:install? Thanks – Moh Oct 30 '15 at 11:11
  • @NARKOZ that migration_template will create duplicate migration version. – seoyoochan Feb 11 '16 at 13:25
3

A small polish on the solution - to save yourself the hassle of defining the timestamp for the migration and future proof your generator in case Rails core team decides to use another way of stamping (e.g. SHA hashes truncated to 10 characters), you can require 'rails/generators/active_record' and extend ActiveRecord::Generators::Migration like this:

require 'rails/generators'
require 'rails/generators/migration'
require 'rails/generators/active_record'

class ThumbitGenerator < Rails::Generators::Base
  include Rails::Generators::Migration
  extend ActiveRecord::Generators::Migration

  source_root File.expand_path('../templates', __FILE__)

  def create_model_file
    template "like.rb", "app/models/like.rb"
    template "liking.rb", "app/models/liking.rb"
    migration_template "create_likes.rb", "db/migrate/create_likes.rb"
    migration_template "create_likings.rb", "db/migrate/create_likings.rb"
  end
end

UPDATE In Rails 4 ActiveRecord::Generators::Migration is no longer a module, so use instead:

require 'rails/generators'
require 'rails/generators/migration'
require 'rails/generators/active_record'

class ThumbitGenerator < Rails::Generators::Base
  include Rails::Generators::Migration
  # Implement the required interface for Rails::Generators::Migration
  def self.next_migration_number(dirname)
    ActiveRecord::Generators::Base.next_migration_number(dirname)
  end

  source_root File.expand_path('../templates', __FILE__)

  def create_model_file
    template "like.rb", "app/models/like.rb"
    template "liking.rb", "app/models/liking.rb"
    migration_template "create_likes.rb", "db/migrate/create_likes.rb"
    migration_template "create_likings.rb", "db/migrate/create_likings.rb"
  end
end
1

you can simply inherit from ActiveRecord::Generators::Base and everything will work

montrealmike
  • 11,433
  • 10
  • 64
  • 86