Module Merb::AssetsMixin
In: merb-assets/lib/merb-assets/assets_mixin.rb

The AssetsMixin module provides a number of helper methods to views for linking to assets and other pages, dealing with JavaScript and CSS.

Included Modules

Accessing Assets

Merb provides views with convenience methods for links images and other assets.

Public Instance methods

Parameters

none

Returns

html<String>

Examples

 We want all possible matches in the FileSys up to the action name
    Given:  controller_name = "namespace/controller"
            action_name     = "action"
 If all files are present should generate link/script tags for:
    namespace.(css|js)
    namespace/controller.(css|js)
    namespace/controller/action.(css|js)

[Source]

    # File merb-assets/lib/merb-assets/assets_mixin.rb, line 26
26:     def auto_link
27:       html    = ""
28:       prefix  = ""
29:       (controller_name / action_name).split("/").each do |path|
30:         path = prefix + path
31: 
32:         css_path  = path + ".css"
33:         if File.exists? Merb.root / "public" / "stylesheets" / css_path
34:           html << %{<link rel="stylesheet" type="text/css" href="/stylesheets/#{css_path}" /> }
35:         end
36: 
37:         js_path   = path + ".js"
38:         if File.exists? Merb.root / "public" / "javascripts" / js_path
39:           html << %{<script type="text/javascript" language="javascript" src="/javascripts/#{js_path}"></script>}
40:         end
41: 
42:         #Update the prefix for the next iteration
43:         prefix += path / ""
44:       end
45: 
46:       #Return the generated HTML
47:       html
48:     end

Parameters

img<~to_s>:The image path.
opts<Hash>:Additional options for the image tag (see below).

Options (opts)

:path<String>:Sets the path prefix for the image. Defaults to "/images/" or whatever is specified in Merb::Config. This is ignored if img is an absolute path or full URL.

All other options set HTML attributes on the tag.

