提问人:djFuz 提问时间:4/9/2023 更新时间:4/11/2023 访问量:264
了解如何将 Turbo 与 Ruby on Rails 配合使用
Understanding how to use Turbo with Ruby on Rails
问:
我正在尝试了解如何使用 Turbo 以便在无需刷新页面的情况下刷新页面内容。我已经浏览了一些视频和网络教程,但它不适用于我的页面设置方式,我试图弄清楚我的设置是否设计不佳,我应该更改它,或者是否可以将 Turbo 功能添加到我的代码中。我是 Ruby on Rails 和 Turbo 的新手,所以可能还没有足够的理解来点击它。从本质上讲,我的索引页面上有一个表单,允许用户选择该州,提交后,显示一个新的选择框,其中包含该州的城市以及该州所有设施的列表。用户选择城市并提交表单后,设施列表将仅限于该城市。表单将提交回索引页。我想通过设施部分更新城市选择框和表格,该部分根据表单提交在索引页面上显示设施,但从我看到的每个教程来看,表单都会提交到不同的函数,该函数会调用一个新页面来替换当前部分。有没有办法从我当前的代码中做到这一点,或者我是否需要让表单调用不同的函数?
index.html.erb
<% provide(:title, "Facilities") %>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<br>
<%= form_with(url: facilities_path, method: :get, remote: true) do |f| %>
<table class="table table-borderless">
<tr>
<td>
<div class="form-inline">
<%= f.label :state_id, "State" %>
<%= f.collection_select :state_id, @states, :id, :state_long, {:selected => params[:state_id], include_blank: 'Select A State'}, {class: 'form-control'} %>
</div>
</td>
<% if !params[:state_id].blank? %>
<td>
<div class="form-inline">
<%= f.label :city_id, "City" %>
<%= f.collection_select :city_id, @cities, :id, :city_titlecase, {:selected => params[:city_id], include_blank: 'Select A City'}, {class: 'form-control'} %>
</div>
</td>
<% end %>
<td><%= f.submit "Update Search", name: nil, class: "btn btn-primary" %></td>
</tr>
</table>
<% end %>
</div>
</div>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<% if @facilities.any? %>
<table class="table table-hover table-striped table-bordered">
<thead>
<tr>
<th> </th>
<th>Facility</th>
<th>City</th>
<th>State</th>
</tr>
</thead>
<tbody>
<%= render @facilities %>
</tbody>
</table>
<span style="float:right"><%= will_paginate %></span>
<% end %>
</div>
</div>
Facilities_Controller.rb
def index
@states = State.all
#Get the state id from the database based on the state long name
current_state_db = State.find_by(state_long: current_state)
if params[:state_id].blank?
@facilities = Facility.all.joins(:state, :city).order("states.state_short, cities.city, facility_name").paginate(page: params[:page])
else
@cities = City.where(state_id: params[:state_id])
if params[:city_id].blank?
@facilities = Facility.where(state_id: params[:state_id]).joins(:state, :city).order("states.state_short, cities.city, facility_name").paginate(page: params[:page])
else
#Check to make sure the city_id is in the selected state -> if the user changed the state a city was selected, it would keep the old city in the params
expected_state = City.find_by(id: params[:city_id]).state_id
if params[:state_id].to_i == expected_state
@facilities = Facility.where(state_id: params[:state_id], city_id: params[:city_id]).joins(:state, :city).order("states.state_short, cities.city, facility_name").paginate(page: params[:page])
else
#The current selected city is not in the state
@facilities = Facility.where(state_id: params[:state_id]).joins(:state, :city).order("states.state_short, cities.city, facility_name").paginate(page: params[:page])
end
end
end
end
我已经浏览了多个 turbo 视频和教程,但它们指的是调用不同函数和视图的表单,然后用相同的 turbo id 替换当前视图。我希望找到一种方法来使用提交给索引函数的表单来做到这一点。我仍在学习 Turbo 和 AJAX,但根据我对所读内容的理解,Turbo 在幕后使用 AJAX 来实现这一目标?
答:
如果您将其放在涡轮框架中,只要您使用匹配的框架进行响应,提交表单的位置就没有区别。也许这个例子有点复杂,但它显示了你可以做什么。它会自动提交到同一页面,控制器操作是空的,唯一不明显的是针对不同的字段更新了不同的帧:
<%= tag.div data: {controller: "selector"} do %>
<%= form_with url: "/", data: {selector_target: "form"} do |f| %>
<%= f.collection_select :state, State.all, :id, :name, {prompt: true},
{data: {action: "selector#nextFrame", selector_frame_param: "cities"}} %>
# ^ this will update v this frame
<%= turbo_frame_tag :cities do %>
<% if (current_state = State.find_by(id: params[:state])) %>
<%= f.collection_select :city, current_state.cities, :id, :name, {prompt: true},
{data: {action: "selector#nextFrame", selector_frame_param: "facilities"}} %>
# ^ this will update v this frame
<%= turbo_frame_tag :facilities do %>
<% if (current_city = current_state.cities.find_by(id: params[:city])) %>
Facilities for <%= current_city.name %>
...
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
请注意,我没有设置选项,因为目标框架之外的字段不会重置。selected
使用 stimulus 动态更新帧目标并提交表单:
bin/rails g stimulus selector
// app/javascript/controllers/selector_controller.js
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["form"];
nextFrame(event) {
const form = this.formTarget;
form.dataset.turboFrame = event.params.frame; // load the next frame
form.requestSubmit(); // after submitting the form
}
}
评论