Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 924
John Avatar asked Oct 10 '12 21:10

John


4 Answers

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
like image 187
WattsInABox Avatar answered Nov 20 '22 13:11

WattsInABox


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.

like image 25
hisa_py Avatar answered Nov 20 '22 13:11

hisa_py


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") %>
like image 5
Fernando Rybka Avatar answered Nov 20 '22 14:11

Fernando Rybka


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

like image 2
Sheharyar Avatar answered Nov 20 '22 15:11

Sheharyar