Rails 7航班查询应用:解决初始加载显示全部航班问题
解决方案
1. 修正模型作用域(Scope)的返回值问题
你的filter_flights作用域存在返回值异常:当所有参数为空时,最后一行条件不执行会导致作用域返回nil而非合法的关系对象。同时,关联查询无需额外joins(departure_airport_id是Flight的直接字段),优化后的代码如下:
class Flight < ApplicationRecord belongs_to :departure_airport, class_name: 'Airport' belongs_to :arrival_airport, class_name: 'Airport' validates :departure_airport, :arrival_airport, :flight_date, presence: true scope :filter_flights, lambda { |departure_airport, arrival_airport, date, passengers| flights = all flights = flights.where(departure_airport_id: departure_airport) if departure_airport.present? flights = flights.where(arrival_airport_id: arrival_airport) if arrival_airport.present? flights = flights.where(flight_date: date) if date.present? flights = flights.where('available_passenger_seats >= ?', passengers) if passengers.present? flights # 确保始终返回ActiveRecord关系对象 } end
2. 调整控制器逻辑,区分初始加载与搜索请求
无需拆分index和search动作,在index中直接判断是否存在有效搜索参数即可。注意Rails控制器命名规范应为复数(FlightsController而非FlightController),并正确获取表单提交的嵌套参数:
class FlightsController < ApplicationController def index @flight = Flight.new # 初始化表单绑定的模型对象 @flight_dates = Flight.select(:flight_date).distinct.order(:flight_date) # 从嵌套的flight参数中提取搜索条件(表单使用model: @flight时参数会自动嵌套) search_params = params[:flight]&.permit(:departure_airport_id, :arrival_airport_id, :flight_date, :number_of_passengers) if search_params.present? && search_params.values.any?(&:present?) # 仅当存在非空搜索参数时,查询航班 @flights = Flight.filter_flights( search_params[:departure_airport_id], search_params[:arrival_airport_id], search_params[:flight_date], search_params[:number_of_passengers] ).includes(:departure_airport, :arrival_airport).order(:flight_date) else # 初始加载或参数全空时,返回空数组 @flights = [] end end end
3. 修正表单提交路径与字段绑定
使用Rails路由辅助方法flights_path替代硬编码的'/',确保表单提交到正确的index动作:
<%= form_with model: @flight, url: flights_path, method: :get do |form| %> <!-- 示例字段,根据实际需求调整 --> <%= form.label :departure_airport_id, "出发机场" %> <%= form.select :departure_airport_id, Airport.pluck(:name, :id), include_blank: "请选择" %> <%= form.label :arrival_airport_id, "到达机场" %> <%= form.select :arrival_airport_id, Airport.pluck(:name, :id), include_blank: "请选择" %> <%= form.label :flight_date, "航班日期" %> <%= form.select :flight_date, @flight_dates.map { |fd| [fd.flight_date.strftime("%Y-%m-%d"), fd.flight_date] }, include_blank: "请选择" %> <%= form.label :number_of_passengers, "乘客数量" %> <%= form.number_field :number_of_passengers, min: 1 %> <%= form.submit "搜索航班" %> <% end %>
4. 视图中控制航班列表显示
保持你原本的@flights.present?判断逻辑即可:
<% if @flights.present? %> <h3>搜索结果</h3> <table> <thead> <tr> <th>出发机场</th> <th>到达机场</th> <th>日期</th> <th>剩余座位</th> </tr> </thead> <tbody> <% @flights.each do |flight| %> <tr> <td><%= flight.departure_airport.name %></td> <td><%= flight.arrival_airport.name %></td> <td><%= flight.flight_date.strftime("%Y-%m-%d") %></td> <td><%= flight.available_passenger_seats %></td> </tr> <% end %> </tbody> </table> <% else %> <p>请填写搜索条件查询航班</p> <% end %>
5. 路由配置
确保config/routes.rb中配置了正确的路由:
Rails.application.routes.draw do resources :flights, only: [:index] end
问题根源说明
- 表单参数嵌套:使用
model: @flight生成表单时,所有参数会被包裹在params[:flight]哈希中,而非直接在params根节点,之前直接取params[:departure_airport_id]会获取不到值。 - 作用域返回值异常:原作用域在参数全空时会返回
nil,导致@flights.present?判断失效,修正后确保始终返回ActiveRecord::Relation对象。 - 初始加载逻辑缺失:未区分初始加载和搜索请求,导致默认查询所有航班,现在通过判断搜索参数是否存在来控制是否查询航班。
内容的提问来源于stack exchange,提问作者Taku Mapfumo
相关产品推荐
相关产品推荐

