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

眉间皱痕 提交于 2019-12-22 05:15:08

问题


In a rails 3.2 app, I would like to check for the existence of a javascript file in the asset pipeline before including the javascript_include_tag in a file. Something like:

<% if javascript_file_exists? %>
  <%= javascript_include_tag "#{controller_name}_controller" %>
<% end %>

I would like to do this so that the absence of a javascript file will not result in an error. Is there a way to do this?


回答1:


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



回答2:


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.




回答3:


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") %>



回答4:


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.




回答5:


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




回答6:


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


来源:https://stackoverflow.com/questions/12828767/in-rails-how-to-check-if-javascript-file-exists-before-using-javascript-include

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!