Rails开发问题:从一个模型的控制器与视图向另一模型提交表单
嘿,作为Rails新手碰到跨模型表单提交的问题太正常了,我来一步步帮你搞定这个校车签到功能!
第一步:先把模型关联理清楚
首先得让Kid和SchoolRide、HomeRide建立正确的关联,这样后续操作才顺畅。假设每个孩子每天会有一条签到/签出记录,那我们可以这么设置:
# app/models/kid.rb class Kid < ApplicationRecord belongs_to :family # 一个孩子有多条签到记录(每天一条) has_many :school_rides, dependent: :destroy has_many :home_rides, dependent: :destroy end # app/models/school_ride.rb class SchoolRide < ApplicationRecord belongs_to :kid # 字段应该包含:checked_in:boolean(签到状态)、checked_in_at:datetime(签到时间)、date:date(签到日期) end # app/models/home_ride.rb 和SchoolRide结构一致 class HomeRide < ApplicationRecord belongs_to :kid end
第二步:配置合理的路由
我们可以用嵌套路由,让签到请求的URL更符合REST风格,同时明确关联关系:
# config/routes.rb Rails.application.routes.draw do resources :families resources :kids do # 给每个孩子添加签到/签出的自定义动作 post 'school_check_in', to: 'school_rides#check_in' post 'home_check_out', to: 'home_rides#check_out' end end
第三步:编写控制器的签到逻辑
接下来在SchoolRidesController和HomeRidesController里实现签到/签出的核心逻辑——优先查找当天的记录,没有就新建,有就更新状态:
# app/controllers/school_rides_controller.rb class SchoolRidesController < ApplicationController # 假设你用了Devise做用户认证,先确保用户登录 before_action :authenticate_user! # 验证当前用户是否有权操作这个孩子的签到 before_action :validate_family_access, only: [:check_in] def check_in @kid = Kid.find(params[:kid_id]) # 查找当天的签到记录,没有则新建 school_ride = @kid.school_rides.find_or_initialize_by(date: Date.current) school_ride.update(checked_in: true, checked_in_at: Time.current) redirect_to @kid, notice: '早晨校车签到成功!' end private def validate_family_access @kid = Kid.find(params[:kid_id]) unless current_user.family == @kid.family redirect_to root_path, alert: '你没有权限操作这个孩子的签到!' end end end # HomeRidesController的check_out逻辑和上面几乎一致,把字段改成对应的签出状态即可
第四步:在视图里添加签到按钮
最后,我们可以在Kid的详情页面(kids/show.html.erb)里添加签到/签出的表单按钮,直接提交到对应的控制器动作:
# app/views/kids/show.html.erb <h1><%= @kid.name %> 的签到页面</h1> <div class="check-in-section"> <h3>早晨校车签到</h3> <% if @kid.school_rides.find_by(date: Date.current)&.checked_in %> <p class="success">已签到:<%= @kid.school_rides.find_by(date: Date.current).checked_in_at.strftime('%Y-%m-%d %H:%M') %></p> <% else %> <%= form_with(url: kid_school_check_in_path(@kid), method: :post, local: true) do |form| %> <%= form.submit '立即签到', class: 'btn btn-primary' %> <% end %> <% end %> </div> <div class="check-out-section"> <h3>下午回家签出</h3> <% if @kid.home_rides.find_by(date: Date.current)&.checked_in %> <p class="success">已签出:<%= @kid.home_rides.find_by(date: Date.current).checked_in_at.strftime('%Y-%m-%d %H:%M') %></p> <% else %> <%= form_with(url: kid_home_check_out_path(@kid), method: :post, local: true) do |form| %> <%= form.submit '立即签出', class: 'btn btn-secondary' %> <% end %> <% end %> </div>
这样就能实现从Kid的视图页面,向SchoolRide/HomeRide模型提交签到请求的功能了!如果需要调整逻辑(比如每个孩子只有一条签到记录而非每天一条),只需要修改关联和控制器里的查找逻辑即可。
内容的提问来源于stack exchange,提问作者landmark
相关产品推荐
相关产品推荐

