Ruby on Rails 7: Hotwire lae Turbo samrap Aepplikheishan Riaethaim
Khumue sombun khong Hotwire lae Turbo nai Rails 7. Sang aepplikheishan riaethaim doi mai tong khian JavaScript duai Turbo Drive, Frames lae Streams.

Rails 7 pathiwat kan phatthana web doi kanruam Hotwire pen khakamnot. Stack ni thamhai samartriang sang aepplikheishan thi mi khwam riaethaim sung doi mai tong khian khot JavaScript thi kahamnot eng mae sak brrthad nueng. Turbo Drive, Turbo Frames lae Turbo Streams thaenthi withikan SPA daengdoem duai pratchya "HTML phan sai".
Hotwire lot khwam sapson khong frontend yang mak. Mai champen tong chai React rue Vue samrap inthoerefet thi mi kan toptoep: soewoe song HTML thi phrom chai lae Turbo chatkan kap kapnhat DOM doi atonmat.
Khaojai Sathapattayakam Hotwire
Hotwire prakop duai sam thekhnoloyi thi soem kan pen thanglueak tham ngan ruam kan phue mop prasopkan phuchai thi rapruen doi mai mi khwam sapson thi thammada khong framework JavaScript.
Turbo Drive reng khwam reo nai kan naewithang doi kan rap klik linkhae lae kan song baep. Thaen thi cha lotphaena thang mot, cha mi phiang nueaha khong <body> thuk thaenthi, doi rak sa boribot khong JavaScript lae CSS wai.
Turbo Frames baeng phaena pen suan thi pen itsara. Tae la frame samat kapnhat idyaek, thamhai samat mi kan toptoep bep jaomung doi mai kra thop suan thi luea khong phaena.
Turbo Streams het hai samat kapnhat raiaethaim phan WebSocket rue pen kan toptoep HTTP request. Paet kan kra tham CRUD mi hai samrap kan chatkan DOM baep prakat.
# Gemfile
# Installing Turbo Rails (included by default in Rails 7+)
gem 'turbo-rails'Samrap porachek thi mi yu laew, kan tittang tong kan phiang kham sang diaw.
# installation.sh
# Installing Turbo in an existing Rails project
rails turbo:install
# Verify the JavaScript import is present
cat app/javascript/application.js
# Should contain: import "@hotwired/turbo-rails"Kan Kamnot Kha Roemton Turbo Drive
Turbo Drive thuek poet chai pen kha khamnot nai Rails 7. Kan naewithang thang mot cha pen "turbo" doi atonmat doi mai tong mi kan kamnot kha phoem. Phruettikam samat prap taeng dai thang atthribut data.
<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
<head>
<meta name="turbo-cache-control" content="no-preview">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
</head>
<body>
<!-- Progress bar during navigation -->
<div class="turbo-progress-bar"></div>
<%= yield %>
</body>
</html>Turbo Drive samat pit kan chai bon link rue baep thi chapho mue champen.
<!-- app/views/pages/examples.html.erb -->
<!-- Link with Turbo enabled (default) -->
<%= link_to "Dashboard", dashboard_path %>
<!-- Disable Turbo for a specific link -->
<%= link_to "Download PDF", export_path, data: { turbo: false } %>
<!-- Disable Turbo for a form (file upload for example) -->
<%= form_with model: @document, data: { turbo: false } do |f| %>
<%= f.file_field :attachment %>
<%= f.submit "Upload" %>
<% end %>
<!-- Turbo with confirmation -->
<%= link_to "Delete", item_path(@item),
data: { turbo_method: :delete, turbo_confirm: "Are you sure?" } %>Turbo Drive khaet phaena thi yiam laew. Atthribut data-turbo-track="reload" bon asset bangkhap kan lot mai thang mot tha fai CSS/JS mi kan plianplaeng.
Turbo Frames samrap Kapnhat Baep Jaomung
Turbo Frames kahamnot son khong phaena thi kapnhat pen itsara. Tae la frame mi tuarabubang thi mi ekkalak lae toptoep phiang kap khamtop thi mi frame thi trongkan.
<!-- app/views/messages/index.html.erb -->
<h1>Messages</h1>
<!-- Frame for the message list -->
<turbo-frame id="messages_list">
<div id="messages">
<%= render @messages %>
</div>
<%= link_to "Load more", messages_path(page: @next_page) %>
</turbo-frame>
<!-- Frame for the creation form -->
<turbo-frame id="new_message">
<%= render "form", message: Message.new %>
</turbo-frame>Khamtop chak soewoe tong mi frame thi mi tuarabubang diaw kan phue hai kan kapnhat tham ngan.
<!-- app/views/messages/_message.html.erb -->
<!-- Partial for an individual message -->
<turbo-frame id="<%= dom_id(message) %>">
<div class="message">
<p><%= message.content %></p>
<span class="metadata">
By <%= message.author.name %> - <%= time_ago_in_words(message.created_at) %>
</span>
<!-- These links stay within the frame -->
<%= link_to "Edit", edit_message_path(message) %>
<%= button_to "Delete", message_path(message), method: :delete %>
</div>
</turbo-frame>Lazy Loading kap Turbo Frames
Frame samat lot nueaha baep asinkronat doi chai atthribut src. Nueaha roemton cha saadaeng nai rawang kan lot.
<!-- app/views/dashboard/show.html.erb -->
<h1>Dashboard</h1>
<!-- Statistics loaded asynchronously -->
<turbo-frame id="stats" src="<%= dashboard_stats_path %>">
<div class="loading-placeholder">
<p>Loading statistics...</p>
</div>
</turbo-frame>
<!-- Notifications loaded when visible (lazy loading) -->
<turbo-frame id="notifications"
src="<%= notifications_path %>"
loading="lazy">
<p>Loading notifications...</p>
</turbo-frame>
<!-- Recent activity with periodic refresh -->
<turbo-frame id="recent_activity"
src="<%= activity_path %>"
data-controller="auto-refresh"
data-auto-refresh-interval-value="30000">
<%= render "activity/placeholder" %>
</turbo-frame>Khonthrolen toptoep kap view thi mi phiang frame thi rong kho.
# app/controllers/dashboard_controller.rb
class DashboardController < ApplicationController
def stats
@user_count = User.count
@message_count = Message.count
@active_today = User.where("last_seen_at > ?", 24.hours.ago).count
# Partial rendering for the frame
render partial: "dashboard/stats"
end
end<!-- app/views/dashboard/_stats.html.erb -->
<turbo-frame id="stats">
<div class="stats-grid">
<div class="stat-card">
<h3><%= @user_count %></h3>
<p>Users</p>
</div>
<div class="stat-card">
<h3><%= @message_count %></h3>
<p>Messages</p>
</div>
<div class="stat-card">
<h3><%= @active_today %></h3>
<p>Active today</p>
</div>
</div>
</turbo-frame>พร้อมที่จะพิชิตการสัมภาษณ์ Ruby on Rails แล้วหรือยังครับ?
ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ
Turbo Streams samrap Kapnhat Raiaethaim
Turbo Streams sanoe paet kan kra tham samrap kan chatkan DOM: append, prepend, replace, update, remove, before, after lae morph. Kan kra tham lehla ni samat thuek riak phan khamtop HTTP rue WebSocket.
# app/controllers/messages_controller.rb
class MessagesController < ApplicationController
def create
@message = current_user.messages.build(message_params)
respond_to do |format|
if @message.save
# Turbo Stream response to add the message
format.turbo_stream do
render turbo_stream: [
turbo_stream.prepend("messages", @message),
turbo_stream.update("message_count", partial: "messages/count"),
turbo_stream.replace("new_message", partial: "messages/form",
locals: { message: Message.new })
]
end
format.html { redirect_to messages_path, notice: "Message created" }
else
format.turbo_stream do
render turbo_stream: turbo_stream.replace(
"new_message",
partial: "messages/form",
locals: { message: @message }
)
end
format.html { render :new, status: :unprocessable_entity }
end
end
end
def destroy
@message = Message.find(params[:id])
@message.destroy
respond_to do |format|
# Removal with animation
format.turbo_stream { render turbo_stream: turbo_stream.remove(@message) }
format.html { redirect_to messages_path, notice: "Message deleted" }
end
end
endThaemplet Turbo Stream Chapho
Samrap khamtop thi sapson kwanan, thaemplet .turbo_stream.erb sanoe khwam yuedhyun makkwa.
<!-- app/views/messages/create.turbo_stream.erb -->
<!-- Prepend the new message to the list -->
<%= turbo_stream.prepend "messages" do %>
<%= render @message %>
<% end %>
<!-- Update the counter -->
<%= turbo_stream.update "message_count" do %>
<span><%= Message.count %> messages</span>
<% end %>
<!-- Reset the form -->
<%= turbo_stream.replace "new_message" do %>
<%= render "form", message: Message.new %>
<% end %>
<!-- Display a flash notification -->
<%= turbo_stream.prepend "flash_messages" do %>
<div class="flash flash-success" data-controller="auto-dismiss">
Message sent successfully!
</div>
<% end %>Khamtop Turbo Stream tong mi content-type text/vnd.turbo-stream.html. Rails chatkan singni doi atonmat kap respond_to lae rup baep turbo_stream.
Broadcasting Raiaethaim kap Action Cable
Turbo Streams doden dai di thi sut kap kan broadcasting WebSocket. Phuchai dai rap kapnhat thanthi doi mai tong polling.
# app/models/message.rb
class Message < ApplicationRecord
belongs_to :room
belongs_to :author, class_name: "User"
# Automatic broadcast after creation
after_create_commit do
broadcast_append_to(
room,
target: "messages",
partial: "messages/message",
locals: { message: self }
)
end
# Broadcast after update
after_update_commit do
broadcast_replace_to(
room,
target: dom_id(self),
partial: "messages/message",
locals: { message: self }
)
end
# Broadcast after deletion
after_destroy_commit do
broadcast_remove_to(room, target: dom_id(self))
end
endView samak rap stream thi trongkan duai helper turbo_stream_from.
<!-- app/views/rooms/show.html.erb -->
<h1><%= @room.name %></h1>
<!-- Subscribe to the WebSocket stream -->
<%= turbo_stream_from @room %>
<!-- Container for messages -->
<div id="messages">
<%= render @room.messages.order(created_at: :asc) %>
</div>
<!-- New message form -->
<%= form_with model: [@room, Message.new], id: "new_message" do |f| %>
<%= f.text_area :content, placeholder: "Your message..." %>
<%= f.submit "Send" %>
<% end %>Broadcasting Baep Asinkronat samrap Kan Tham Ngan Nak
Phue likliang kan blok request, broadcasting samat tham dai nai baenglang.
# app/models/report.rb
class Report < ApplicationRecord
belongs_to :user
after_create_commit :generate_async
private
def generate_async
GenerateReportJob.perform_later(self)
end
end# app/jobs/generate_report_job.rb
class GenerateReportJob < ApplicationJob
queue_as :default
def perform(report)
# Simulating a long operation
report.update!(status: "processing")
# Notify user of start
report.broadcast_replace_to(
report.user, :reports,
target: dom_id(report),
partial: "reports/report"
)
# Generate the report
result = ReportGenerator.new(report).generate
report.update!(content: result, status: "completed")
# Notify user of completion
report.broadcast_replace_to(
report.user, :reports,
target: dom_id(report),
partial: "reports/report"
)
end
endRuepbaep Kanchai Ngan Khansungsamrap Turbo
Kan Kaekhai Baep Inline
Ruepbaeb thi phop boi kiao kap kan thaenthi nueaha thi khong mi kan plianplaeng duai baep kaekhai inline.
<!-- app/views/tasks/_task.html.erb -->
<turbo-frame id="<%= dom_id(task) %>">
<div class="task">
<span class="task-content"><%= task.content %></span>
<div class="task-actions">
<%= link_to "Edit", edit_task_path(task) %>
<%= button_to "Delete", task_path(task), method: :delete,
data: { turbo_confirm: "Delete this task?" } %>
</div>
</div>
</turbo-frame><!-- app/views/tasks/edit.html.erb -->
<turbo-frame id="<%= dom_id(@task) %>">
<%= form_with model: @task do |f| %>
<%= f.text_field :content, autofocus: true %>
<div class="form-actions">
<%= f.submit "Save" %>
<%= link_to "Cancel", task_path(@task) %>
</div>
<% end %>
</turbo-frame>Naewithang Nok Frame Lak
Doi kahamnot, link nai frame cha yu nai frame nan. Atthribut data-turbo-frame anuyat hai jaomung pai frame uen rue thang phaena.
<!-- app/views/search/_results.html.erb -->
<turbo-frame id="search_results">
<ul>
<% @results.each do |result| %>
<li>
<!-- This link navigates the entire page, not the frame -->
<%= link_to result.title, result_path(result),
data: { turbo_frame: "_top" } %>
</li>
<% end %>
</ul>
</turbo-frame><!-- app/views/layouts/_sidebar.html.erb -->
<aside>
<!-- This frame loads content and updates main -->
<turbo-frame id="sidebar_nav" target="main_content">
<%= render "navigation" %>
</turbo-frame>
</aside>
<main>
<turbo-frame id="main_content">
<%= yield %>
</turbo-frame>
</main>Nai sapha waetlaom kan phatthana, poet JavaScript console lae phim Turbo.setProgressBarDelay(0) phue hen thaeang khwam khaonah thanthi. Turbo.session.drive = false pit Turbo Drive chuakhrao.
Kan Chatkan Khophitphlat lae Sathana Kamlang Lot
UX thi di tong kan kan chatkan sathana kamlang lot lae khophitphlat khruekhai.
<!-- app/views/shared/_form_with_loading.html.erb -->
<%= form_with model: @model,
data: {
controller: "form-loading",
action: "turbo:submit-start->form-loading#disable turbo:submit-end->form-loading#enable"
} do |f| %>
<%= yield f %>
<button type="submit" data-form-loading-target="submit">
<span data-form-loading-target="text">Save</span>
<span data-form-loading-target="spinner" class="hidden">
<svg class="animate-spin h-5 w-5"><!-- spinner SVG --></svg>
</span>
</button>
<% end %>import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["submit", "text", "spinner"]
disable() {
this.submitTarget.disabled = true
this.textTarget.classList.add("hidden")
this.spinnerTarget.classList.remove("hidden")
}
enable() {
this.submitTarget.disabled = false
this.textTarget.classList.remove("hidden")
this.spinnerTarget.classList.add("hidden")
}
}Kan Chatkan Khophitphlat Soewoe
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound do |exception|
respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.replace(
"main_content",
partial: "shared/not_found"
)
end
format.html { render "errors/not_found", status: :not_found }
end
end
endKan Prapprung Prasiththiphap
Lai thekhnik raprong aepplikheishan Turbo thi mi prasiththiphap.
# app/controllers/messages_controller.rb
class MessagesController < ApplicationController
# Avoid N+1 queries with eager loading
def index
@messages = Message.includes(:author, :room)
.order(created_at: :desc)
.page(params[:page])
end
# Fragment caching for static elements
def show
@message = Message.find(params[:id])
fresh_when @message
end
end<!-- app/views/messages/_message.html.erb -->
<!-- Partial-level caching -->
<% cache message do %>
<turbo-frame id="<%= dom_id(message) %>">
<div class="message">
<%= message.content %>
<small>By <%= message.author.name %></small>
</div>
</turbo-frame>
<% end %>Srupphon
Hotwire lae Turbo plianplaeng kan phatthana Rails doi kan loet khwam sapson khong framework JavaScript daengdoem. Turbo Drive reng khwam reo kan naewithang, Turbo Frames anuyat kan kapnhat baep jaomung, lae Turbo Streams sanoe khwam samat raiaethaim thi trongklang.
Raikantruatsop samrap Roem Ton kap Hotwire
- Chai Rails 7+ samrap kan ruam Hotwire thi mi ma hai
- Khaojai sam ongprakop: Drive, Frames lae Streams
- Rabu son khong phaena thi dai rap phon prayot chak Turbo Frames
- Chai
respond_tokapformat.turbo_streamnai khonthrolen - Nammaj broadcasting samrap ficoer raiaethaim
- Ruam kap Stimulus samrap kan toptoep JavaScript thi ngai
เริ่มฝึกซ้อมเลย!
ทดสอบความรู้ของคุณด้วยตัวจำลองสัมภาษณ์และแบบทดสอบเทคนิคครับ
Withikan "HTML phan sai" ni anuyat hai sang aepplikheishan thi than samai lae mi kan toptoep khana thi rak sa khwam ngai lae phon phlit thi thamhai Ruby on Rails mi phalang makkhana. Phonlap: khot thi tong dulae noi long, prasiththiphap thi yiam yot lae prasopkan nak phatthana thi di thi sut.
แท็ก
แชร์