问题
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