在 Rails 中如何在使用 javascript_include_tag 之前检查 javascript 文件是不是存在

Posted

技术标签:

【中文标题】在 Rails 中如何在使用 javascript_include_tag 之前检查 javascript 文件是不是存在【英文标题】:In Rails how to check if javascript file exists before using javascript_include_tag在 Rails 中如何在使用 javascript_include_tag 之前检查 javascript 文件是否存在 【发布时间】:2012-10-01 11:32:00 【问题描述】:

在 rails 3.2 应用程序中,我想在文件中包含 javascript_include_tag 之前检查资产管道中是否存在 javascript 文件。比如:

<% if javascript_file_exists? %>
  <%= javascript_include_tag "#controller_name_controller" %>
<% end %>

我想这样做,以便没有 javascript 文件不会导致错误。有没有办法做到这一点?

【问题讨论】:

类似..什么?为什么需要它? 修复了这个问题,并添加了动机。谢谢! 【参考方案1】:

更多的 Rails 方法是使用助手。这允许您检查文件的咖啡脚本或 javascript 版本:

def javascript_exists?(script)
  script = "#Rails.root/app/assets/javascripts/#params[:controller].js"
  File.exists?(script) || File.exists?("#script.coffee") 
end

然后你可以在你的布局中使用它:

<%= javascript_include_tag params[:controller], :media => "all"  if javascript_exists?(params[:controller]) %>

你可以对你的 CSS 做同样的事情:

 -- helper --
 def stylesheet_exists?(stylesheet)
   stylesheet = "#Rails.root/app/assets/stylesheets/#params[:controller].css"
   File.exists?(stylesheet) || File.exists?("#stylesheet.scss") 
 end

 -- layout --
 <%= stylesheet_link_tag params[:controller], :media => "all"  if stylesheet_exists?(params[:controller]) %>

编辑:更新了#javascript_exists?

我最近对我的javascript_exists? 助手进行了一些更改:

def javascript_exists?(script)
  script = "#Rails.root/app/assets/javascripts/#script.js"
  extensions = %w(.coffee .erb .coffee.erb) + [""]
  extensions.inject(false) do |truth, extension|
    truth || File.exists?("#script#extension")
  end
end

在应用布局中调用它:

<%= javascript_include_tag params[:controller]  if javascript_exists?(params[:controller]) %>

现在这将处理更多扩展名并使用注入来确定文件是否存在。然后,您可以根据应用的需要向 extensions 数组添加更多扩展。

EDIT DEUX:更新了#stylesheet_exists?

相同,但对于样式表:

def stylesheet_exists?(stylesheet)
  stylesheet = "#Rails.root/app/assets/stylesheets/#stylesheet.css"
  extensions = %w(.scss .erb .scss.erb) + [""]
  extensions.inject(false) do |truth, extension|
    truth || File.exists?("#stylesheet#extension")
  end
end

最后编辑(可能):擦干

def asset_exists?(subdirectory, filename)
  File.exists?(File.join(Rails.root, 'app', 'assets', subdirectory, filename))
end

def image_exists?(image)
  asset_exists?('images', image)
end

def javascript_exists?(script)
  extensions = %w(.coffee .erb .coffee.erb) + [""]
  extensions.inject(false) do |truth, extension|
    truth || asset_exists?('javascripts', "#script.js#extension")
  end
end

def stylesheet_exists?(stylesheet)
  extensions = %w(.scss .erb .scss.erb) + [""]
  extensions.inject(false) do |truth, extension|
    truth || asset_exists?('stylesheets', "#stylesheet.css#extension")
  end
end

【讨论】:

这在 Rails 6 中仍然有效/实用吗? @Jake 你告诉我。我已经很多年没有做过 Rails 了。我现在是一名数据工程师。【参考方案2】:

虽然我知道 application.js 中的资产管道和清单,但我的方法是在 application.js 中保留应用程序的“基本”javascript,并使用

仅加载每个控制器的特定 javascript
<%= javascript_include_tag "application" %> 
<%= javascript_include_tag controller_name if File.exists?("#Rails.root/app/assets/javascripts/#controller_name.js") %>

在我的 application.html.erb 的末尾,在

