Search code examples
javascriptruby-on-railsbackbone.jscoffeescriptbackbone-routing

Facing issues in Backbone With Rails 3.x, for multiple routers


In one of the rails app I am trying to use backbone with "rails-backbone" gem, And I have created one model using scaffolding which is working fine. but I have another model and I am trying to use different router for it, but when tries to instantiate that router from index.html.erb it fires, "Uncaught TypeError: undefined is not a function" which clearly means there is no such router. But it is there and even in developer's tool it shows those JS files. I tried all different ways but it didn't work. Thanks in advance.


Solution

  • I'd guess that you're defining your router like this:

    class SomeRouter extends Backbone.Router
      # router code goes here
    

    and then you're trying to create one with:

    r = new SomeRouter
    

    But CoffeeScript will wrap your files in a function to prevent scope creep:

    Although suppressed within this documentation for clarity, all CoffeeScript output is wrapped in an anonymous function: (function(){ ... })(); This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult to pollute the global namespace by accident.

    If you'd like to create top-level variables for other scripts to use, attach them as properties on window, or on the exports object in CommonJS. The existential operator (covered below), gives you a reliable way to figure out where to add them; if you're targeting both CommonJS and the browser: exports ? this

    That wrapper will hide SomeRouter inside a function so there will be no SomeRouter visible outside the file which defines it.

    A common solution in Rails/Backbone apps is to manage the namespaces yourself. Set up your own namespace somewhere before any other (Java|Coffee)Script will be pulled in:

    # AppName is just a placeholder, you'd use something more
    # sensible in real life.
    window.AppName =
        Routers:     { }
        Views:       { }
        Models:      { }
        Collections: { }
    

    and then define your router as:

    class AppName.Routers.SomeRouter extends Backbone.Router
        #...
    

    and later:

    r = new AppName.Routers.SomeRouter
    

    similarly with models, collections, and views that need to be globally visible.