Class: Silas::Generators::ChannelGenerator
- Inherits:
-
Rails::Generators::NamedBase
- Object
- Rails::Generators::NamedBase
- Silas::Generators::ChannelGenerator
- Defined in:
- lib/generators/silas/channel/channel_generator.rb
Overview
rails g silas:channel whatsapp
A channel is two halves that must agree on one name, and hand-rolling them is where the mistakes live: inbound needs signature verification and a stable thread key, outbound needs the approval link to reach an operator. This scaffolds both, wired together, with the security decisions already made.
Instance Method Summary collapse
- #add_route ⇒ Object
-
#create_channel ⇒ Object
Templates are .rb.tt (Rails' own convention): the .tt keeps ERB-bearing files out of the linter and off Zeitwerk's radar.
-
#create_controller ⇒ Object
The webhook lives in the HOST app, not the engine: only the host knows the vendor's signature scheme and payload shape.
- #show_next_steps ⇒ Object
-
#validate_name ⇒ Object
Channel identity is the filename (app/agent/channels/whatsapp.rb -> Agent::Channels::Whatsapp), and Registry#channels resolves it with
camelize.
Instance Method Details
#add_route ⇒ Object
45 46 47 |
# File 'lib/generators/silas/channel/channel_generator.rb', line 45 def add_route route %(post "/agent/channels/#{file_name}", to: "agent/channels/#{file_name}#create") end |
#create_channel ⇒ Object
Templates are .rb.tt (Rails' own convention): the .tt keeps ERB-bearing files out of the linter and off Zeitwerk's radar.
34 35 36 |
# File 'lib/generators/silas/channel/channel_generator.rb', line 34 def create_channel template "channel.rb.tt", "app/agent/channels/#{file_name}.rb" end |
#create_controller ⇒ Object
The webhook lives in the HOST app, not the engine: only the host knows the vendor's signature scheme and payload shape. The engine ships routes for Slack alone because it also ships Slack's verification.
41 42 43 |
# File 'lib/generators/silas/channel/channel_generator.rb', line 41 def create_controller template "controller.rb.tt", "app/controllers/agent/channels/#{file_name}_controller.rb" end |
#show_next_steps ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/generators/silas/channel/channel_generator.rb', line 49 def show_next_steps say <<~MSG, :green Channel "#{file_name}" scaffolded: app/agent/channels/#{file_name}.rb (outbound: answers + approvals) app/controllers/agent/channels/#{file_name}_controller.rb (inbound: webhook) config/routes.rb POST /agent/channels/#{file_name} Next: 1. Set the signing secret: bin/rails credentials:edit -> silas: #{file_name}: signing_secret: ... 2. Fill in the three TODOs — the vendor's signature scheme, how a message maps to a thread key, and how to post a message back. 3. Point the vendor's webhook at https://<your-host>/agent/channels/#{file_name} 4. Restart: app/agent/ registers at boot. Full contract and a worked example: docs/channels.md MSG end |
#validate_name ⇒ Object
Channel identity is the filename (app/agent/channels/whatsapp.rb ->
Agent::Channels::Whatsapp), and Registry#channels resolves it with
camelize. A filename that isn't a snake_case identifier produces a
constant Zeitwerk can't define, and the channel then fails at boot
rather than here — so refuse it here, where the message is useful.
(Rails' usual normalisation still applies first: MsTeams and
ms_teams both land on ms_teams.)
24 25 26 27 28 29 30 |
# File 'lib/generators/silas/channel/channel_generator.rb', line 24 def validate_name return if file_name.match?(/\A[a-z_][a-z0-9_]*\z/) raise Thor::Error, "#{file_name.inspect} is not a valid channel name — " \ "it must be lowercase words separated by underscores, " \ "starting with a letter (e.g. whatsapp, ms_teams)." end |