Class: Hibiki::Rails::Generators::ScaffoldControllerGenerator

Inherits:
Rails::Generators::NamedBase
  • Object
show all
Includes:
GeneratorHelpers, ScaffoldHelpers, ScaffoldModelInjection, ScaffoldParentInjection, ScaffoldParentNotices, ScaffoldPostInstall, ScaffoldViewHelpers, Rails::Generators::ResourceHelpers
Defined in:
lib/generators/hibiki/rails/scaffold_controller/scaffold_controller_generator.rb

Overview

A reactive CRUD resource for a model that already exists: the graph (a collection channel and a per-record one), a shared query object, a ReactiveForm, the views, and a scaffold-shaped controller that still serves the first paint and the non-JS path.

Everything is derived from the model's schema — column names, column types, belongs_to reflections — or from the same NAME field:type argument list Rails' own scaffold takes. Nothing here knows what a "book" is.

Constant Summary collapse

TEMPLATE_ROOT =
File.expand_path("templates", __dir__)

Constants included from ScaffoldParentNotices

Hibiki::Rails::Generators::ScaffoldParentNotices::PARENT_PIECES

Constants included from ScaffoldViewHelpers

Hibiki::Rails::Generators::ScaffoldViewHelpers::FIELD_TOKENS

Constants included from GeneratorHelpers

GeneratorHelpers::APPLICATION_HELPER, GeneratorHelpers::IMPORTMAP, GeneratorHelpers::INDEX_JS, GeneratorHelpers::REGISTER_FRAGMENT, GeneratorHelpers::SHIM

Instance Method Summary collapse

Instance Method Details

#add_routeObject

The route action directly rather than hook_for :resource_route. The hook resolves through Rails::Generators.find_by_namespace with OUR base_name ("hibiki"), which is a resolution risk for a one-line action — and calling it here also keeps hibiki:rails:scaffold from having to reason about whether Thor de-duplicated the invocation. Guarded, so re-running an overlay does not stack duplicate routes.



140
141
142
143
144
# File 'lib/generators/hibiki/rails/scaffold_controller/scaffold_controller_generator.rb', line 140

def add_route
  return if options[:skip_routes] || route_declared?

  route "resources :#{plural_name}", namespace: regular_class_path
end

#create_channelsObject



75
76
77
78
# File 'lib/generators/hibiki/rails/scaffold_controller/scaffold_controller_generator.rb', line 75

def create_channels
  template "channel.rb.tt", collection_channel_path
  template "member_channel.rb.tt", member_channel_path
end

#create_controllerObject



89
90
91
# File 'lib/generators/hibiki/rails/scaffold_controller/scaffold_controller_generator.rb', line 89

def create_controller
  template "controller.rb.tt", scaffold_controller_path
end

#create_formObject



85
86
87
# File 'lib/generators/hibiki/rails/scaffold_controller/scaffold_controller_generator.rb', line 85

def create_form
  template "form.rb.tt", form_path
end

#create_modelsObject



80
81
82
83
# File 'lib/generators/hibiki/rails/scaffold_controller/scaffold_controller_generator.rb', line 80

def create_models
  template "query.rb.tt", query_path
  template "row.rb.tt", row_path
end

#create_viewsObject



93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/generators/hibiki/rails/scaffold_controller/scaffold_controller_generator.rb', line 93

def create_views
  %w[index show new edit _form _list _controls _field_error _busy].each do |view|
    template "views/#{view}.html.erb.tt", view_path("#{view}.html.erb")
  end

  template "views/_row.html.erb.tt", view_path("_#{row_partial}.html.erb")
  template "views/_row_form.html.erb.tt", view_path("_#{row_form_partial}.html.erb")

  # Under --infinite-scroll the sentinel is inlined in _list and there
  # is no page control at all — not an empty one.
  template "views/_pagination.html.erb.tt", view_path("_pagination.html.erb") unless infinite?
end

#inject_model_supportObject

The model being scaffolded — one of two files this generator modifies that the app already owned.

It is not optional, and not only about the ping: the row partial prints an association's LABEL, and the show page hands that partial a live record — so without the delegate the show page raises on arrival. Once we are editing the model anyway, the ping belongs here too.

The alternative — printing it and hoping — fails SILENTLY: everything works in one tab, and cross-tab plus out-of-band writes simply never arrive.



117
118
119
120
121
122
123
# File 'lib/generators/hibiki/rails/scaffold_controller/scaffold_controller_generator.rb', line 117

def inject_model_support
  return manual_wiring(model_path, model_support) unless exists?(model_path)
  return if wired?(model_path, ping_marker)

  inject_into_model model_path, class_name, model_support
  announce_model_change
end

#inject_parent_supportObject

The other one: the model a belongs_to points AT, which Rails' own scaffold never touches. It owes this resource two things it cannot write for itself — the has_many half of the association, and a ping, because a row prints the parent's label rather than its id. Both are derived from the reflection; see ScaffoldParentInjection.



130
131
132
# File 'lib/generators/hibiki/rails/scaffold_controller/scaffold_controller_generator.rb', line 130

def inject_parent_support
  inject_parent_models
end

#post_installObject



146
147
148
# File 'lib/generators/hibiki/rails/scaffold_controller/scaffold_controller_generator.rb', line 146

def post_install
  post_install_notices
end

#resolve_schemaObject

Resolving the schema first means a missing model or an unmigrated table aborts before anything is written, rather than half-way through.



67
68
69
70
71
72
73
# File 'lib/generators/hibiki/rails/scaffold_controller/scaffold_controller_generator.rb', line 67

def resolve_schema
  schema
  # Captured BEFORE anything is written, so post_install can tell which
  # app/* directories are new — Rails computes autoload paths from that
  # glob at boot, and a new one needs a restart.
  @new_app_dirs = %w[app/forms app/channels app/models app/views].reject { exists?(it) }
end