Reputation: 23
Briefly, I want to override and/or add additional files when running rails generate scaffold MyModel name:string
for example.
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?
lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt
lib/templates/rails/generators/rails/scaffold_controller/templates/controller.rb.tt
lib/templates/controller.rb.tt
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.
Upvotes: 1
Views: 477
Reputation: 30101
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
Upvotes: 2
Reputation: 23
For sake of adding some more texture to answer from Alex which 100% nailed my questions.
I wanted to added a partial view such as app/views/my_models/_my_model.html
which is populated with the model attributes and values.
Out of the box, the above example from Alex ended up crapping out till I stumbled upon https://garrettdimon.com/journal/posts/creating-custom-rails-generators, see Figure 13 for specifics.
This resulted in some minor tweaks, or:
# lib/generators/rails/my_scaffold/my_scaffold_generator.rb
class Rails::MyScaffoldGenerator < Rails::Generators::NamedBase
# run default scaffold
invoke 'scaffold_controller'
argument :attributes, type: :array, default: [],
banner: "field[:type][:index] field[:type][:index]"
# 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
['partial.html.haml'].each do |filename|
template filename, File.join('app/views', controller_file_path, "_#{singular_table_name}.html.haml")
end
end
end
More specifically, two things I added are:
argument :attributes, type: :array, default: [],
banner: "field[:type][:index] field[:type][:index]"
which ensures you can access model attributes in the template.
['partial.html.haml'].each do |filename|
template filename, File.join('app/views', controller_file_path, "_#{singular_table_name}.html.haml")
end
adds a partial and renames it to the singular model name
And then I added to my generator templates:
# lib/generators/rails/my_scaffold/templates/partial.html.haml.tt
.container
<%- attributes.each do |attribute| -%>
%p
%b <%= attribute.name.humanize %>:
=<%= singular_table_name %>.<%= attribute.name %>
<%- end -%>
= link_to 'Edit', edit_<%= singular_table_name %>_path(<%= singular_table_name %>), class: 'btn btn-secondary m-1'
Note, I did not find the .tt
entirely necessary since I'm using haml
vs erb
as tt
is itself a variant of tt
, or so I understand.
And that, coupled to Alex's answer above ensures
Upvotes: 1