### Setup preload.rb for Rails Application Source: https://github.com/socketry/falcon-rails/blob/main/guides/getting-started/readme.md Creates the `preload.rb` file, which is responsible for loading the Rails application environment before worker processes are forked. This optimizes memory usage. ```ruby # frozen_string_literal: true require_relative "config/environment" ``` -------------------------------- ### Run Production Server with Falcon Source: https://github.com/socketry/falcon-rails/blob/main/guides/getting-started/readme.md Starts the Falcon production server using the configured `falcon.rb` file. Alternatively, the `falcon host` command can be used directly. ```bash bundle exec ./falcon.rb # Or: bundle exec falcon host ``` -------------------------------- ### Install Falcon-Rails Gem Source: https://github.com/socketry/falcon-rails/blob/main/context/getting-started.md Adds the Falcon Rails gem to your project's Gemfile. This is the initial step to integrate Falcon with your Rails application. ```bash bundle add falcon-rails ``` -------------------------------- ### Install Falcon Rails Gem Source: https://github.com/socketry/falcon-rails/blob/main/guides/getting-started/readme.md Adds the falcon-rails gem to your Rails application's Gemfile. It's recommended to remove other web servers like Puma after installation. ```bash bundle add falcon-rails bundle remove puma ``` -------------------------------- ### Serve Rails Application with Falcon Source: https://github.com/socketry/falcon-rails/blob/main/context/getting-started.md Starts your Rails application using the Falcon web server. This command is used to run your application in development or production environments. ```bash > bundle exec falcon serve ``` -------------------------------- ### Configure Falcon for Production Deployment Source: https://github.com/socketry/falcon-rails/blob/main/guides/getting-started/readme.md Sets up the `falcon.rb` configuration file for production deployments. It includes Rack environment setup, preloading the Rails application, and defining the network endpoint. ```ruby #!/usr/bin/env -S falcon-host # frozen_string_literal: true require "falcon/environment/rack" hostname = File.basename(__dir__) service hostname do include Falcon::Environment::Rack # This file will be loaded in the main process before forking. preload "preload.rb" # Default to port 3000 unless otherwise specified. port {ENV.fetch("PORT", 3000).to_i} # Default to HTTP/1.1 for compatibility with proxies: endpoint do Async::HTTP::Endpoint .parse("http://0.0.0.0:#{port}") .with(protocol: Async::HTTP::Protocol::HTTP11) end end ``` -------------------------------- ### Make falcon.rb Executable Source: https://github.com/socketry/falcon-rails/blob/main/guides/getting-started/readme.md Grants execute permissions to the `falcon.rb` configuration file, allowing it to be run directly as a script for starting the production server. ```bash chmod +x falcon.rb ``` -------------------------------- ### Install Development TLS Certificates Source: https://github.com/socketry/falcon-rails/blob/main/context/getting-started.md Installs local development TLS certificates required for running Falcon in development mode. This enables secure connections during local testing. ```bash > bundle exec bake localhost:install ``` -------------------------------- ### Start Rails Application with Falcon (HTTP) Source: https://github.com/socketry/falcon-rails/blob/main/guides/getting-started/readme.md Starts your Rails application with Falcon in development mode, explicitly binding to an HTTP endpoint. This is useful if you prefer not to use HTTPS during development. ```bash bundle exec falcon serve -b http://localhost:3000 ``` -------------------------------- ### Install Live::View JavaScript Packages Source: https://context7.com/socketry/falcon-rails/llms.txt Installs the necessary JavaScript packages for Live::View using `importmap`. This command pins the `@socketry/live` package for use in the application. ```bash # Install Live::View JavaScript packages bin/importmap pin @socketry/live ``` -------------------------------- ### Initialize Live::View Client Source: https://github.com/socketry/falcon-rails/blob/main/context/real-time-views.md Initializes the Live::View client by importing the Live class and starting the connection. This JavaScript code makes the Live connection globally available as `window.live`. ```javascript import {Live} from "@socketry/live" window.live = Live.start() ``` -------------------------------- ### Install Live::View JavaScript Packages Source: https://github.com/socketry/falcon-rails/blob/main/context/real-time-views.md Installs the necessary JavaScript packages for Live::View and morphdom using the importmap tool. This ensures the client-side components are available for real-time functionality. ```bash > bin/importmap pin @socketry/live Pinning "@socketry/live" to vendor/javascript/@socketry/live.js via download from https://ga.jspm.io/npm:@socketry/live@0.14.0/Live.js Pinning "morphdom" to vendor/javascript/morphdom.js via download from https://ga.jspm.io/npm:morphdom@2.7.7/dist/morphdom-esm.js ``` -------------------------------- ### Development Server with HTTPS Source: https://context7.com/socketry/falcon-rails/llms.txt Start the Falcon development server with automatic HTTPS using self-signed certificates. This involves an initial setup for TLS certificates and then starting the server. ```bash # Install development TLS certificates (one-time setup) bundle exec bake localhost:install # Start Falcon with HTTPS (default) bundle exec falcon serve # => Application available at https://localhost:9292 # Or start with HTTP on custom port bundle exec falcon serve -b http://localhost:3000 ``` -------------------------------- ### Start Rails Application with Falcon (HTTPS) Source: https://github.com/socketry/falcon-rails/blob/main/guides/getting-started/readme.md Launches your Rails application using the Falcon web server in development mode, defaulting to HTTPS. The application will be accessible at https://localhost:9292. ```bash bundle exec falcon serve ``` -------------------------------- ### Configure Worker Processes in falcon.rb Source: https://github.com/socketry/falcon-rails/blob/main/guides/getting-started/readme.md Demonstrates how to configure the number of worker processes for Falcon in the `falcon.rb` file. This setting is controlled by the `WEB_CONCURRENCY` environment variable, defaulting to 2. ```ruby # In your falcon.rb service hostname do include Falcon::Environment::Rack # Set the number of worker processes count ENV.fetch("WEB_CONCURRENCY", 2).to_i # ... rest of configuration end ``` -------------------------------- ### Initialize Live::View in JavaScript Source: https://context7.com/socketry/falcon-rails/llms.txt Initializes the Live::View library in the browser's JavaScript environment. This makes the `Live` object globally available for starting live views. ```javascript // app/javascript/live.js import { Live } from "@socketry/live" window.live = Live.start() ``` -------------------------------- ### Rails Routing for SSE Source: https://github.com/socketry/falcon-rails/blob/main/context/server-sent-events.md Configures the routes for the Server-Sent Events example in a Rails application. It maps GET requests to the `sse#index` action for the page displaying the JavaScript client and to the `sse#events` action for the SSE endpoint. ```ruby Rails.application.routes.draw do # SSE Example: get "sse/index" get "sse/events" end ``` -------------------------------- ### Install Falcon::Rails Gem Source: https://context7.com/socketry/falcon-rails/llms.txt Add the falcon-rails gem to your Rails application's Gemfile and optionally remove other web servers like Puma. ```bash # Add falcon-rails gem bundle add falcon-rails # Optionally remove Puma bundle remove puma ``` -------------------------------- ### Rails Routing Configuration for WebSockets Source: https://github.com/socketry/falcon-rails/blob/main/context/websockets.md Defines the necessary routes in `config/routes.rb` to handle WebSocket connections for a chat application. It maps GET requests to the index action and WebSocket connections to the connect action. ```ruby Rails.application.routes.draw do get "chat/index" connect "chat/connect" end ``` -------------------------------- ### Client-Side Fetch API for HTTP Streaming Source: https://github.com/socketry/falcon-rails/blob/main/guides/http-streaming/readme.md This JavaScript code demonstrates how to consume an HTTP stream on the client-side using the Fetch API and ReadableStream. It includes event listeners for starting and stopping the stream, displays streamed data in a terminal-like div, and uses an AbortController for stream cancellation. The code decodes the stream chunks using TextDecoder and handles stream completion or errors. ```javascript
``` -------------------------------- ### Rails Routing for HTTP Streaming Source: https://github.com/socketry/falcon-rails/blob/main/guides/http-streaming/readme.md This Ruby code snippet shows how to configure routes in a Rails application's `config/routes.rb` file to support HTTP streaming. It defines GET routes for 'streaming/index' to serve the page with the client-side streaming JavaScript, and 'streaming/stream' to act as the endpoint for the actual data stream. ```ruby Rails.application.routes.draw do # Streaming Example: get "streaming/index" # Page with streaming JavaScript get "streaming/stream" # HTTP streaming endpoint end ``` -------------------------------- ### Make Live.js Importable in Rails Views Source: https://github.com/socketry/falcon-rails/blob/main/context/real-time-views.md Configures the import map to make the local `live.js` file importable within Rails view templates. This allows easy inclusion of the Live::View client-side setup. ```ruby pin "live" ``` -------------------------------- ### Remove Puma Gem Source: https://github.com/socketry/falcon-rails/blob/main/context/getting-started.md Removes the Puma gem from your project. This is an optional step to ensure Falcon is the sole web server. ```bash bundle remove puma ``` -------------------------------- ### Client-side HTTP Stream Consumption Source: https://context7.com/socketry/falcon-rails/llms.txt Consume HTTP streams on the client-side using JavaScript's Fetch API and the ReadableStream interface. This example demonstrates reading and decoding streamed text data. ```javascript // Client-side: Consume HTTP stream fetch('/streaming/stream') .then(response => { const reader = response.body.getReader(); const decoder = new TextDecoder(); function readStream() { reader.read().then(({ done, value }) => { if (done) return; console.log(decoder.decode(value, { stream: true })); readStream(); }); } readStream(); }); ``` -------------------------------- ### Rails WebSocket Routing Source: https://context7.com/socketry/falcon-rails/llms.txt Configures WebSocket routes in a Rails application. It defines a standard GET route and a specific `connect` route for WebSocket connections. ```ruby # config/routes.rb Rails.application.routes.draw do get "chat/index" connect "chat/connect" # Rails 8 WebSocket route helper end ``` -------------------------------- ### Live::View WebSocket Controller in Ruby Source: https://context7.com/socketry/falcon-rails/llms.txt Sets up a Rails controller to handle Live::View WebSocket connections. It uses `Async::WebSocket::Adapters::Rails` and `Live::Page` to manage the live view lifecycle. ```ruby # app/controllers/clock_controller.rb require "async/websocket/adapters/rails" class ClockController < ApplicationController RESOLVER = Live::Resolver.allow(ClockTag) def index @tag = ClockTag.new("clock") end skip_before_action :verify_authenticity_token, only: :live def live self.response = Async::WebSocket::Adapters::Rails.open(request) do |connection| Live::Page.new(RESOLVER).run(connection) end end end ``` -------------------------------- ### Rails Routing for Live::View WebSocket Source: https://github.com/socketry/falcon-rails/blob/main/context/real-time-views.md Configures the routes in `config/routes.rb` to handle both the standard HTTP request for the clock index and the WebSocket connection for Live::View. Uses the `connect` helper for WebSocket routes. ```ruby Rails.application.routes.draw do # Live Clock Example: get "clock/index" connect "clock/live" end ``` -------------------------------- ### Rails Controller for Live::View WebSocket Source: https://github.com/socketry/falcon-rails/blob/main/guides/real-time-views/readme.md Handles incoming WebSocket connections for Live::View. It sets up a resolver to allow `ClockTag` and uses `Async::WebSocket::Adapters::Rails` to manage the connection lifecycle. ```ruby require "async/websocket/adapters/rails" class ClockController < ApplicationController RESOLVER = Live::Resolver.allow(ClockTag) def index @tag = ClockTag.new("clock") end skip_before_action :verify_authenticity_token, only: :live def live self.response = Async::WebSocket::Adapters::Rails.open(request) do |connection| Live::Page.new(RESOLVER).run(connection) end end end ``` -------------------------------- ### Live::View Clock Component Implementation Source: https://github.com/socketry/falcon-rails/blob/main/context/real-time-views.md Defines a `Live::View` class for a real-time clock. It uses `Async` for background updates, `self.update!` to trigger re-renders, and `forward_event` for handling interactions. The `render` method structures the HTML output. ```ruby require "live" class ClockTag < Live::View def initialize(...) super end def bind(page) @task ||= start_clock end def close if task = @task @task = nil task.stop end end def start_clock Async do while true sleep 1 self.update! end end def forward_event(name) "event.preventDefault(); live.forwardEvent(#JSON.dump(@id)}, event, {name: #{name.inspect}})" end render(builder) builder.tag(:div, class: "clock-container") do builder.tag(:h2) {builder.text("Live Clock")} builder.tag(:div, id: "clock", class: "clock-display") do builder.text(Time.now.strftime("%H:%M:%S")) end end end end ``` -------------------------------- ### Rails Controller for Live::View WebSocket Connection Source: https://github.com/socketry/falcon-rails/blob/main/context/real-time-views.md Sets up a Rails controller to handle Live::View connections. It whitelists the `ClockTag` using `Live::Resolver`, skips CSRF verification for the WebSocket endpoint, and uses `Async::WebSocket::Adapters::Rails` to manage the connection. ```ruby require "async/websocket/adapters/rails" class ClockController < ApplicationController RESOLVER = Live::Resolver.allow(ClockTag) def index @tag = ClockTag.new("clock") end skip_before_action :verify_authenticity_token, only: :live live self.response = Async::WebSocket::Adapters::Rails.open(request) do |connection| Live::Page.new(RESOLVER).run(connection) end end end ``` -------------------------------- ### Live::View Counter Component Implementation (Ruby) Source: https://context7.com/socketry/falcon-rails/llms.txt This Ruby code defines a CounterTag class that inherits from Live::View. It manages a counter's state, handles 'click' events for incrementing and decrementing, and updates the UI dynamically using `self.replace`. It also includes methods for forwarding events and rendering the component's HTML structure with buttons. ```ruby class CounterTag < Live::View def initialize(id, count: 0) super(id) @data["count"] = @data.fetch("count", count).to_i end def handle(event) case event[:type] when "click" case event.dig(:detail, :name) when "increment" then @data["count"] += 1 when "decrement" then @data["count"] -= 1 end update_counter end end def update_counter self.replace("#counter") do |builder| builder.tag(:div, id: "counter") { builder.text(@data["count"].to_s) } end end def forward_event(name) "event.preventDefault(); live.forwardEvent(#JSON.dump(@id)), event, {name: #{name.inspect}})" end def render(builder) builder.tag(:div, class: "counter") do builder.tag(:div, id: "counter") { builder.text(@data["count"].to_s) } builder.tag(:button, onclick: forward_event("decrement")) { builder.text("-") } builder.tag(:button, onclick: forward_event("increment")) { builder.text("+") } end end end ``` -------------------------------- ### Configure async-job Queues in Rails Initializer Source: https://github.com/socketry/falcon-rails/blob/main/context/job-processing.md This Ruby code configures async-job queues within a Rails initializer. It defines queues like 'default' (using Redis for persistence) and 'local' (using inline processing for higher throughput). It demonstrates how to specify different processors for enqueueing and dequeueing jobs. ```ruby require "async/job" require "async/job/processor/aggregate" require "async/job/processor/redis" require "async/job/processor/inline" Rails.application.configure do config.async_job.define_queue "default" do # Double-buffers incoming jobs to avoid submission latency: enqueue Async::Job::Processor::Aggregate dequeue Async::Job::Processor::Redis end config.async_job.define_queue "local" do dequeue Async::Job::Processor::Inline end end ``` -------------------------------- ### Configure Live::View Importmap Source: https://context7.com/socketry/falcon-rails/llms.txt Pins the 'live' JavaScript file in the Rails importmap configuration. This makes the Live::View JavaScript accessible to the application. ```ruby # config/importmap.rb pin "live" ``` -------------------------------- ### Production Configuration with falcon.rb Source: https://context7.com/socketry/falcon-rails/llms.txt Configure Falcon for production deployment using a `falcon.rb` file. This includes setting up worker processes, custom endpoints, and preloading the Rails environment for efficiency. ```ruby #!/usr/bin/env -S falcon-host # frozen_string_literal: true require "falcon/environment/rack" hostname = File.basename(__dir__) service hostname do include Falcon::Environment::Rack # Preload Rails before forking workers (reduces memory usage) preload "preload.rb" # Number of worker processes count ENV.fetch("WEB_CONCURRENCY", 2).to_i # Port configuration port { ENV.fetch("PORT", 3000).to_i } # HTTP/1.1 endpoint for proxy compatibility endpoint do Async::HTTP::Endpoint .parse("http://0.0.0.0:#{port}") .with(protocol: Async::HTTP::Protocol::HTTP11) end end ``` ```ruby # preload.rb - Load Rails before forking # frozen_string_literal: true require_relative "config/environment" ``` ```bash # Make executable and run chmod +x falcon.rb bundle exec ./falcon.rb # Or use: bundle exec falcon host ``` -------------------------------- ### Live::View Clock Component in Ruby Source: https://context7.com/socketry/falcon-rails/llms.txt Defines a Live::View component that displays the current time, updating every second. It uses `Async` for background tasks and `self.update!` to trigger re-renders. ```ruby # app/views/clock_tag.rb require "live" class ClockTag < Live::View def bind(page) @task ||= start_clock end def close @task&.stop @task = nil end def start_clock Async do loop do sleep 1 self.update! # Queue full re-render end end end def render(builder) builder.tag(:div, class: "clock-container") do builder.tag(:div, class: "clock-display") do builder.text(Time.now.strftime("%H:%M:%S")) end end end end ``` -------------------------------- ### Rails Server-Side WebSocket Implementation Source: https://github.com/socketry/falcon-rails/blob/main/context/websockets.md Implements a Rails controller to handle incoming WebSocket connections using the `async-websocket` adapter. It listens for messages, echoes them back to the client, and handles connection closures. Requires the `async-websocket` gem. ```ruby require "async/websocket/adapters/rails" class ChatController < ApplicationController def index # Render the page with WebSocket JavaScript end skip_before_action :verify_authenticity_token, only: :connect def connect self.response = Async::WebSocket::Adapters::Rails.open(request) do |connection| Sync do # Perpetually read incoming messages from client: while message = connection.read # Echo message back to client: response_data = { text: "Echo: #{JSON.parse(message.buffer)['text']}" } connection.send_text(response_data.to_json) connection.flush end rescue Protocol::WebSocket::ClosedError # Connection closed by client. end end end end ``` -------------------------------- ### Client-Side SSE with EventSource API Source: https://context7.com/socketry/falcon-rails/llms.txt Demonstrates how to consume Server-Sent Events on the client-side using the native EventSource API in JavaScript. It connects to the SSE endpoint and listens for different event types. ```javascript // Client-side: EventSource API const eventSource = new EventSource("/sse/events"); eventSource.addEventListener("open", () => console.log("Connected")); eventSource.addEventListener("message", (e) => console.log("Data:", e.data)); eventSource.addEventListener("user_joined", (e) => { const user = JSON.parse(e.data); console.log("User joined:", user); }); eventSource.addEventListener("error", () => console.log("Connection error")); ``` -------------------------------- ### Rails Controller for HTTP Streaming Source: https://github.com/socketry/falcon-rails/blob/main/guides/http-streaming/readme.md This Ruby code defines a Rails controller with two actions: 'index' to render the page with streaming JavaScript, and 'stream' which implements the server-side logic for HTTP streaming. It uses Rack::Response to send data progressively to the client. The 'stream' action writes lines of text with a delay, simulating a long-running task. ```ruby class StreamingController < ApplicationController def index # Render the page with streaming JavaScript end def stream body = proc do |stream| 10.downto(1) do |i| stream.write "#{i} bottles of beer on the wall\n" sleep 1 stream.write "#{i} bottles of beer\n" sleep 1 stream.write "Take one down, pass it around\n" sleep 1 stream.write "#{i - 1} bottles of beer on the wall\n" sleep 1 end end self.response = Rack::Response[200, {"content-type" => "text/plain"}, body] end end ``` -------------------------------- ### JavaScript Client for SSE Source: https://github.com/socketry/falcon-rails/blob/main/guides/server-sent-events/readme.md Consumes Server-Sent Events from the server. It establishes a connection using `EventSource`, listens for 'open', 'message', and 'error' events, and updates the UI accordingly. It also includes logic to limit the number of displayed messages. ```javascript
🔄 Connecting to event stream...
``` -------------------------------- ### Ruby Live::View for Interactive Counter Source: https://github.com/socketry/falcon-rails/blob/main/context/real-time-views.md Implements a Live::View component in Ruby to create an interactive counter. It handles user clicks to increment or decrement the count, updates the displayed count, and maintains the count state in `@data`. The `forward_event` method generates JavaScript for client-side event forwarding to the server. ```ruby class CounterTag < Live::View def initialize(count: 0) super # @data is persisted on the tag in `data-` attributes. @data["count"] = @data.fetch("count", count).to_i end def handle(event) case event[:type] when "click" case event.dig(:detail, :name) when "increment" @data["count"] += 1 when "decrement" @data["count"] -= 1 end update_counter end end def update_counter self.replace("#counter") do |builder| builder.tag(:div, id: "counter", class: "counter-display") do builder.text(@data["count"].to_s) end end end def forward_event(name) "event.preventDefault(); live.forwardEvent(#JSON.dump(@id)}, event, {name: #{name.inspect}})" end def render(builder) builder.tag(:div, class: "counter-container") do builder.tag(:h2) {builder.text("Live Counter")} builder.tag(:div, id: "counter", class: "counter-display") do builder.text(@count.to_s) end builder.tag(:div, class: "counter-buttons") do builder.tag(:button, onclick: forward_event("decrement")) do builder.text("-") end builder.tag(:button, onclick: forward_event("increment")) do builder.text("+") end end end end end ``` -------------------------------- ### Define Live::View for a Live Clock Source: https://github.com/socketry/falcon-rails/blob/main/guides/real-time-views/readme.md A Ruby class `ClockTag` that inherits from `Live::View` to manage a real-time clock. It uses `Async` for background updates and `self.update!` to trigger re-renders, displaying the current time. ```ruby require "live" class ClockTag < Live::View def initialize(...) super end def bind(page) @task ||= start_clock end def close if task = @task @task = nil task.stop end end def start_clock Async do while true sleep 1 self.update! end end def forward_event(name) "event.preventDefault(); live.forwardEvent(#JSON.dump(@id)), event, {name: #{name.inspect}}" end render(builder) builder.tag(:div, class: "clock-container") do builder.tag(:h2) {builder.text("Live Clock")} builder.tag(:div, id: "clock", class: "clock-display") do builder.text(Time.now.strftime("%H:%M:%S")) end end end end ``` -------------------------------- ### Ruby Live::View for User Interaction and DOM Updates Source: https://github.com/socketry/falcon-rails/blob/main/guides/real-time-views/readme.md This Ruby code defines a `CounterTag` Live::View component. It manages a counter's state in `@data`, handles 'click' events to increment or decrement the counter, and updates the DOM using `self.replace`. The `forward_event` method generates JavaScript to send events from the client to the server. ```ruby class CounterTag < Live::View def initialize(count: 0) super # @data is persisted on the tag in `data-` attributes. @data["count"] = @data.fetch("count", count).to_i end def handle(event) case event[:type] when "click" case event.dig(:detail, :name) when "increment" @data["count"] += 1 when "decrement" @data["count"] -= 1 end update_counter end end def update_counter self.replace("#counter") do |builder| builder.tag(:div, id: "counter", class: "counter-display") do builder.text(@data["count"].to_s) end end end def forward_event(name) "event.preventDefault(); live.forwardEvent(#JSON.dump(@id)}, event, {name: #{name.inspect}})" end render(builder) builder.tag(:div, class: "counter-container") do builder.tag(:h2) {builder.text("Live Counter")} builder.tag(:div, id: "counter", class: "counter-display") do builder.text(@count.to_s) end builder.tag(:div, class: "counter-buttons") do builder.tag(:button, onclick: forward_event("decrement")) do builder.text("-") end builder.tag(:button, onclick: forward_event("increment")) do builder.text("+") end end end end end ``` -------------------------------- ### Background Job Processing with Async::Job Source: https://context7.com/socketry/falcon-rails/llms.txt Implement background job processing in Rails using the `async-job` adapter for ActiveJob. This allows for asynchronous task execution, with options for Redis-backed queues or inline processing. ```ruby # config/initializers/async_job.rb require "async/job" require "async/job/processor/aggregate" require "async/job/processor/redis" require "async/job/processor/inline" Rails.application.configure do # Redis-backed queue for persistent job storage config.async_job.define_queue "default" do enqueue Async::Job::Processor::Aggregate # Double-buffers for low latency dequeue Async::Job::Processor::Redis end # Inline queue for high-throughput, non-critical jobs config.async_job.define_queue "local" do dequeue Async::Job::Processor::Inline end end ``` ```ruby # config/application.rb config.active_job.queue_adapter = :async_job ``` ```ruby # app/jobs/my_job.rb class MyJob < ApplicationJob queue_as "default" def perform(user_id, action) user = User.find(user_id) # Perform background work... end end # Enqueue job from anywhere MyJob.perform_later(user.id, "process_data") ``` -------------------------------- ### Rails View Template for Rendering Live::View Clock Source: https://github.com/socketry/falcon-rails/blob/main/context/real-time-views.md Renders the Live::View clock component within a Rails view. It includes the Live::View JavaScript and uses `raw @tag.to_html` to display the dynamically updating clock, along with basic styling. ```html

