0

我可能对 rails 生成器工作流程有误解,但是经过几天的代码和文档搜索后,我找不到问题的解决方案。

我制作了一个自定义脚手架生成器,用于添加一些额外的文件,并在创建脚手架文件后立即运行生成的迁移。使用相同的方法,当执行rails destroy my_scaffold命令以便在删除迁移文件之前回滚时,我尝试将迁移作为第一件事进行回滚。

我的自定义生成器代码scaffold_meta.rb,在创建迁移文件后运行 db:migrate 命令。这是工作部分。

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

之前的代码最终调用了我的自定义model_generator.rb,它会在删除迁移文件之前尝试回滚。

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

具有撤销行为的生成器的输出显示了如何调用rake db:rollback但没有效果。

$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`

任何帮助都会非常感激。

4

1 回答 1

0

我在 Rails 4.7.0 中遇到了同样的挑战。

我注意到rake db:rollback在 时有效,behavior == :invoke但在 时什么也没做behavior == :revoke

查看rake方法源:

  # GEMDIR/railties-4.2.7/lib/rails/generators/actions.rb:

  # Runs the supplied rake task
  #
  #   rake("db:migrate")
  #   rake("db:migrate", env: "production")
  #   rake("gems:install", sudo: true)
  def rake(command, options={})
    log :rake, command
    env  = options[:env] || ENV["RAILS_ENV"] || 'development'
    sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : ''
    in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", verbose: false) }
  end

run在传递给的块中调用的方法in_root来自Thor::Actions模块:

# GEMDIR/thor-0.19.1/lib/thor/actions.rb:

# Executes a command returning the contents of the command.
#
# ==== Parameters
# command<String>:: the command to be executed.
# config<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output. Specify :with
#                to append an executable to command execution.
#
# ==== Example
#
#   inside('vendor') do
#     run('ln -s ~/edge rails')
#   end
#
def run(command, config = {})
  return unless behavior == :invoke

  destination = relative_to_original_destination_root(destination_root, false)
  desc = "#{command} from #{destination.inspect}"

  if config[:with]
    desc = "#{File.basename(config[:with].to_s)} #{desc}"
    command = "#{config[:with]} #{command}"
  end

  say_status :run, desc, config.fetch(:verbose, true)

  unless options[:pretend]
    config[:capture] ? `#{command}` : system("#{command}")
  end
end

该方法的第一行,return unless behavior == :invoke将调用短路以执行原始rake 'db:rollback'命令。

Railties 还有一个Actions模块 ( Rails::Generators::Actions),它似乎遵循 Thor 的invoke\revoke逻辑。所以我得出的结论是,最好不要在生成器处于:revoke状态时尝试回滚。

我最终遵循 Rails 约定在 上生成迁移文件:invoke,并将其销毁:revoke并依赖用户手动执行rake db:migraterake db:rollback在需要时执行。

希望有帮助。

于 2016-10-20T12:28:36.113 回答