Turbo嵌套表单问题:添加/删除按钮失效及参数错误
Turbo动态嵌套表单问题修复方案
问题概述
- 保存父表单后返回编辑页面可显示嵌套项,但Delete按钮无响应;
- Add Option按钮未触发子项创建,反而调用父控制器
surveys/questions_controller#create,报":title, :description, :question_options_attributes"参数不允许错误。
核心错误分析与修复
一、Add Option按钮错误修复
1. 路由定义错误
当前路由将create定义为member动作(需要对应资源实例),但create是创建新资源的collection动作,修正路由:
resources :surveys, param: :slug do resources :sections, controller: "surveys/sections", param: :sec_num resources :questions, controller: "surveys/questions", param: :position do resources :options, controller: "surveys/questions/options", only: [:create, :destroy], param: :index end end
此定义会自动生成:
- POST请求:
survey_question_options_path(对应create动作) - DELETE请求:
survey_question_option_path(对应destroy动作)
2. Options控制器缺失create方法
添加create方法,构建新选项并返回Turbo流响应:
class Surveys::Questions::OptionsController < Surveys::QuestionsController before_action :setup def create # 注意:模型关联是has_many :question_options,不是options @option = @question.question_options.build @options = @question.question_options + [@option] respond_to do |format| format.turbo_stream end end def destroy @option = @question.question_options.find(params[:id]) respond_to do |format| format.turbo_stream end end private def setup @survey = Survey.find_by(slug: params[:survey_slug]) @section = @survey.sections.find_by(section_number: params[:sec_num]) @question = @section.questions.find_by(position: params[:question_position]) end end
3. 视图中路径与关联调用错误
- 修正Add按钮的路径为collection路由:
= f.submit "Add Option", formaction: survey_question_options_path(survey_slug: q.survey_section.survey.slug, question_position: q.position, sec_num: q.survey_section.section_number), formmethod: :post, formnovalidate: true, id: "add_option"
- 统一模型关联调用:将所有
@question.options/q.options改为@question.question_options/q.question_options(模型中定义的是has_many :question_options)
4. 修正create.turbo_stream.haml模板错误
将模板中的task_form改为of,并更新Add按钮的index参数:
= fields model: @question do |f| = f.fields_for :question_options, @options, child_index: params[:index] do |of| = turbo_stream.replace "add_option" do = f.submit "Add Option", formaction: survey_question_options_path(survey_slug: @survey.slug, question_position: @question.position, sec_num: @section.section_number, index: @options.size), formmethod: :post, formnovalidate: true, id: "add_option" = turbo_stream.append "options" do = render "surveys/questions/options/form", form: of, q: @question
二、Delete按钮无响应修复
1. 修正destroy.turbo_stream.haml模板逻辑
添加标记删除的隐藏字段到父表单,再移除对应选项的Turbo帧:
= turbo_stream.append "options" do = fields_for :survey_question, @question do |f| = f.fields_for :question_options, @option, child_index: params[:index] do |of| = of.hidden_field :id = of.hidden_field :_destroy, value: true = turbo_stream.remove "question_#{@question.id}_option_#{params[:index]}"
2. 移除Delete按钮的Turbo帧限制
删除按钮的data-turbo-frame属性,让Turbo全局处理响应:
= form.submit "Delete", formaction: survey_question_option_path(survey_slug: q.survey_section.survey.slug, question_position: q.position, index: form.index, id: form.object.id, sec_num: q.survey_section.section_number), formmethod: :delete, formnovalidate: true
三、其他细节修正
- 父控制器update_params拼写错误:将
:survey_setion_id改为:survey_section_id
def update_params params.require(:survey_question).permit(:survey_section_id, :position, :question_type, :title, :description, question_options_attributes: [:id, :_destroy, :name, :logic, :sub_logic]) end
- 父控制器edit方法中关联调用修正:
def edit @option = @question.question_options.build render partial: "surveys/questions/edit", locals: {q: @question, survey: @survey, section: @section, option: @option} end
内容的提问来源于stack exchange,提问作者Patrick Vellia
相关产品推荐
相关产品推荐

