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

如何在Rails 7中无需刷新页面渲染控制器自定义动作结果

问题需求

我在Task控制器中编写了自定义动作check_url,包含if-else逻辑,会调用Google Safe Browsing API返回检测结果。现在需要将结果渲染到index.html.erb页面,且无需刷新页面。目前用render plain: "" and return会在新页面展示结果,试过Ajax没成功,觉得Hotwire/Turbo教程太复杂,想要简单解决方案。

相关代码

tasks_controller.rb中的check_url动作

def check_url
    @id = params[:id]
    @result = params[:result]
    if params[:link].present?
      api_key = ENV[""]
      # Set up the request parameters
      url = params[:link]

      formatted_url = canonicalize_url(url)

      threat_types = ["MALWARE", "THREAT_TYPE_UNSPECIFIED", "SOCIAL_ENGINEERING", "UNWANTED_SOFTWARE", "POTENTIALLY_HARMFUL_APPLICATION"]
      platform_types = ["ANY_PLATFORM"]
      body = {
        client: {
          clientId: api_key,
          clientVersion: "1.0.0",
        },
        threatInfo: {
          threatTypes: threat_types,
          platformTypes: platform_types,
          threatEntryTypes: %w[URL THREAT_ENTRY_TYPE_UNSPECIFIED EXECUTABLE],
          threatEntries: [
            { url: formatted_url },
          ],
        },
      }

      # Set up the request headers
      headers = {
        "Content-Type" => "application/json",
      }

      # Make the request to the Safe Browsing API
      response = HTTP.post(
        "https://safebrowsing.googleapis.com/v4/threatMatches:find?key=",
        json: body,
        headers: headers,
      )

      # Check the response
      if response.code == 200
        data = JSON.parse(response.body)
        puts JSON.pretty_generate(data)

        @result = response.body
        if data["matches"].try(:empty?)
          render plain: "The URL is safe" and return
        else
          render plain: "The URL is not safe" and return
        end
      else
        render plain: "An error occurred"
      end
    else
      puts "link variable is empty"
    end

    puts "Response code: #{response.code}"
    puts "Response body: #{response.body}"

    puts "Request parameters: #{body}"
    puts "Request headers: #{headers}"
  end

  private

  def task_params
    params.require(:task).permit(:link, :result)
  end

_form.html.erb中的提交表单

<%= form_tag("/check_url", method: "post") do %>
  <%= label_tag(:link, "Enter a link:") %>
  <%= text_field_tag(:link) %>
  <%= submit_tag("Submit") %>
<% end %>

index.html.erb代码

<% if notice.present? %>
  <p class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block" id="notice">
    <%= notice %>
  </p>
<% end %>
<h1 class="font-bold text-2xl">Task Manager</h1>
<div class="mt-4">
  <%= render "form", task: @task %>
  <%= render 'tasks/check_url' %>
</div>
简单解决方案(适合Rails新手)

用Rails内置的UJS(Unobtrusive JavaScript)就能实现无刷新提交,无需复杂原生Ajax或Hotwire:

步骤1:修改表单,启用AJAX提交

在_form.html.erb的form_tag中添加remote: true,让表单通过AJAX提交而非刷新页面:

<%= form_tag("/check_url", method: "post", remote: true) do %>
  <%= label_tag(:link, "Enter a link:") %>
  <%= text_field_tag(:link) %>
  <%= submit_tag("Submit") %>
<% end %>

步骤2:修改控制器,响应JS请求

将check_url动作中的render plain:改为设置@message变量,然后渲染JS模板:

def check_url
    @id = params[:id]
    @result = params[:result]
    @message = ""
    if params[:link].present?
      api_key = ENV["GOOGLE_SAFE_BROWSING_KEY"] # 替换为你的API密钥环境变量名
      url = params[:link]
      formatted_url = canonicalize_url(url)

      threat_types = ["MALWARE", "THREAT_TYPE_UNSPECIFIED", "SOCIAL_ENGINEERING", "UNWANTED_SOFTWARE", "POTENTIALLY_HARMFUL_APPLICATION"]
      platform_types = ["ANY_PLATFORM"]
      body = {
        client: {
          clientId: api_key,
          clientVersion: "1.0.0",
        },
        threatInfo: {
          threatTypes: threat_types,
          platformTypes: platform_types,
          threatEntryTypes: %w[URL], # 仅保留URL类型即可,简化请求
          threatEntries: [
            { url: formatted_url },
          ],
        },
      }

      headers = {
        "Content-Type" => "application/json",
      }

      response = HTTP.post(
        "https://safebrowsing.googleapis.com/v4/threatMatches:find?key=#{api_key}", # 拼接API密钥
        json: body,
        headers: headers,
      )

      if response.code == 200
        data = JSON.parse(response.body)
        puts JSON.pretty_generate(data)

        @result = response.body
        if data["matches"].try(:empty?)
          @message = "The URL is safe"
        else
          @message = "The URL is not safe"
        end
      else
        @message = "An error occurred"
      end
    else
      @message = "Please enter a link"
    end

    # 渲染JS模板,替代plain文本输出
    respond_to do |format|
      format.js
    end
  end

注意:补全ENV[""]中的API密钥环境变量名,同时把请求URL里的key=改为key=#{api_key},否则API调用会失败。

步骤3:创建JS模板文件

在app/views/tasks/目录下新建check_url.js.erb文件,用来更新页面结果区域:

// 将检测结果插入到指定容器中
document.getElementById('url-check-result').innerHTML = "<p><%= j @message %></p>";

j是escape_javascript的简写,用于转义字符串特殊字符,避免JS执行报错。

步骤4:在index页面添加结果容器

修改index.html.erb,添加一个用于显示结果的div,并设置id为url-check-result:

<% if notice.present? %>
  <p class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block" id="notice">
    <%= notice %>
  </p>
<% end %>
<h1 class="font-bold text-2xl">Task Manager</h1>
<div class="mt-4">
  <%= render "form", task: @task %>
  <!-- 新增结果显示容器 -->
  <div id="url-check-result" class="mt-4"></div>
</div>

删除原有的<%= render 'tasks/check_url' %>,结果将通过JS直接更新到上述容器中。

验证功能

启动Rails服务器,提交链接后,页面不会刷新,检测结果会直接显示在表单下方的url-check-result容器内。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 07:45:38