You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails中Simple Form无法向控制器传递motivo参数问题

问题原因

你遇到的核心问题是两个同名的motivo输入框冲突:不管是否隐藏,表单提交时浏览器会将所有带有name="vacacion[motivo]"的字段都发送给控制器,最后一个空的输入框值会覆盖之前填写的内容,导致控制器拿到的motivo始终为空。另外注意你JS里的div选择器和视图里的div id不匹配(视图是id1/id2,JS里写的是#campos_vacaciones_abonadas),这也会导致显示隐藏逻辑失效,需要先修正。

解决办法

方案1:禁用隐藏区域的输入框(最简单)

在切换显示/隐藏div时,给隐藏区域内的motivo输入框添加disabled属性(禁用的字段不会被表单提交),给显示区域的输入框移除禁用属性:

$(document).ready(function(){
    $("#vacacion_tipo").change(function(){
      const tomadasDiv = $("#id1");
      const abonadasDiv = $("#id2");
      const tomadasMotivo = tomadasDiv.find("input[name='vacacion[motivo]']");
      const abonadasMotivo = abonadasDiv.find("input[name='vacacion[motivo]']");

      if(this.value == "tomadas"){
        abonadasDiv.hide("slow");
        abonadasMotivo.prop("disabled", true);
        tomadasDiv.show("slow");
        tomadasMotivo.prop("disabled", false);
      }

      if(this.value == "abonadas"){
        tomadasDiv.hide("slow");
        tomadasMotivo.prop("disabled", true);
        abonadasDiv.show("slow");
        abonadasMotivo.prop("disabled", false);
      }
    });
});

方案2:使用不同的字段名,在控制器统一处理

给两个motivo设置不同的name属性,然后在控制器根据tipo字段的值,将对应的值赋值给模型的motivo:

视图修改:

<div id="id1" style="display:none">
  <!-- 其他字段保持不变 -->
  <%= f.input :motivo_tomadas, input_html: { id: 'motivo_tomadas'},label: 'Motivo de los días tomados' %>
</div>

<div id="id2" style="display:none">
  <!-- 其他字段保持不变 -->
  <%= f.input :motivo_abonadas, input_html: { id: 'motivo_abonadas'},label: 'Motivo de los días abonados' %>
</div>

控制器修改:

def vacacion_params
  params.require(:vacacion).permit(:tipo, :desde, :hasta, :dias_tomados, :dias_abonados, :motivo_tomadas, :motivo_abonadas).tap do |permitted|
    permitted[:motivo] = permitted.delete(permitted[:tipo] == 'tomadas' ? :motivo_tomadas : :motivo_abonadas)
  end
end

方案3:使用单个输入框,动态切换标签

只保留一个motivo输入框,通过JS切换类型时修改输入框的标签文本,从根源避免同名冲突:

视图修改:

<%= simple_form_for(@vacacion, validate: true, html: { class: "form-horizontal", role: "form" }) do |f| %>
  <%= f.error_notification %>
  <%= display_base_errors @vacacion %>

  <%= f.input :tipo, label: 'Tipo', as: :select, collection: [["Registrar días de vacaciones utilizados", "tomadas"], ["Abonar días de vacaciones", "abonadas"]], required: true %>

  <div id="id1" style="display:none">
    <%= f.input :desde, label: 'Fecha inicio vacaciones', as: :datepicker, input_html: { value: @vacacion.desde.present? ? l(@vacacion.desde, format: :slash) : nil } %>
    <%= f.input :hasta, label: 'Fecha fin vacaciones', as: :datepicker, input_html: { value: @vacacion.hasta.present? ? l(@vacacion.hasta, format: :slash) : nil } %>
    <%= f.input :dias_tomados, label: 'Días de vacaciones utilizados', input_html: { min: 0 }, hint: '<div id="dias_habiles_div"></div>'.html_safe %>
  </div>

  <div id="id2" style="display:none">
    <%= f.input :dias_abonados, label: 'Días de vacaciones a abonar', input_html: { min: 0 } %>
  </div>

  <%= f.input :motivo, input_html: { id: 'motivo_input' }, label: 'Motivo' %>
<% end %>

JS修改:

$(document).ready(function(){
    $("#vacacion_tipo").change(function(){
      const tomadasDiv = $("#id1");
      const abonadasDiv = $("#id2");
      const motivoLabel = $("#motivo_input").closest(".form-group").find("label");

      if(this.value == "tomadas"){
        abonadasDiv.hide("slow");
        tomadasDiv.show("slow");
        motivoLabel.text("Motivo de los días tomados");
      }

      if(this.value == "abonadas"){
        tomadasDiv.hide("slow");
        abonadasDiv.show("slow");
        motivoLabel.text("Motivo de los días abonados");
      }
    });
});

内容的提问来源于stack exchange,提问作者Rodrigo Ladrón de Guevara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 00:03:21