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
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 3 generators in gem
This took a little bit for me to figure out, but I've run into the same problem. Here is how I fixed it.
Tree structure looks like this:
lib
- generators
- gemname
install_generator.rb
- templates
(template files)
Here's the code for install_generator.rb
#lib/generators/gemname/install_generator.rb
require 'rails/generators'
module Gemname
class InstallGenerator < Rails::Generators::Base
desc "Some description of my generator here"
# Commandline options can be defined here using Thor-like options:
class_option :my_opt, :type => :boolean, :default => false, :desc => "My Option"
# I can later access that option using:
# options[:my_opt]
def self.source_root
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
end
# Generator Code. Remember this is just suped-up Thor so methods are executed in order
end
end
When I run
rails g
I see:
Gemname
gemname:install
Some other things you may need to setup:
#lib/gemname.rb
module Gemname
require 'gemname/engine' if defined?(Rails)
# any additional requires
end
and
#/lib/gemname/engine.rb
require 'rails'
module Gemname
class Engine < Rails::Engine
end
end
Some good references I've found on this are:
- http://textmate.rubyforge.org/thor/Thor.html (take a look at the modules, especially Thor::Actions)
- http://api.rubyonrails.org/classes/Rails/Generators/Base.html
- http://api.rubyonrails.org/classes/Rails/Generators/Actions.html
- https://github.com/wycats/thor/blob/master/README.md
- http://www.themodestrubyist.com/2010/03/16/rails-3-plugins---part-3---rake-tasks-generators-initializers-oh-my/
Ruby on Rails Custom Generators with multiple sub generators
What rmlockerd explained only half answered my question, Here's what worked:
I created the custom generators using rails g generator g1
and rails g generator g2
and organized them into the following directory structure:
# directory: /lib/generators
λ tree
.
└── gorking_generators
├── g1
│ ├── g1_generator.rb
│ ├── templates
│ └── USAGE
└── g2
├── g2_generator.rb
├── templates
└── USAGE
The content of the files are as follows:
# file: g1_generator.rb
module GorkingGenerators
module Generators
class G1Generator < Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
end
end
end
# file: g2_generator.rb
module GorkingGenerators
module Generators
class G2Generator < Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
end
end
end
After this, I am able to see the generators in place when using rails g
:
GorkingGenerators:
gorking_generators:g1
gorking_generators:g2
I can then use them using:
rails g gorking_generators:g1
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.
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'
Rails Gem: Running All Generators for given Namespace
Keep an "AllGenerator" class under Admin module. The generator will have to do the following :
- For each class under the namespace that is a generator class,
- get the namespace from classname.
- 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
.
Related Topics
Refactoring Activerecord Models with a Base Class Versus a Base Module
Display Base64 Encoded Image in Rails
Adding Username to Devise Rails 4
Rvm VS Native Installation of Ruby
Dealing with Large CSV Files (20G) in Ruby
How to Find Best Matching Element in Array of Numbers
How to Pass an Argument When Calling a View File
Rails Two-Legged Oauth Provider
How to Integrate Hoptoad with Delayedjob and Daemonspawn
Override the Protect_From_Forgery Strategy in a Controller
Remove Rails Model After Migration
Ruby: How to Calculate a Path Relative to Another One