⏰ Live Clock Example

This clock updates every second using Live::View.

<%= javascript_import_module_tag "live" %>
<%= raw @tag.to_html %>
``` -------------------------------- ### HTTP Streaming with Rack::Response Source: https://context7.com/socketry/falcon-rails/llms.txt Stream data progressively to clients using chunked transfer encoding with Rack::Response. This is useful for large exports, progress indicators, or live logs. ```ruby # app/controllers/streaming_controller.rb class StreamingController < ApplicationController def stream body = proc do |stream| 10.downto(1) do |i| stream.write "#{i} bottles of beer on the wall\n" sleep 1 end end self.response = Rack::Response[200, {"content-type" => "text/plain"}, body] end # Stream NDJSON for large datasets def users body = proc do |stream| User.find_each(batch_size: 100) do |user| stream.write "#{user.to_json}\n" end end self.response = Rack::Response[200, {"content-type" => "application/x-ndjson"}, body] end end ``` -------------------------------- ### Client-Side JavaScript EventSource Implementation Source: https://github.com/socketry/falcon-rails/blob/main/context/server-sent-events.md Consumes the SSE stream from the server using the `EventSource` API. It handles connection opening, incoming messages, and errors, updating the UI accordingly. It also limits the number of displayed messages to prevent memory issues. ```javascript var eventSource = new EventSource("events"); var messageCount = 0; eventSource.addEventListener("open", function(event) { document.getElementById("status").innerHTML = "✅ Connected to event stream"; document.getElementById("status").className = "status success"; }); eventSource.addEventListener("message", function(event) { messageCount++; var container = document.createElement("div"); container.className = "terminal-line"; container.innerHTML = `#${messageCount} ${event.data}`; var history = document.querySelector("#history"); history.appendChild(container); history.scrollTop = history.scrollHeight; // Keep only last 20 messages to prevent memory issues if (history.children.length > 20) { history.removeChild(history.firstChild); } }); eventSource.addEventListener("error", function(event) { document.getElementById("status").innerHTML = "❌ Connection error - attempting to reconnect..."; document.getElementById("status").className = "status error"; }); ``` -------------------------------- ### Client-Side WebSocket JavaScript Implementation Source: https://github.com/socketry/falcon-rails/blob/main/context/websockets.md Provides JavaScript code to establish a WebSocket connection to a Rails server. It handles connection opening, message sending and receiving, error handling, and automatic reconnection. It converts the HTTP URL to a WebSocket URL and uses JSON for message formatting. ```html
``` -------------------------------- ### Render Live::View Component in ERB Source: https://context7.com/socketry/falcon-rails/llms.txt Embeds a Live::View component into an ERB template. It includes the Live::View JavaScript import and renders the component's HTML. ```erb <%= javascript_import_module_tag "live" %> <%= raw @tag.to_html %> ``` -------------------------------- ### JavaScript Client for Custom SSE Event Types Source: https://github.com/socketry/falcon-rails/blob/main/context/server-sent-events.md Handles custom event types sent from the server. It registers specific event listeners for 'user_joined' and 'message' events. Received data is parsed as JSON for further processing. ```javascript eventSource.addEventListener("user_joined", function(event) { var user = JSON.parse(event.data); // Handle user joined event }); eventSource.addEventListener("message", function(event) { var message = JSON.parse(event.data); // Handle message event }); ``` -------------------------------- ### WebSocket Communication in Ruby Source: https://context7.com/socketry/falcon-rails/llms.txt Implements full-duplex WebSocket communication using `async/websocket` for Rails. It handles incoming messages, parses JSON data, and echoes back a response. ```ruby # app/controllers/chat_controller.rb require "async/websocket/adapters/rails" class ChatController < ApplicationController skip_before_action :verify_authenticity_token, only: :connect def connect self.response = Async::WebSocket::Adapters::Rails.open(request) do |connection| Sync do while message = connection.read data = JSON.parse(message.buffer) response_data = { text: "Echo: #{data['text']}" } connection.send_text(response_data.to_json) connection.flush end rescue Protocol::WebSocket::ClosedError # Connection closed by client end end end end ``` -------------------------------- ### Define a Background Job Class in Rails Source: https://github.com/socketry/falcon-rails/blob/main/context/job-processing.md This Ruby code defines a background job class that inherits from ApplicationJob. It specifies the queue to use and contains the perform method where the background work is executed. This is a standard pattern for ActiveJob. ```ruby class MyJob < ApplicationJob # Specify the queue adapter per-job rather than globally: # queue_adapter :async_job queue_as "default" def perform # ... work ... end end ``` -------------------------------- ### Client-Side WebSocket API Source: https://context7.com/socketry/falcon-rails/llms.txt Connects to a WebSocket server using the browser's WebSocket API. It sends a message upon connection, handles incoming messages, and implements auto-reconnect on close. ```javascript // Client-side: WebSocket API const url = new URL('/chat/connect', window.location.href); url.protocol = url.protocol.replace('http', 'ws'); const server = new WebSocket(url.href); server.onopen = () => { server.send(JSON.stringify({ text: "Hello!" })); }; server.onmessage = (event) => { const message = JSON.parse(event.data); console.log("Received:", message.text); }; server.onclose = () => { setTimeout(() => connectToChatServer(url), 1000); // Auto-reconnect }; ``` -------------------------------- ### Server-Sent Events (SSE) in Ruby Source: https://context7.com/socketry/falcon-rails/llms.txt Implements Server-Sent Events to push real-time updates from the server to the client. It sets specific headers for the event stream and writes data periodically. Supports custom event types. ```ruby # app/controllers/sse_controller.rb class SseController < ApplicationController EVENT_STREAM_HEADERS = { "content-type" => "text/event-stream", "cache-control" => "no-cache", "connection" => "keep-alive" } def events body = proc do |stream| loop do stream.write("data: #{Time.now}\n\n") sleep 1 end end self.response = Rack::Response[200, EVENT_STREAM_HEADERS.dup, body] end # Custom event types def notifications body = proc do |stream| stream.write("event: user_joined\n") stream.write("data: #{user.to_json}\n\n") stream.write("event: message\n") stream.write("data: #{message.to_json}\n\n") end self.response = Rack::Response[200, EVENT_STREAM_HEADERS.dup, body] end end ``` -------------------------------- ### Set async-job as Default ActiveJob Adapter in Rails Source: https://github.com/socketry/falcon-rails/blob/main/context/job-processing.md This Ruby code snippet configures the ActiveJob queue adapter to use ':async_job' globally within a Rails application. This ensures that all ActiveJobs will be processed by the async-job system by default, though it can be overridden per-job. ```ruby # ... in the application configuration: config.active_job.queue_adapter = :async_job ``` -------------------------------- ### Rails Server-Sent Events with Custom Event Types Source: https://github.com/socketry/falcon-rails/blob/main/context/server-sent-events.md Demonstrates sending custom event types from the Rails server. Instead of the default 'message', it sends 'user_joined' and 'message' events, each with associated JSON data. This allows for more structured communication. ```ruby def events body = proc do |stream| # Send different event types stream.write("event: user_joined\n") stream.write("data: #{user.to_json}\n\n") stream.write("event: message\n") stream.write("data: #{message.to_json}\n\n") end self.response = Rack::Response[200, EVENT_STREAM_HEADERS.dup, body] end ``` -------------------------------- ### Rails Server-Sent Events Controller Source: https://github.com/socketry/falcon-rails/blob/main/context/server-sent-events.md Implements the server-side logic for SSE. It sets the required headers and streams data to the client. The `events` action continuously writes timestamped data to the stream, separated by double newlines. ```ruby class SseController < ApplicationController def index # Render the page with EventSource JavaScript end EVENT_STREAM_HEADERS = { "content-type" => "text/event-stream", "cache-control" => "no-cache", "connection" => "keep-alive" } def events body = proc do |stream| while true # Send timestamped data: stream.write("data: #{Time.now}\n\n") sleep 1 end end self.response = Rack::Response[200, EVENT_STREAM_HEADERS.dup, body] end end ```