Using Rails 3.1, where do you put your “page speci

2018-12-31 14:27发布

To my understanding, all of your JavaScript gets merged into 1 file. Rails does this by default when it adds //= require_tree . to the bottom of your application.js manifest file.

This sounds like a real life-saver, but I am a little concerned about page-specific JavaScript code. Does this code get executed on every page? The last thing I want is for all of my objects to be instantiated for every page when they are only needed on 1 page.

Also, isn't there potential for code that clashes too?

Or do you put a small script tag at the bottom of the page that just calls into a method that executes the javascript code for the page?

Do you no longer need require.js then?

Thanks

EDIT: I appreciate all the answers... and I don't think they are really getting at the problem. Some of them are about styling and don't seem to relate... and others just mention javascript_include_tag... which I know exists (obviously...) but it would appear that the Rails 3.1 way going forward is to wrap up all of your JavaScript into 1 file rather than loading individual JavaScript at the bottom of each page.

The best solution I can come up with is to wrap certain features in div tags with ids or classes. In the JavaScript code, you just check if the id or class is on the page, and if it is, you run the JavaScript code that is associated with it. This way if the dynamic element is not on the page, the JavaScript code doesn't run - even though it's been included in the massive application.js file packaged by Sprockets.

My above solution has the benefit that if a search box is included on 8 of the 100 pages, it will run on only those 8 pages. You also won't have to include the same code on 8 of the pages on the site. In fact, you'll never have to include manual script tags on your site anywhere ever again.

I think this is the actual answer to my question.

29条回答
只若初见
2楼-- · 2018-12-31 15:01

I see that you've answered your own question, but here's another option:

Basically, you're making the assumption that

//= require_tree .

is required. It's not. Feel free to remove it. In my current application, the first I'm doing with 3.1.x honestly, I've made three different top level JS files. My application.js file only has

//= require jquery
//= require jquery_ujs
//= require_directory .
//= require_directory ./api
//= require_directory ./admin

This way, I can create subdirectories, with their own top level JS files, that only include what I need.

The keys are:

  1. You can remove require_tree - Rails lets you change the assumptions it makes
  2. There's nothing special about the name application.js - any file in the assets/javascript subdirectory can include pre-processor directives with //=

Hope that helps and adds some details to ClosureCowboy's answer.

Sujal

查看更多
孤独寂梦人
3楼-- · 2018-12-31 15:01
<%= javascript_include_tag params[:controller] %>
查看更多
唯独是你
4楼-- · 2018-12-31 15:02

I don't see an answer that really puts it all together and lays it out for you. Thus, I'll try to put meleyal, sujal (a la ClosureCowboy), the first part of Ryan's answer, and even Gal's bold statement about Backbone.js... all together in a way that is short and clear. And, who knows, I might even meet Marnen Laibow-Koser's requirements.

Example edits

assets/javascripts/application.js

//= require jquery
//= require jquery_ujs
//= require lodash.underscore.min
...


views/layouts/application.html.erb

  ...
  </footer>

  <!-- Javascripts ================================================== -->
  <!-- Placed at the end of the document so the pages load faster -->
  <%= javascript_include_tag "application" %>
  <%= yield :javascript %>

</body>
</html>


views/foo/index.html.erb

...
<% content_for :javascript do %>
  <%= javascript_include_tag params[:controller] %>
<% end %>


assets/javascripts/foo.js

//= require moment
//= require_tree ./foostuff


assets/javascripts/foostuff/foothis.js.coffee

alert "Hello world!"


Brief description

  • Remove //= require_tree . from application.js and list only the JS that each page shares.

  • The two lines shown above in application.html.erb tell the page where to include application.js and your page-specific JS.

  • The three lines shown above in index.html.erb tells your view to look for some page-specific JS and include it at a named yield region called ":javascript" (or whatever you want to name it). In this example, the controller is "foo" so Rails will attempt to include "foo.js" at the :javascript yield region in the application layout.

  • List your page-specific JS in foo.js (or whatever the controller is named). List common libraries, a tree, directories, whatever.

  • Keep your custom page-specific JS someplace where you can easily reference it apart from your other custom JS. In this example, foo.js requires the foostuff tree so put your custom JS there, such as foothis.js.coffee.

  • There are no hard rules here. Feel free to move things around and perhaps even create multiple yield regions of various names in various layouts if needed. This just shows one possible first step forward. (I don't do it exactly like this given our use of Backbone.js. I might also choose to drop foo.js down into a folder called foo instead of foostuff but haven't decided that yet.)

Notes

You can do similar things with CSS and <%= stylesheet_link_tag params[:controller] %> but this is beyond scope of the question.

If I missed a glaring best practice here, send me a note and I'll conisder adapting. Rails is fairly new to me and, honestly, I'm not terribly impressed so far with the chaos it brings by default to enterprise development and all the traffic the average Rails program generates.

查看更多
冷夜・残月
5楼-- · 2018-12-31 15:03

I appreciate all the answers... and I don't think they are really getting at the problem. Some of them are about styling and don't seem to relate... and others just mention javascript_include_tag... which I know exists (obviously...) but it would appear that the Rails 3.1 way going forward is to wrap up all of your Javascript into 1 file rather than loading individual Javascript at the bottom of each page.

The best solution I can come up with is to wrap certain features in div tags with ids or classes. In the javascript code. Then you just check if the id or class is on the page, and if it is, you run the javascript code that is associated with it. This way if the dynamic element is not on the page, the javascript code doesn't run - even though it's been included in the massive application.js file packaged by Sprockets.

My above solution has the benefit that if a search box is included on 8 of the 100 pages, it will run on only those 8 pages. You also won't have to include the same code on 8 of the pages on the site. In fact, you'll never have to include manual script tags on your site anywhere ever again - except to maybe preload data.

I think this is the actual answer to my question.

查看更多
旧时光的记忆
6楼-- · 2018-12-31 15:03

First: remove \\=require_treefrom application.js Second: all your JS code must be alocated at /app/assets/javascritpt and all your CSS code must be alocated at /app/assets/stylesheets

查看更多
素衣白纱
7楼-- · 2018-12-31 15:05

Another option: to create page- or model-specific files, you could create directories inside your assets/javascripts/ folder.

assets/javascripts/global/
assets/javascripts/cupcakes
assets/javascripts/something_else_specific

Your main application.js manifest file could be configured to load its files from global/. Specific pages or groups of pages could have their own manifests which load files from their own specific directories. Sprockets will automatically combine the files loaded by application.js with your page-specific files, which allows this solution to work.

This technique can be used for style_sheets/ as well.

查看更多
登录 后发表回答