# Terminal
bin/rails action_text:install
bin/rails g model post title
bin/rails g stimulus search
bin/rails g stimulus search-active
# models/post.rb
class Post < ApplicationRecord
has_rich_text :content
end
# welcome_controller.rb
class WelcomeController < ApplicationController
def index
@posts = params[:query] ? Post.where("title like ?", "%#{params[:query]}%") : []
respond_to do |format|
format.html {}
format.turbo_stream {
render turbo_stream: turbo_stream.replace("results", partial: "welcome/results")
}
end
end
def show
@post = Post.find(params[:id])
render turbo_stream: turbo_stream.replace("show_content", partial: "welcome/show")
end
end
# javascript/controllers/search_controller.js
import { Controller } from "@hotwired/stimulus"
// Connects to data-controller="search"
export default class extends Controller {
connect() {
this.element.setAttribute("data-action", "keyup->search#search")
}
search() {
let params = new URLSearchParams()
params.append("query", this.element.value)
fetch(`/?${params}`, {
method: "GET",
headers: {
Accept: "text/vnd.turbo-stream.html"
}
})
.then(r => r.text())
.then(html => Turbo.renderStreamMessage(html))
}
}
# javascript/controllers/search_active_controller.js
import { Controller } from "@hotwired/stimulus"
import { List } from "immutable"
// Connects to data-controller="search-active"
export default class extends Controller {
connect() {
this.element.setAttribute("data-action", "click->search-active#clicked")
}
clicked() {
let links = document.querySelectorAll("#results a.active")
Array.from(links).forEach(link => {
link.classList.remove("active")
})
this.element.classList.add("active")
}
}
# views/welcome/index.html.erb
<div class="row">
<div class="col-4">
<%= form_with url: root_path do |f| %>
<%= f.text_field :query, class: "form-control", "data-controller": :search %>
<% end %>
<%= render "welcome/results" %>
</div>
<div class="col-8">
<%= turbo_frame_tag :show_content %>
</div>
</div>
# views/welcome/_results.html.erb
<%= turbo_frame_tag :results do %>
<div class="list-group mt-3">
<% @posts.each do |post| %>
<%= link_to post.title,
welcome_path(post),
class: "list-group-item list-group-item-action",
"data-controller": "search-active" %>
<% end %>
</div>
<% end %>
# views/welcome/_show.html.erb
<%= turbo_frame_tag :show_content do %>
<h1><%= @post.title %></h1>
<%= @post.content %>
<% end %>
# config/routes.rb
Rails.application.routes.draw do
root to: 'welcome#index'
resources :welcome, only: :show
end