In Rails how to check if javascript file exists before using javascript_include_tag

你。 提交于 2019-12-05 07:28:35

A more Rails way is to use a helper. This allows you to check for a coffeescript or a javascript version of a file:

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

Then you can use it in your layout:

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

You can do the same with your 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]) %>


EDIT: updated #javascript_exists?

I have recently made some changes to my javascript_exists? helper:

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

call it in the application layout:

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

This will now handle more extensions and use an inject to determine if the file exists. You can then add a bunch more extensions to the extensions array, as needed for your app.


EDIT DEUX: Updated #stylesheet_exists?

Same, but for stylesheets:

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


EDIT Last (probably): DRY it up

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

Although I know about the assets pipeline and the manifest in application.js, my approach is to keep app's "essential" javascript in application.js and load only the specific javascript for each controller using

<%= javascript_include_tag "application" %> 
<%= javascript_include_tag controller_name if File.exists?("#{Rails.root}/app/assets/javascripts/#{controller_name}.js") %>

at the end of my application.html.erb before the </body>

I know that causes the browser to issue one more request to get the controller specific javascript but perhaps after the first request, that javascript will be cached by the browser.

I know this is a pretty old question, but I would suggest using the find_asset function. For Rails 4 you could do something like:

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

In Rails3.2 all what you need is to write the list of your js files at the top of application.js file. For example,

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

If one of these files don't really exists (btw put them at app/assets/javascripts) - not a problem, no errors will be shown.

Custom ViewHelpers to the Rescue!

Add this to your 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

and you can use them like this in your application.html.erb:

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

Note: This works with all .js, .coffee, .css, .scss even though it just says .css and .js

Catch the error:

    #/app/helpers/application_helpers.rb

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

Alternatively, since this asks to check before using the method, javascript_include_tag uses javascript_path so you might as well use it to check and then catch that error. This works for all javascript-like assets. For css-like assets, use 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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!