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

Ruby on Rails中JavaScript下拉更新失效问题(疑似预加载导致)

问题分析与解决方案

核心原因

你遇到的问题是Rails默认启用的**Turbo(原TurboLinks)**页面加载机制导致的。Turbo为了加速导航,会缓存页面并在返回时复用DOM,而你的内嵌JS仅在页面首次加载时执行,返回页面时DOM可能被替换,但JS变量初始化、事件绑定都没有重新执行,导致linePicker等变量指向旧DOM元素,功能失效。本地环境可能因为Turbo未完全启用(或缓存机制不同)所以没有问题。


快速解决方法

方法1:禁用当前页面的Turbo

在页面的<head>中添加meta标签,强制页面每次都重新加载:

<meta name="turbo-visit-control" content="reload">

或者在触发跳转的顶部菜单链接上添加data-turbo="false",让跳转不使用Turbo缓存:

<%= link_to '项目页', projects_path, data: { turbo: false } %>

方法2:适配Turbo的加载事件(更优雅)

将JS逻辑包裹在Turbo的turbo:load事件监听中,确保每次页面加载(包括返回)都重新初始化元素和事件绑定,同时建议替换inline的onChange为JS事件监听,避免依赖DOM属性:

<script>
document.addEventListener('turbo:load', function() {
  // 线路常量定义
  const REDLINE = {
    "47th (95th-bound)": "30238",
    "47th (Howard-bound)": "30237",
  };
  const BLUELINE = {
    "Addison (Forest Pk-bound)": "30240",
    "Addison (O'Hare-bound)": "30239",
  };
  const PURPLELINE = {
    "Central (Howard-Loop-bound)": "30242",
    "Central (Linden-bound)": "30241",
  };
  const GREENLINE = {
    "35-Bronzeville-IIT (63rd-bound)": "30214",
    "35-Bronzeville-IIT (Harlem-bound)": "30213",
  };
  const ORANGELINE = {
    "35th/Archer (Loop-bound)": "30022",
    "35th/Archer (Midway-bound)": "30023",
  };
  const PINKLINE = {
    "18th (54th/Cermak-bound)": "30162",
    "18th (Loop-bound)": "30161",
  };
  const YELLOWLINE = {
    "Dempster-Skokie (Arrival)": "30026",
    "Dempster-Skokie (Howard-bound)": "30027",
  };

  const linePicker = document.getElementById("line");
  const stopPicker = document.getElementById("stop");

  function linePick() {
    let pickList = '<option value="null">Pick a Stop!</option>';
    if (linePicker.value === "red") {
      Object.entries(REDLINE).forEach(([name, id]) => {
        pickList += `<option value="${id}">${name}</option>`;
      });
    } else if (linePicker.value === "blue") {
      Object.entries(BLUELINE).forEach(([name, id]) => {
        pickList += `<option value="${id}">${name}</option>`;
      });
    } else if (linePicker.value === "purple") {
      Object.entries(PURPLELINE).forEach(([name, id]) => {
        pickList += `<option value="${id}">${name}</option>`;
      });
    } else if (linePicker.value === "green") {
      Object.entries(GREENLINE).forEach(([name, id]) => {
        pickList += `<option value="${id}">${name}</option>`;
      });
    } else if (linePicker.value === "orange") {
      Object.entries(ORANGELINE).forEach(([name, id]) => {
        pickList += `<option value="${id}">${name}</option>`;
      });
    } else if (linePicker.value === "pink") {
      Object.entries(PINKLINE).forEach(([name, id]) => {
        pickList += `<option value="${id}">${name}</option>`;
      });
    } else if (linePicker.value === "yellow") {
      Object.entries(YELLOWLINE).forEach(([name, id]) => {
        pickList += `<option value="${id}">${name}</option>`;
      });
    }
    stopPicker.innerHTML = pickList;
  }

  function stopPick() {
    const pickedStop = stopPicker.value;
    console.log(pickedStop);
    window.location.href = `${window.location.origin}/projects/train_tracker/${pickedStop}`;
  }

  // 绑定事件(替代inline onChange)
  if (linePicker) linePicker.addEventListener('change', linePick);
  if (stopPicker) stopPicker.addEventListener('change', stopPick);
});
</script>

代码优化建议

  1. 修复代码中的错误:你原代码里有重复的purple分支,且未定义BROWNLINE常量(如果实际不需要可以删除对应分支),这些可能引发控制台报错导致功能失效。
  2. 简化线路逻辑:把所有线路合并成一个对象,减少重复代码:
const LINES = {
  red: REDLINE,
  blue: BLUELINE,
  purple: PURPLELINE,
  green: GREENLINE,
  orange: ORANGELINE,
  pink: PINKLINE,
  yellow: YELLOWLINE
};

function linePick() {
  const selectedLine = LINES[linePicker.value];
  let pickList = '<option value="null">Pick a Stop!</option>';
  if (selectedLine) {
    Object.entries(selectedLine).forEach(([name, id]) => {
      pickList += `<option value="${id}">${name}</option>`;
    });
  }
  stopPicker.innerHTML = pickList;
}

后续迁移到Rails Assets Pipeline的建议

等熟悉Rails后,建议把JS代码迁移到app/javascript目录下:

  • Rails 6+:使用Import Maps或Webpacker,创建app/javascript/train_tracker.js,然后在页面中用javascript_importmap_tags 'train_tracker'引入。
  • Rails 5及以下:使用Sprockets,把代码放在app/assets/javascripts/train_tracker.js,然后用javascript_include_tag 'train_tracker'引入。
    这样更符合Rails最佳实践,便于维护和管理静态资源。

内容的提问来源于stack exchange,提问作者CJGlitter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 16:16:10