Call Task More Than Once in Rails 3 Generator

How to get generators call other generators in rails 3

In your generator, you can just call

generate "some:generator" # can be anything listed by 'rails g'

for example:

module MyGem
class InstallGenerator < Rails::Generators::Base

def run_other_generators
generate "jquery:install" # or whatever you want here
end

end
end

By the way, if you are working on Rails 3 gems, this question can also help out:

Rails 3 generators in gem

Fixing Rails generator issues: calling same generator twice no-ops and exits 0 without running 2nd generator

Turns out the problem lies in Thor - it will only read the first invoke statement in any generator. Found the solution in this answer to a question about rails 3 generators - turns out it hasn't changed since.

Quoting the original answer:

"There's a catch however: Probably due to Thors dependency management, this only works once per generator you want to call, meaning that a second invoke of the same generator will do nothing. This can be circumvented by using a statement like

Rails::Generators.invoke 'active_record:model', '...', behavior: behavior"

So replacing invoke with Rails::Generators.invoke totally did the trick.

Running other generator within a generator

You must define a hook_for the other generator in your generator class. The ScaffoldGenerator is probably the best example of this, as it has a hook for the scaffold_controller generator.

If you want to pass in arguments to your generator, it's probably better to use something like the hook_for examples further down in this file for assets and stylesheet engine.

Rails Gem: Running All Generators for given Namespace

Keep an "AllGenerator" class under Admin module. The generator will have to do the following :

  1. For each class under the namespace that is a generator class,
  2. get the namespace from classname.
  3. Call the invoke method with the namespace.

Something like this :

module Admin
module Generators
class AllGenerator < Rails::Generators::Base
def generator
Rails::Generators.lookup!
Admin::Generators.constants.each do |const|
generator_class = Admin::Generators.const_get(const)
next if self.class == generator_class
if generator_class < Rails::Generators::Base
namespace = generator_klass_to_namespace(generator_class)
invoke(namespace)
end
end
end
private
def generator_klass_to_namespace(klass)
namespace = Thor::Util.namespace_from_thor_class(klass)
return namespace.sub(/_generator$/, '').sub(/:generators:/, ':')
end
end

end
end

Here's the link to the gist with complete tested code

This way, running rails g admin:all would run every other generator directly under Admin::Generators .

How to invoke generators from code?

Solution appears to be pretty simple:

This code in controller

Rails::Generators.invoke("ead_document", [@document_type.table_name.classify, "--document_type_id=#{@document_type.id}"])

is the same as this in console

rails generate ead_document TechnicalOpinion --document_type_id=1

In case you want to use it outside a controller, you may also want to require it explicitely:

require 'rails/generators'


Related Topics



Leave a reply



Submit