Examples

  image_tag('foo.gif')
  # => <img src='/images/foo.gif' />

  image_tag('foo.gif', :class => 'bar')
  # => <img src='/images/foo.gif' class='bar' />

  image_tag('foo.gif', :path => '/files/')
  # => <img src='/files/foo.gif' />

  image_tag('http://test.com/foo.gif')
  # => <img src="http://test.com/foo.gif">

  image_tag('charts', :path => '/dynamic/')
  or
  image_tag('/dynamic/charts')
  # => <img src="/dynamic/charts">

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 100
100:     def image_tag(img, opts={})
101:       if img[0].chr == '/'
102:         opts[:src] = img
103:       else
104:         opts[:path] ||=
105:           if img =~ %r{^https?://}
106:             ''
107:           else
108:             if Merb::Config[:path_prefix]
109:               Merb::Config[:path_prefix] + '/images/'
110:             else
111:               '/images/'
112:             end
113:           end
114:         opts[:src] ||= opts.delete(:path) + img
115:       end
116:       random = opts.delete(:reload) || Merb::Config[:reload_templates]
117:       opts[:src] += opts[:src].include?('?') ? "&#{random_query_string}" : "?#{random_query_string}" if random
118:       %{<img #{ opts.to_xml_attributes } />}
119:     end

Parameters

name<~to_s>:The text of the link.
url<~to_s>:The URL to link to. Defaults to an empty string.
opts<Hash>:Additional HTML options for the link.

Examples

  link_to("The Merb home page", "http://www.merbivore.com/")
    # => <a href="http://www.merbivore.com/">The Merb home page</a>

  link_to("The Ruby home page", "http://www.ruby-lang.org", {'class' => 'special', 'target' => 'blank'})
    # => <a href="http://www.ruby-lang.org" class="special" target="blank">The Ruby home page</a>

  link_to p.title, "/blog/show/#{p.id}"
    # => <a href="/blog/show/13">The Entry Title</a>

[Source]

    # File merb-assets/lib/merb-assets/assets_mixin.rb, line 66
66:     def link_to(name, url='', opts={})
67:       opts[:href] ||= url
68:       %{<a #{ opts.to_xml_attributes }>#{name}</a>}
69:     end

JavaScript related functions

Public Instance methods

Parameters

javascript<String>:Text to escape for use in JavaScript.

Examples

  escape_js("'Lorem ipsum!' -- Some guy")
    # => "\\'Lorem ipsum!\\' -- Some guy"

  escape_js("Please keep text\nlines as skinny\nas possible.")
    # => "Please keep text\\nlines as skinny\\nas possible."

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 133
133:     def escape_js(javascript)
134:       (javascript || '').gsub('\\','\0\0').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
135:     end

Parameters

data<Object>:Object to translate into JSON. If the object does not respond to :to_json, then data.inspect.to_json is returned instead.

Examples

  js({'user' => 'Lewis', 'page' => 'home'})
   # => "{\"user\":\"Lewis\",\"page\":\"home\"}"

  js([ 1, 2, {"a"=>3.141}, false, true, nil, 4..10 ])
    # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 148
148:     def js(data)
149:       if data.respond_to? :to_json
150:         data.to_json
151:       else
152:         data.inspect.to_json
153:       end
154:     end

External JavaScript and Stylesheets

You can use require_js(:prototype) or require_css(:shinystyles) from any view or layout, and the scripts will only be included once in the head of the final page. To get this effect, the head of your layout you will need to include a call to include_required_js and include_required_css.

Examples

  # File: app/views/layouts/application.html.erb

  <html>
    <head>
      <%= include_required_js %>
      <%= include_required_css %>
    </head>
    <body>
      <%= catch_content :layout %>
    </body>
  </html>

  # File: app/views/whatever/_part1.herb

  <% require_js  'this' -%>
  <% require_css 'that', 'another_one' -%>

  # File: app/views/whatever/_part2.herb

  <% require_js 'this', 'something_else' -%>
  <% require_css 'that' -%>

  # File: app/views/whatever/index.herb

  <%= partial(:part1) %>
  <%= partial(:part2) %>

  # Will generate the following in the final page...
  <html>
    <head>
      <script src="/javascripts/this.js" type="text/javascript"></script>
      <script src="/javascripts/something_else.js" type="text/javascript"></script>
      <link href="/stylesheets/that.css" media="all" rel="Stylesheet" type="text/css"/>
      <link href="/stylesheets/another_one.css" media="all" rel="Stylesheet" type="text/css"/>
    </head>
    .
    .
    .
  </html>

See each method‘s documentation for more information.

Bundling Asset Files

The key to making a fast web application is to reduce both the amount of data transfered and the number of client-server interactions. While having many small, module Javascript or stylesheet files aids in the development process, your web application will benefit from bundling those assets in the production environment.

An asset bundle is a set of asset files which are combined into a single file. This reduces the number of requests required to render a page, and can reduce the amount of data transfer required if you‘re using gzip encoding.

Asset bundling is always enabled in production mode, and can be optionally enabled in all environments by setting the :bundle_assets value in config/merb.yml to true.

Examples

In the development environment, this:

  js_include_tag :prototype, :lowpro, :bundle => true

will produce two <script> elements. In the production mode, however, the two files will be concatenated in the order given into a single file, all.js, in the public/javascripts directory.

To specify a different bundle name:

  css_include_tag :typography, :whitespace, :bundle => :base
  css_include_tag :header, :footer, :bundle => "content"
  css_include_tag :lightbox, :images, :bundle => "lb.css"

(base.css, content.css, and lb.css will all be created in the public/stylesheets directory.)

Callbacks

To use a Javascript or CSS compressor, like JSMin or YUI Compressor:

  Merb::Assets::JavascriptAssetBundler.add_callback do |filename|
    system("/usr/local/bin/yui-compress #{filename}")
  end

  Merb::Assets::StylesheetAssetBundler.add_callback do |filename|
    system("/usr/local/bin/css-min #{filename}")
  end

These blocks will be run after a bundle is created.

Bundling Required Assets

Combining the require_css and require_js helpers with bundling can be problematic. You may want to separate out the common assets for your application — Javascript frameworks, common CSS, etc. — and bundle those in a "base" bundle. Then, for each section of your site, bundle the required assets into a section-specific bundle.

N.B.: If you bundle an inconsistent set of assets with the same name, you will have inconsistent results. Be thorough and test often.

Example

In your application layout:

  js_include_tag :prototype, :lowpro, :bundle => :base

In your controller layout:

  require_js :bundle => :posts

Public Instance methods

Parameters

*stylesheets:The stylesheets to include. If the last element is a Hash, it will be used as options (see below). If ".css" is left out from the stylesheet names, it will be added to them.

Options

:bundle<~to_s>:The name of the bundle the stylesheets should be combined into.
:media<~to_s>:The media attribute for the generated link element. Defaults to :all.

Returns

String:The CSS include tag(s).

Examples

  css_include_tag 'style'
  # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />

  css_include_tag 'style.css', 'layout'
  # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
  #    <link href="/stylesheets/layout.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />

  css_include_tag :menu
  # => <link href="/stylesheets/menu.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />

  css_include_tag :style, :screen
  # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
  #    <link href="/stylesheets/screen.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />

 css_include_tag :style, :media => :print
 # => <link href="/stylesheets/style.css" media="print" rel="Stylesheet" type="text/css" charset="utf-8" />

 css_include_tag :style, :charset => 'iso-8859-1'
 # => <link href="/stylesheets/style.css" media="print" rel="Stylesheet" type="text/css" charset="iso-8859-1" />

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 491
491:     def css_include_tag(*stylesheets)
492:       options = stylesheets.last.is_a?(Hash) ? stylesheets.pop : {}
493:       return nil if stylesheets.empty?
494: 
495:       reload = options[:reload] || Merb::Config[:reload_templates]
496: 
497:       if (bundle_name = options[:bundle]) && Merb::Assets.bundle? && stylesheets.size > 1
498:         bundler = Merb::Assets::StylesheetAssetBundler.new(bundle_name, *stylesheets)
499:         bundled_asset = bundler.bundle!
500:         return css_include_tag(bundled_asset)
501:       end
502: 
503:       tags = ""
504: 
505:       for stylesheet in stylesheets
506:         href = asset_path(:stylesheet, stylesheet)
507:         href += href.include?('?') ? "&#{random_query_string}" : "?#{random_query_string}" if reload
508:         attrs = {
509:           :href => href,
510:           :type => "text/css",
511:           :rel => "Stylesheet",
512:           :charset => options[:charset] || 'utf-8',
513:           :media => options[:media] || :all
514:         }
515:         tags << %Q{<link #{attrs.to_xml_attributes} />}
516:       end
517: 
518:       return tags
519:     end

A method used in the layout of an application to create +<link>+ tags for CSS stylesheets required in in templates and subtemplates using require_css.

Parameters

options<Hash>:Options to pass to css_include_tag.

Returns

String:The CSS tag.

Options

:bundle<~to_s>:The name of the bundle the stylesheets should be combined into.
:media<~to_s>:The media attribute for the generated link element. Defaults to :all.

Examples

  # my_action.herb has a call to require_css 'style'
  # File: layout/application.html.erb
  include_required_css
  # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>

  # my_action.herb has a call to require_css 'style', 'ie-specific'
  # File: layout/application.html.erb
  include_required_css
  # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
  #    <link href="/stylesheets/ie-specific.css" media="all" rel="Stylesheet" type="text/css"/>

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 397
397:     def include_required_css(options = {})
398:       required_css(options).map { |req_js| css_include_tag(*req_js) }.join
399:     end

A method used in the layout of an application to create +<script>+ tags to include JavaScripts required in in templates and subtemplates using require_js.

Parameters

options<Hash>:Options to pass to js_include_tag.

Options

:bundle<~to_s>:The name of the bundle the scripts should be combined into.

Returns

String:The JavaScript tag.

Examples

  # my_action.herb has a call to require_js 'jquery'
  # File: layout/application.html.erb
  include_required_js
  # => <script src="/javascripts/jquery.js" type="text/javascript"></script>

  # my_action.herb has a call to require_js 'jquery', 'effects', 'validation'
  # File: layout/application.html.erb
  include_required_js
  # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
  #    <script src="/javascripts/effects.js" type="text/javascript"></script>
  #    <script src="/javascripts/validation.js" type="text/javascript"></script>

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 365
365:     def include_required_js(options = {})
366:       required_js(options).map { |req_js| js_include_tag(*req_js) }.join
367:     end

Parameters

*scripts:The scripts to include. If the last element is a Hash, it will be used as options (see below). If ".js" is left out from the script names, it will be added to them.

Options

:bundle<~to_s>:The name of the bundle the scripts should be combined into.

Returns

String:The JavaScript include tag(s).

Examples

  js_include_tag 'jquery'
  # => <script src="/javascripts/jquery.js" type="text/javascript"></script>

  js_include_tag 'moofx.js', 'upload'
  # => <script src="/javascripts/moofx.js" type="text/javascript"></script>
  #    <script src="/javascripts/upload.js" type="text/javascript"></script>

  js_include_tag :effects
  # => <script src="/javascripts/effects.js" type="text/javascript"></script>

  js_include_tag :jquery, :validation
  # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
  #    <script src="/javascripts/validation.js" type="text/javascript"></script>

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 429
429:     def js_include_tag(*scripts)
430:       options = scripts.last.is_a?(Hash) ? scripts.pop : {}
431:       return nil if scripts.empty?
432:       
433:       reload = options[:reload] || Merb::Config[:reload_templates]
434: 
435:       if (bundle_name = options[:bundle]) && Merb::Assets.bundle? && scripts.size > 1
436:         bundler = Merb::Assets::JavascriptAssetBundler.new(bundle_name, *scripts)
437:         bundled_asset = bundler.bundle!
438:         return js_include_tag(bundled_asset)
439:       end
440: 
441:       tags = ""
442: 
443:       for script in scripts
444:         src = asset_path(:javascript, script)
445:         src += src.include?('?') ? "&#{random_query_string}" : "?#{random_query_string}" if reload
446:         attrs = {
447:           :src => src,
448:           :type => "text/javascript"
449:         }
450:         tags << %Q{<script #{attrs.to_xml_attributes}></script>}
451:       end
452: 
453:       return tags
454:     end

The require_css method can be used to require any CSS file anywhere in your templates. Regardless of how many times a single stylesheet is included with require_css, Merb will only include it once in the header.

Parameters

*css<~to_s>:CSS files to include.

Examples

  <% require_css('style') %>
  # A subsequent call to include_required_css will render...
  # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>

  <% require_css('style', 'ie-specific') %>
  # A subsequent call to include_required_css will render...
  # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
  #    <link href="/stylesheets/ie-specific.css" media="all" rel="Stylesheet" type="text/css"/>

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 325
325:     def require_css(*css)
326:       @required_css ||= []
327:       @required_css << css
328:     end

The require_js method can be used to require any JavaScript file anywhere in your templates. Regardless of how many times a single script is included with require_js, Merb will only include it once in the header.

Parameters

*js<~to_s>:JavaScript files to include.

Examples

  <% require_js 'jquery' %>
  # A subsequent call to include_required_js will render...
  # => <script src="/javascripts/jquery.js" type="text/javascript"></script>

  <% require_js 'jquery', 'effects' %>
  # A subsequent call to include_required_js will render...
  # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
  #    <script src="/javascripts/effects.js" type="text/javascript"></script>

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 295
295:     def require_js(*js)
296:       @required_js ||= []
297:       @required_js << js
298:     end

All css files to include, without duplicates.

Parameters

options<Hash>:Default options to pass to css_include_tag.

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 334
334:     def required_css(options = {})
335:       extract_required_files(@required_css, options)
336:     end

All javascript files to include, without duplicates.

Parameters

options<Hash>:Default options to pass to js_include_tag.

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 304
304:     def required_js(options = {})
305:       extract_required_files(@required_js, options)
306:     end

Parameters

*assets:Creates unique paths for stylesheet files (prepends "/stylesheets" and appends ".css")

Returns

Array:Full unique paths to assets OR
String:if only a single path is requested

Examples

 uniq_css_path("my")
 #=> "http://assets2.my-awesome-domain.com/stylesheets/my.css"

 uniq_css_path(["admin/secrets","home/signup"])
 #=> ["http://assets2.my-awesome-domain.com/stylesheets/admin/secrets.css",
        "http://assets1.my-awesome-domain.com/stylesheets/home/signup.css"]

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 587
587:     def uniq_css_path(*assets)
588:       paths = []
589:       assets.collect.flatten.each do |filename|
590:         paths.push(Merb::Assets::UniqueAssetPath.build(asset_path(:stylesheet,filename)))
591:       end
592:       paths.length > 1 ? paths : paths.first
593:     end

Parameters

*assets:As uniq_css_tag but has unique path

Returns

Array:Full unique paths to assets OR
String:if only a single path is requested

Examples

 uniq_css_tag("my")
 #=> <link href="http://assets2.my-awesome-domain.com/stylesheets/my.css" type="text/css" />

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 619
619:     def uniq_css_tag(*assets)
620:       css_include_tag(*uniq_css_path(assets))
621:     end

Parameters

*assets:Creates unique paths for javascript files (prepends "/javascripts" and appends ".js")

Returns

Array:Full unique paths to assets OR
String:if only a single path is requested

Examples

 uniq_js_path("my")
 #=> "http://assets2.my-awesome-domain.com/javascripts/my.js"

 uniq_js_path(["admin/secrets","home/signup"])
 #=> ["http://assets2.my-awesome-domain.com/javascripts/admin/secrets.js",
        "http://assets1.my-awesome-domain.com/javascripts/home/signup.js"]

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 565
565:     def uniq_js_path(*assets)
566:       paths = []
567:       assets.collect.flatten.each do |filename|
568:         paths.push(Merb::Assets::UniqueAssetPath.build(asset_path(:javascript,filename)))
569:       end
570:       paths.length > 1 ? paths : paths.first
571:     end

Parameters

*assets:As js_include_tag but has unique path

Returns

Array:Full unique paths to assets OR
String:if only a single path is requested

Examples

 uniq_js_tag("my")
 #=> <script type="text/javascript" src="http://assets2.my-awesome-domain.com/javascripts/my.js"></script>

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 605
605:     def uniq_js_tag(*assets)
606:       js_include_tag(*uniq_js_path(assets))
607:     end

Parameters

*assets:The assets to include. These should be the full paths to any static served file

Returns

Array:Full unique paths to assets OR
String:if only a single path is requested

Examples

 uniq_path("/javascripts/my.js","/javascripts/my.css")
 #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/javascripts/my.css"]

 uniq_path(["/javascripts/my.js","/stylesheets/my.css"])
 #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/stylesheets/my.css"]

 uniq_path(%w(/javascripts/my.js /stylesheets/my.css))
 #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/stylesheets/my.css"]

 uniq_path('/stylesheets/somearbitrary.css')
 #=> "http://assets3.my-awesome-domain.com/stylesheets/somearbitrary.css"

 uniq_path('/images/hostsexypicture.jpg')
 #=>"http://assets1.my-awesome-domain.com/images/hostsexypicture.jpg"

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 543
543:     def uniq_path(*assets)
544:       paths = []
545:       assets.collect.flatten.each do |filename|
546:         paths.push(Merb::Assets::UniqueAssetPath.build(filename))
547:       end
548:       paths.length > 1 ? paths : paths.first
549:     end

Private Instance methods

Helper method to filter out duplicate files.

Parameters

options<Hash>:Options to pass to include tag methods.

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 629
629:     def extract_required_files(files, options = {})
630:       return [] if files.nil? || files.empty?
631:       seen = []
632:       files.inject([]) do |extracted, req_js|
633:         include_files, include_options = if req_js.last.is_a?(Hash)
634:           [req_js[0..-2], options.merge(req_js.last)]
635:         else
636:           [req_js, options]
637:         end
638:         seen += (includes = include_files - seen)
639:         extracted << (includes + [include_options]) unless includes.empty?
640:         extracted
641:       end
642:     end

[Source]

     # File merb-assets/lib/merb-assets/assets_mixin.rb, line 644
644:     def random_query_string
645:       Time.now.strftime("%m%d%H%M%S#{rand(99)}")
646:     end