Search code examples
ruby-on-railsruby-on-rails-7

Overriding Scaffold Controller in Rails 7.1


Briefly, I want to override and/or add additional files when running rails generate scaffold MyModel name:string for example.

  1. [DONE] Override the views
  2. [????] Override the controller.rb
  3. [????] Add to the views such as destroy.turbo_stream.haml, _mymodel.html.haml

I've spent the afternoon reading documentation reading how to override templates with rails generators at https://guides.rubyonrails.org/generators.html#overriding-rails-generator-templates along with a slew of posts on how to over-ride various parts of controllers.

While I was able to override some of the views, I've yet been able find the path magic to override the controller.rb used during scaffold generation.

Per this, I should be able to add the controller file somewhere in lib/templates but nothing is working.

I wanted to add before_action :authenticate_user! and some other changes that I want to ensure are always in scaffolded controllers.

Any thoughts as to the specific location within railties ... per documentation it is this: https://github.com/rails/rails/blob/main/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt

But then where in lib/ does it go?

  • I've tried lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt
  • I've tried lib/templates/rails/generators/rails/scaffold_controller/templates/controller.rb.tt
  • I've tried lib/templates/controller.rb.tt
  • I've tried ... banging my head

I'd love some help. HELP!! :)

P.S. And if you know how to add additional views (e.g. destroy.turbo_stream.haml to the mix in the views along with _MODEL.html.haml I'd love to figure that out, too.


Solution

  • Override the views

    https://github.com/haml/haml-rails/tree/master/lib/generators/haml/scaffold/templates

    # lib/generators/haml/scaffold/templates/show.html.haml
    #             .--'    |                  |
    #             |    .--'     .------------'
    #             v    v        v
    lib/templates/haml/scaffold/show.html.haml
    
    $ bin/rails g scaffold Testing
    ...
    $ cat app/views/testings/show.html.haml
    hi haml
    

    Override the controller.rb

    Override default controller template from railties gem:

    # lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt
    #             .--------'     |                             |
    #             |     .--------'          .------------------'
    #             v     v                   v
    lib/templates/rails/scaffold_controller/controller.rb.tt
    

    Add to the views such as destroy.turbo_stream.haml.

    Generate a generator in rails namespace:

    $ bin/rails g generator rails/my_scaffold
    
    # lib/generators/rails/my_scaffold/my_scaffold_generator.rb
    
    class Rails::MyScaffoldGenerator < Rails::Generators::NamedBase
      # run default scaffold
      invoke "scaffold_controller"
    
      # add new stuff
      include Rails::Generators::ResourceHelpers
      source_root File.expand_path("templates", __dir__)
      def copy_view_files
        ["destroy.turbo_stream.haml"].each do |filename|
          template filename, File.join("app/views", controller_file_path, filename)
        end
      end
    end
    
    # lib/generators/rails/my_scaffold/templates/destroy.turbo_stream.haml.tt
    
    # TODO: make a template
    

    Change default scaffold controller generator:

    # config/application.rb
    
    config.generators do |g|
      g.scaffold_controller :my_scaffold
    end
    
    $ bin/rails g scaffold Testing   
    ...
         create    app/views/testings/destroy.turbo_stream.haml
    

    You could get a bit more granular if you want:

    # config/application.rb
    
    config.generators do |g|
      g.template_engine :my_scaffold
    end
    

    and then instead of invoking the whole scaffold just invoke "haml:scaffold" the rest is the same.


    This isn't the prettiest way of adding to the scaffold, because the scaffold log is nested under my_scaffold. If you want to add this generator to be invoked by the scaffold instead, you'll have to add a new hook:

    https://api.rubyonrails.org/classes/Rails/Generators/Base.html#method-c-hook_for

    For example, have a look at how jbuilder does it:
    https://github.com/rails/jbuilder/blob/v2.11.5/lib/jbuilder/railtie.rb#L29
    https://github.com/rails/jbuilder/tree/v2.11.5/lib/generators/rails