I'm probably misunderstanding something with the rails generators workflow, but after several days searching through the code and documentation, I can't find a solution for the problem.
I made a custom scaffold generator for adding some extra files and run the generated migration right after the scaffold files are created. With the same approach i'm trying to rollback the migration as the first thing when rails destroy my_scaffold command is executed in order to rollback before the migration file is deleted.
my custom generator code scaffold_meta.rb, wich runs the db:migrate command after the migration file is created. This is the working part.
require 'generators/resource/resource_generator'
module Rails
module Generators
class ScaffoldMetaGenerator < ResourceGenerator # :nodoc:
remove_hook_for :resource_controller
remove_class_option :actions
class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets"
class_option :stylesheet_engine, desc: "Engine for Stylesheets"
class_option :assets, type: :boolean
class_option :resource_route, type: :boolean
class_option :scaffold_stylesheet, type: :boolean
class_option :steps, type: :boolean, default: 'step'
def handle_skip
@options = @options.merge(stylesheets: false) unless options[:assets]
@options = @options.merge(stylesheet_engine: false) unless options[:stylesheets] && options[:scaffold_stylesheet]
end
hook_for :scaffold_controller, required: true
hook_for :assets do |assets|
invoke assets, [controller_name]
end
hook_for :stylesheet_engine do |stylesheet_engine|
if behavior == :invoke
invoke stylesheet_engine, [controller_name]
end
end
def mirate_if_invoke
if behavior == :invoke
say behavior.to_s + ' migrate', :green
rake("db:migrate --trace")
end
end
invoke 'step'
end
end
end
previous code ends up calling my custom model_generator.rb, which tries to rollback before deleting the migration file.
require 'rails/generators/model_helpers'
module Rails
module Generators
class ModelGenerator < Rails::Generators::NamedBase # :nodoc:
include Rails::Generators::ModelHelpers
def rollback_if_revoke
if self.behavior == :revoke
say behavior.to_s + ' rollback', :red
rake("db:rollback --trace")
end
end
argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
hook_for :orm, required: true, desc: "ORM to be invoked"
end
end
end
output of the generator with revoke behavior shows how rake db:rollback is suposedly called but has no effect.
$rails d scaffold_meta pez edad:integer nombre
Running via Spring preloader in process 8888
***revoke rollback
rake db:rollback --trace***
invoke active_record
remove db/migrate/20161013145014_create_pezs.rb
remove app/models/pez.rb
invoke rspec`
Any help would be very apreciated.
I encountered the same challenge in Rails 4.7.0.
I noticed that
rake db:rollback
worked when thebehavior == :invoke
but did nothing whenbehavior == :revoke
.Looking at the
rake
method source:The
run
method called in the block passed toin_root
is from theThor::Actions
module:The first line in the method,
return unless behavior == :invoke
short circuits the call to execute the originalrake 'db:rollback'
command.Railties also has an
Actions
module (Rails::Generators::Actions
) which seems to follow Thor'sinvoke
\revoke
logic. So I've concluded that it's best just not to try rollback when the generator is in the:revoke
state.I've ended up following the Rails convention to generate a migration file on
:invoke
, and destroy it on:revoke
and rely on the user to manually executerake db:migrate
orrake db:rollback
when needed.Hope that helps.