简体   繁体   中英

Rails inline Javascript and Best Practices

I'm kinda new to using Rails, and an app I am working on is progressing well - however I'm looking though the generated HTML and noticed things like...

<script type="text/javascript">
//<![CDATA[
Droppables.add(...);
//]]>
</script>

Sprinkled around the HTML, which of course matches up with places where I use:

<%= drop_receiving_element ... %>

What I'm wondering is... is there a better way to do this, or make it cleaner? Some of these script tags are coming from partials so putting them at the 'bottom of the page' doesn't really help in this situation.

Another option may be pushing all these 'tag blocks' into an array then writing them out in the application.rhtml file, but its still a bit messy...

Well if you really want to use best practices...Do not use inline javascript. Keep your HTML, CSS and Javascript clean and seperated from eachother. Ideally the html file should be usable without CSS and javascript.

The cleanest way, imo, is to just build your app using plain html/css, and enhance it with unobtrusive javascript to provide a better user experience.

A pattern for this is to include all your JS files at the bottom of your page, and start running your code with functionality like onDomReady.

Based on the comments I would like to add some possible options to get you started:

  • JQuery
  • YUI
  • Prototype

Best practice is to remove all inline javascript. However, there are 3 cases that I've run into where you absolutely need inline javascript:

1. To resolve image errors

If an image tag is referencing an image path that doesn't exist, the only way to prevent the image error from appearing (even in the web inspector) is to do this:

<img src="/i/dont/exist.png" onerror="$(this).attr("src", "/i/do/exist.png")" />

The following doesn't work because the onerror event is executed before you even have time to grab the image with jQuery:

$("img").error(function() {
  $(this).attr("src", "/i/do/exist.png")
});

The code below doesn't work either because the onerror event doesn't bubble:

$("img").live("error", function() {
  $(this).attr("src", "/i/do/exist.png");
});

So you have to use inline javascript for that.

2. To render javascript templates as the page loads

If you wait until $(document).ready to draw your feed of content into one of the empty container elements in your dom, the user will see the blank spot for a split second. This is why when your Twitter page first loads, the feed is blank for an instant. Even if you just put an external script file at the bottom of the dom, and in there you append the dynamically generated html elements to your page without even using $(document).ready , it's still too late. You have to append the dynamic nodes immediately after the container element is added:

<script>App.bootstrap({some: "json"});</script>
<nav id='navigation'></nav>
<header id='header'></header>
<section id='content'>
  // dynamic content here
</section>
<script>App.renderContent();</script>
<aside id='sidebar'>
  // dynamically toggle which one is selected with javascript
  <nav>
    <h3>Search By Category</h3>
    <ol>
      <li>
        <a href="/category-a">Category A</a>
      </li>
      <li>
        <a href="/category-b">Category B</a>
      </li>
    </ol>
  </nav>
</aside>
<script>App.renderSidebar();</script>
<footer id='footer'></footer>

3. You're bootstrapping your app with JSON

If you're using JSON + javascript templates, it's a good idea to bootstrap the first set of data into the response body by including it inline in the page (in the above dom example too). That makes it so you don't need an additional ajax request to render content.

Everything else should be done with Unobtrusive Javascript

Rails has a lot of javascript helpers, and thankfully in Rails 3 most (all?) of it is unobtrusive; they're now using the data- attribute and an external rails.js file. However, many of the gems out there that are part-ruby part-javascript tend to still write helper methods add complex javascript inline:

That's helpful, but I think just having a clear README describing how to add the javascript to your application.js is even more useful. External javascript makes it a lot easier to customize/extend the functionality down the road, it gives you a lot more control over the system, and it minimizes duplication across your html pages (so the response body is smaller, and the browser can cache external javascript files). Unless you need to handle missing images, instantaneous rendering, or bootstrap some json, you can put everything else in external javascript files and never have to use Rails javascript/ajax helpers.

Sometimes inline JavaScript is useful for critical, fast views (eg, certain landing pages), or small snippets (eg, Facebook SDK initialization, Analytics/Kissmetrics initialization scripts, etc.) where using no external libraries can speed up page load. For those cases, I recommend using a partial _facebook.js.erb inside layouts, and define a helper:

module ApplicationHelper
  def facebook_tag
    content_tag :script, render(partial: 'layouts/facebook.js')
  end
end

Then, create the file _facebook.js.erb and include the inline JavaScript inside application.html.erb using the defined helper:

<%= facebook_tag %>

For any other case, such as the partials you mention that inline JavaScript, I recommend using unobtrusive JavaScript as other answers suggest.

This bothered me for a while and I eventually came up with a two pronged approach.

If you are developing a web application for a closed domain, where search engine performance and javascript are not an issue, just be pragmatic and let Rails' javascript helpers do their thing.

If you are developing for the web at large then do what Tomh sugested and code in plain html/css and then enhance onDomReady.

If you still want to use Rails helpers like button_to_remote that use inline javascript, then code your page load handler to send an Ajax request to the server. you can then use page.replace / page.replace_html to replace your regular page elements with code returned from the helpers.

I'd also recommend going with the unobtrusive Javascript approach and use jQuery .

For a great introductory tutorial on how to do that with Rails take a look at this jQuery + Rails screencast by Ryan Bates .

If you'd like to keep using helpers with jQuery, then take a look at a jRails , but if you do that, you'll still be violating the unobtrusive Javascript premise.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM