Search code examples
javascriptruby-on-railsrubyurl-routing

including external JS for a specific view in Rails


I am trying to use Ruby on Rails to build my first website.

I have read about the asset pipeline and I have a specific view that needs to reference 3 JS libraries that no other files need to reference.

I don't want to use them as require directives in the assets/javascripts manifest because than they would end up on all of the other pages that don't need them.

So, I thought I could simply include them in the view template.


However, I am getting 404: file not found errors.

This is how I am including them in the template /app/views/welcome/index.html.erb:

<%= javascript_include_tag "/lib/assets/javascripts/three.js" %>          
<%= javascript_include_tag "/lib/assets/javascripts/perlin.js" %>
<%= javascript_include_tag "/lib/assets/javascripts/cube.js" %>

This is being rendered as the first lines inside of <body> tags (this is because the code in the template is rendered according to a yield tag in /app/views/layouts/application.html.erb and that yield tag is placed inside body tags)

As you can see, the files are located in lib/assets/javascripts and I am trying to access them by using the full path (relative to the web-root).


This is an example of an error message that gets generated on the server when trying to render one of the libraries:

Started GET "/lib/assets/javascripts/three.js" for 127.0.0.1 at 2015-03-15 11:30:52 -0400

ActionController::RoutingError (No route matches [GET] "/lib/assets/javascripts/three.js"):
  actionpack (4.2.0) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
  web-console (2.1.0) lib/web_console/middleware.rb:37:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  railties (4.2.0) lib/rails/rack/logger.rb:38:in `call_app'
  railties (4.2.0) lib/rails/rack/logger.rb:20:in `block in call'
  activesupport (4.2.0) lib/active_support/tagged_logging.rb:68:in `block in tagged'
  activesupport (4.2.0) lib/active_support/tagged_logging.rb:26:in `tagged'
  activesupport (4.2.0) lib/active_support/tagged_logging.rb:68:in `tagged'
  railties (4.2.0) lib/rails/rack/logger.rb:20:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/request_id.rb:21:in `call'
  rack (1.6.0) lib/rack/methodoverride.rb:22:in `call'
  rack (1.6.0) lib/rack/runtime.rb:18:in `call'
  activesupport (4.2.0) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
  rack (1.6.0) lib/rack/lock.rb:17:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/static.rb:113:in `call'
  rack (1.6.0) lib/rack/sendfile.rb:113:in `call'
  railties (4.2.0) lib/rails/engine.rb:518:in `call'
  railties (4.2.0) lib/rails/application.rb:164:in `call'
  rack (1.6.0) lib/rack/lock.rb:17:in `call'
  rack (1.6.0) lib/rack/content_length.rb:15:in `call'
  rack (1.6.0) lib/rack/handler/webrick.rb:89:in `service'
  /home/luke/.rbenv/versions/2.2.0/lib/ruby/2.2.0/webrick/httpserver.rb:138:in `service'
  /home/luke/.rbenv/versions/2.2.0/lib/ruby/2.2.0/webrick/httpserver.rb:94:in `run'
  /home/luke/.rbenv/versions/2.2.0/lib/ruby/2.2.0/webrick/server.rb:294:in `block in start_thread'

Edit

People are suggesting that I move my files. Can you please explain why I can't have them in lib? The docs say that lib/assets is where libs should go and I concur with this organization.

  • The /public directory thing is only kept around for backwards compatibility from what I have read (it isn't even created by default anymore)

Solution

  • Put your Javascript in /app/assets/javascripts and you'll be able to include it like this:

    <%= javascript_include_tag 'file-name' %>
    

    Please note that you shouldn't include the extension. Rails will find it for you.

    Each controller has it's own Javascript and CSS files, using them is a good idea.

    Be warned that if you add more assets, you'll have to add Rails.application.config.assets.precompile += %w( [file name] ) to config/initializers/assets.rb and restart your server

    Libs isn't exactly for what you think, and using public is a bad idea... It's best just to put it in /app/assets/javascripts, as I've said.