How do I create a command line rails generator gem? - ruby-on-rails

I know how to create a rails generator gem which is called like:
rails g my_generator command
And I know how to create a thor gem which can be called like:
my_generator command
But I don't know how to create a rails generator that can be called using an executable. I have tried by creating a lib/my_generator/cli.rb file like:
require 'thor'
module Mang
class Cli < Thor
include ::Rails::Generators::Base
desc "install_gem", "install a gem"
def install_gem
gem 'thor', "0.18.1"
end
end
end
But I get the following error despite having added Rails as a dependency in my gemspec.
uninitialized constant Rails (NameError)

The fix was just a matter of including the rails/generators/actions module.
require 'thor'
require 'rails/generators'
require 'rails/generators/actions'
module Mang
class Cli < Thor
include Thor::Actions
include Rails::Generators::Actions
desc "install_gem", "install a gem"
def install_gem
gem 'thor', "0.18.1"
end
end
end

Related

How to install migration in Rails engine from other engine?

I have an engine, that has gem dependency. This gem has rake task to install migrations:
rake acts_as_taggable_on_engine:install:migrations
What is the proper way to install migration? When I run this command from host app or my engine I getting
Don't know how to build task
Add the gem dependency to you gemspec:
Gem::Specification.new do |s|
# ...
s.add_dependency 'acts-as-taggable-on', '~> 6.0'
# ...
end
Then require the gem in your engine:
# lib/my_engine/engine.rb
require 'acts-as-taggable-on'
module MyEngine
class Engine < ::Rails::Engine
isolate_namespace Chatty
end
end
ActsAsTaggableOn should be loaded through the main file which requires the engine as well unlike some gems where you require gemname/engine - and the file naming is not snake_case like most gems.
Then run bundle install and rake acts_as_taggable_on_engine:install:migrations in the folder of the dummy application (or the host).
max#MaxBook ~/p/c/t/dummy> rake acts_as_taggable_on_engine:install:migrations
Copied migration 20181030123059_acts_as_taggable_on_migration.acts_as_taggable_on_engine.rb from acts_as_taggable_on_engine
Copied migration 20181030123060_add_missing_unique_indices.acts_as_taggable_on_engine.rb from acts_as_taggable_on_engine
Copied migration 20181030123061_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb from acts_as_taggable_on_engine
Copied migration 20181030123062_add_missing_taggable_index.acts_as_taggable_on_engine.rb from acts_as_taggable_on_engine
Copied migration 20181030123063_change_collation_for_tag_names.acts_as_taggable_on_engine.rb from acts_as_taggable_on_engine
Copied migration 20181030123064_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb from acts_as_taggable_on_engine
I don't know why but invoking the command through bundler (bundle exec ...) does not work. This may give problems with RVM if you are using shims.
You can also create a generator for your engine that invokes the task:
# lib/generators/my_engine/install/install_generator.rb
module MyEngine
class InstallGenerator < Rails::Generators::Base
source_root File.expand_path('templates', __dir__)
desc "Installs MyEngine"
def copy_initializer
# template 'my_engine.rb', 'config/initializers/my_engine.rb'
rake "acts_as_taggable_on_engine:install:migrations"
end
end
end
Which you can then run with rails g my_engine:install.

How to use Thor::Shell::Basic in a Rails Generator?

I am writing a Rails 3.2 generator and would like to use Thor::Shell::Basic instance methods (e.g. ask or yes?) like they do in the official Rails guides on Application Templates.
module MyNamespace
class ScaffoldGenerator < Rails::Generators::Base
source_root File.expand_path('../templates', __FILE__)
if yes? "Install MyGem?"
gem 'my_gem'
end
run 'bundle install'
end
end
This will give me a NoMethodError: undefined method 'yes?' for MyNamespace::ScaffoldGenerator:Class.
I cannot figure out a clean way to make those instance methods available - I am already inheriting from Rails::Generators::Base.
Edit:
Ah, it probably has nothing to do with Thor... I get a warning:
[WARNING] Could not load generator "generators/my_namespace/scaffold/scaffold_generator"
Something is not set up correctly although I used the generator for generating generators...
Oh, yes, it does have to do something with Thor.
Do not let yourself get confused by the warning. You know that Rails::Generators uses Thor, so walk over to the Thor Wiki and check out how Thor tasks work.
The rails generator execution will call any method in your generator. So make sure that you organize your stuff into methods:
module MyNamespace
class ScaffoldGenerator < Rails::Generators::Base
source_root File.expand_path('../templates', __FILE__)
def install_my_gem
if yes? "Install MyGem?"
gem 'my_gem'
end
end
def bundle
run 'bundle install'
end
end
end
Be sure to put your generator into the right folder structure, e.g. lib/generators/my_namespace/scaffold_generator.rb.
Thanks for asking your question, dude!

Gem not working in rails project but in ruby file

When I run test.rb (see below) as a separate ruby file from within my rails project it works fine but when I wrap it as a module to be called from a controller it gives me:
LoadError (no such file to load -- eventmachine):1 in 'ModuleTest'
The gem is installed (sudo gem install event machine and bundle install) and added to the gem file (gem 'eventmachine').
Could someone please advice on what it is that I'm missing?
Separate file (called through: $ ruby lib/test.rb):
require 'rubygems'
require 'eventmachine'
require 'em-http'
require 'fiber'
def doStuff
end
doStuff
Module:
require 'eventmachine'
require 'em-http'
require 'fiber'
module ModuleTest
def doStuff
end
end
Controller:
require 'moduletest'
class MyController < ApplicationController
doStuff
end
Add
gem 'eventmachine'
Into your Gemfile. Then execute bundle install.
If you want to use a new gem in your rails project, you need to add it into Gemfile. To learn more, visit http://gembundler.com/

Rails 3 generators in gem

Might sound like a simple question, but I'm stumped.
I've created a gem that essentially contains a generator.
It contains the following structure:
lib
- generators
- my_generator
my_generator_generator.rb (see below)
- templates
my_template_files...
- my_generator.rb (empty file)
test
-test files
GemFile
etc..
However when I add this Gem to my gem file and run rails g, it's not listed. Is there any additional config that I need to do?
My generator roughly looks like this...
class MyGeneratorGenerator < Rails::Generators::NamedBase
source_root File.expand_path('../templates', __FILE__)
generator code....
end
The strange thing is, it works in Cygwin, but not in Ubuntu...
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/
If you use Railtie, you can define your generator wherever it could be using:
generators do
require "path/to/my_railtie_generator"
end
in Railtie class.

require other modules in the controller

gem install rubyoverflow
irb
> require 'rubyoverflow'
=> true
But:
require 'rubyoverflow'
include Rubyoverflow
class QuestionsController < ApplicationController
def question_by_tag
ruby_q = Questions.retrieve_by_tag('ruby')
Get error:
LoadError in
QuestionsController#question_by_tag no
such file to load -- rubyoverflow
Rails.root:
D:/artefacts/dev/projects/stack
app/controllers/questions_controller.rb:1:in
`'
This error occurred while loading the
following files: rubyoverflow
Is there any special rules to import moduled in the controller?
why do you use both require and include? include Rubyoverflow will be enough
UPD
For gem you should add it into your Gemfile (Rails 3.x) or config/environment.rb (Rails 2.x)
# Gemfile
gem "rubyoverflow"
# environment.rb
config.gem "rubyoverflow"
Then run bundle for Rails 3.x and rake gems:install for Rails 2.x

Resources