We are on Rails 5 and have a flow we are trying to automate which involves the creation of several models. We made a custom generator that handles this, among other things.
The first step creates some files that we need, and works splendidly, however we began to chain things and noticed something quite odd:
If we run invoke model some_args
more than once, the second run does nothing, and exits with a 0 status code. We are somewhere in the Rack layer when this happens, however it seems that if we change invoke
to be another generator it will run fine.
If we wrap rails g model
in back-ticks it will run and execute the generator:
`rails g model`
Here is the code:
require "rails/generators"
require_relative "helpers/scaffold_generator_helper"
module ActiveCsv
class ModelScaffoldGenerator < Rails::Generators::NamedBase
desc <<~DESCRIPTION
This Generator takes a file containing a class inheriting from ActiveCsv
and produces 3 models and migrations (SourceModel, DestinationModel, FailedImportModel)
based on the configurations within the object
DESCRIPTION
def load_object_params
@helper = ActiveCSVScaffoldGeneratorHelper.new(name)
@params = @helper.extract_parameters
puts @params
end
def handle_source_model
case self.behavior
when :invoke
args = @helper.generate_source_model_options
created_files = invoke("model", args)
created_class_name = created_files[0][0][0]
created_model_path = created_files[0][2]
inject_into_class(created_model_path, created_class_name) do
" acts_as_copy_target\n"
end
when :revoke
invoke "model", [@helper.source_model_name], behavior: :revoke
end
end
def handle_destination_model
case self.behavior
when :invoke
args = @helper.generate_destination_model_options
created_files = invoke("model", args)
when :revoke
invoke "model", [@helper.destination_model_name], behavior: :revoke
end
end
end
end
Is it not possible to run the same generator multiple times inside of another 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.