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

Ruby on Rails 7:如何从控制器调用JavaScript函数并传递变量

Rails 7 控制器变量传递与JS执行顺序问题解决

问题说明

我在app/javascript/scripts/script_scripts.js路径下有一个JS文件,文件关联正常。目前id="create"的元素功能正常,id="func"的事件监听器也能正常工作,但存在两个问题:

  1. JS代码会在控制器调用前执行,导致id="funner"的事件监听器无法获取控制器中定义的@txt变量;
  2. 不清楚在Rails 7中如何正确使用onclick执行函数。

需求:要么实现控制器先设置变量再调用JS函数,要么实现从控制器直接调用该JS文件。


现有代码

1. JS文件(app/javascript/scripts/script_scripts.js)

function fun() {
  alerts('<%= @txt %>')
};

function funs(txt) {
  alerts(txt)
};

document.getElementById('funner').addEventListener('click', function() {
  alert("<%= @txt %>")
});

document.getElementById('func').addEventListener('click', function() {
  alert("TADA")
});

var test = document.getElementById('create').innerHTML = "Hello World! In script.js Test";

2. ERB视图文件

<% content_for :head do %>
  <%= javascript_import_module_tag "script" %>
<% end %>

<%= 
  button_to "Click Me", 
  home_test_path,
  onclick:"fun()"
%>

<%= 
  button_to "Click Me", 
  home_test_path,
  onclick:"funs(#{@txt})"
%>

<%= 
  button_to "Click Me", 
  home_test_path,
  id:"funner"
%>

<%= 
  button_to "Click Me", 
  home_test_path,
  id:"func"
%>

<div id="create"></div>

3. Home控制器test方法

class HomeController < ApplicationController
  def test
    @txt = "YAY"
  end
end

(注:原代码中test方法定义缺少def,已修正)


解决方案

方案1:修正JS执行时机,正确传递控制器变量

单独的JS文件无法解析ERB的<%= %>语法,且Rails 7默认使用Turbo,需确保JS在页面完全加载后执行,同时通过视图传递变量。

步骤1:修改ERB视图

  • 用普通<button>替代button_to避免默认表单提交(或在onclick中阻止默认行为);
  • 将@txt通过全局变量或data属性传递给JS:
<% content_for :head do %>
  <%= javascript_import_module_tag "script" %>
  <!-- 定义全局变量传递控制器值 -->
  <script>
    window.controllerTxt = '<%= j @txt %>';
  </script>
<% end %>

<!-- 普通button执行前端函数,阻止默认提交 -->
<button onclick="fun(); return false;">Click Me</button>

<button onclick="funs('<%= j @txt %>'); return false;">Click Me</button>

<!-- 用data属性传递变量给funner按钮 -->
<%= button_to "Click Me", home_test_path, id:"funner", data: { txt: @txt } %>

<%= button_to "Click Me", home_test_path, id:"func" %>

<div id="create"></div>

步骤2:修改JS文件

使用Turbo的turbo:load事件确保页面就绪后执行代码,从全局变量或data属性读取值:

// 等待Turbo完成页面加载
document.addEventListener('turbo:load', function() {
  // 初始化create元素
  document.getElementById('create').innerHTML = "Hello World! In script.js Test";

  // 绑定func按钮事件
  const funcBtn = document.getElementById('func');
  if (funcBtn) {
    funcBtn.addEventListener('click', function() {
      alert("TADA");
    });
  }

  // 绑定funner按钮事件,从data属性获取变量
  const funnerBtn = document.getElementById('funner');
  if (funnerBtn) {
    funnerBtn.addEventListener('click', function(e) {
      // 阻止默认表单提交
      e.preventDefault();
      alert(this.dataset.txt);
    });
  }
});

// 全局声明函数,供onclick调用
window.fun = function() {
  alert(window.controllerTxt);
};

window.funs = function(txt) {
  alert(txt);
};

方案2:从控制器直接调用JS

在控制器中渲染JS代码,确保控制器先设置变量再执行逻辑:

修改Home控制器test方法

class HomeController < ApplicationController
  def test
    @txt = "YAY"
    # 直接渲染JS代码,执行需要的逻辑
    render js: "alert('#{j @txt}'); document.getElementById('create').innerHTML = 'Hello World! In script.js Test';"
    # 也可以调用JS文件中的函数
    # render js: "fun('#{j @txt}');"
  end
end

这种方式下,点击button_to会触发控制器方法,返回的JS代码会直接在前端执行,保证变量已被设置。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 14:54:24