【参考方案3】:

我知道这是一个很老的问题,但我建议使用 find_asset 函数。对于 Rails 4,您可以执行以下操作:

<%= javascript_include_tag params[:controller] if ::Rails.application.assets.find_asset("#params[:controller].js") %>

【讨论】:

好主意。这可能取决于 Rails 的版本或我们的偏好,但对于 4 及更高版本,我会使用 controller_name 而不是 params[:controller](以及 action_name,因为特定于页面的 js 文件之间的联系要紧密得多到动作而不是控制器)。 适用于最新的 Ruby 2.2.1 和 Rails 4.2.3。如果需要,您甚至可以省略 .js 扩展名。默认模板不再添加 .js(我的 JS 文件现在只有 .coffee 扩展名),但如果添加,Rails 仍会识别它。【参考方案4】:

自定义 ViewHelpers 救援!

将此添加到您的ApplicationHelper

module ApplicationHelper
  def controller_stylesheet(opts =  media: :all )
    if Rails.application.assets.find_asset("#controller_name.css")
      stylesheet_link_tag(controller_name, opts)
    end
  end

  def controller_javascript(opts = )
    if Rails.application.assets.find_asset("#controller_name.js")
      javascript_include_tag(controller_name, opts)
    end
  end
end

您可以在application.html.erb 中像这样使用它们:

<%= controller_stylesheet %>
<%= controller_javascript %>

注意:这适用于所有 .js、.coffee、.css、.scss,即使它只是说 .css 和 .js

【讨论】:

不应使用params[:controller]。而是controller.controller_name 描述的here 仅供参考,这适用于 Rails 6 / Ruby 3【参考方案5】:

在 Rails3.2 中,您只需在 application.js 文件的顶部写入 js 文件列表。例如,

//=require jquery.min
//=require jquery_ujs
//=require general

如果其中一个文件确实不存在(顺便说一句,将它们放在 app/assets/javascripts 中)- 没问题,不会显示任何错误。

【讨论】:

那么通过asset pipeline,每个控制器是否会自动加载manifest文件中指定的与控制器同名的js文件。 IE。 users_controller.rb 会加载 users_controller.js 吗? 此外,您不需要在视图中指定 javascript_include_tag 吗? 不,您必须将//=require users.js 写入application.js。只有这样才能访问 users.js 中的所有逻辑。 在您的布局中输入&lt;%= javascript_include_tag "application" %&gt;。见railscasts.com/episodes/279-understanding-the-asset-pipeline @alex 的方法会用这个users.js 重载EVERY 视图。最好只做你上面做的事情,然后询问Rails.application.assets文件是否存在如果要渲染它。【参考方案6】:

捕捉错误:

    #/app/helpers/application_helpers.rb

    def javascript_include_tag_if_assets(*args)
      javascript_include_tag(*args)
    rescue Sprockets::Rails::Helper::AssetNotFound
      ''
    end

另外,由于这要求在使用该方法之前进行检查,javascript_include_tag 使用javascript_path,因此您不妨使用它来检查然后捕获该错误。这适用于所有类似 javascript 的资产。对于类似 css 的资产,请使用 stylesheet_path

    #/app/helpers/application_helpers.rb

    def javascript_include_tag_if_assets(*files, **opts)
      files.each  |file| javascript_path(file) 
      javascript_include_tag(*files, **opts)
    rescue Sprockets::Rails::Helper::AssetNotFound
      ''
    end

【讨论】:

以上是关于在 Rails 中如何在使用 javascript_include_tag 之前检查 javascript 文件是不是存在的主要内容,如果未能解决你的问题,请参考以下文章

Rails如何检测是不是使用javascript / jQuery插入了部分

如何使用 AJAX 请求将用户在类变量中的 HTML5 位置从 JavaScript 传递到 Rails 控制器?

如何在 ruby​​ on rails 和 javascript 中使用 data-post 接收数据

如何在 ruby​​ on rails 中访问 rails 助手和嵌入资产 javascript 文件中的 ruby​​?

如何使用 Rails 代码/将变量传递给 .coffee javascript 文件?

Rails - 如何向用 javascript 创建的表单添加 CSRF 保护?