修复 Rails 生成器问题:在没有 运行 第二个生成器的情况下调用同一个生成器两次无操作并退出 0

Fixing Rails generator issues: calling same generator twice no-ops and exits 0 without running 2nd generator

我们在 Rails 5 上有一个我们正在尝试自动化的流程,其中涉及创建多个模型。我们制作了一个自定义生成器来处理这个问题。

第一步创建了一些我们需要的文件,并且运行良好,但是我们开始链接事物并注意到一些非常奇怪的事情:

如果我们 运行 invoke model some_args 不止一次,第二个 运行 什么都不做,并以 0 状态码退出。当这种情况发生时,我们在机架层的某个地方,但是似乎如果我们将 invoke 更改为另一个生成器,它将 运行 正常。

如果我们用反引号包裹 rails g model 它将 运行 并执行生成器:

`rails g model`

代码如下:

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

难道不能运行同一个生成器在另一个生成器中多次使用吗?

原来问题出在 Thor - 它只会读取任何生成器中的第一个 invoke 语句。在 this answer 中找到了关于 rails 3 台发电机的问题的解决方案 - 事实证明它从那以后就没有改变过。

引用原回答:

“但是有一个问题:可能是由于 Thors 的依赖管理,这对每个你想调用的生成器只起作用一次,这意味着对同一个生成器的第二次调用将什么都不做。这可以通过使用语句来规避喜欢

Rails::Generators.invoke 'active_record:model', '...', behavior: behavior

所以用 Rails::Generators.invoke 替换 invoke 完全成功了。