49

using Rails 3.1.0.rc4, I'm trying to access a route helper in a javascript file (event.js.erb in this case) and it seems like they are not loaded at that moment. When requesting the merged /assets/application.js file, I get:

throw Error("NameError: undefined local variable or method `events_path' for #<#<Class:0x00000001580010>:0x00000003191510>\n  (in /<...>/app/assets/javascripts/event.js.erb)")

Any idea how to access the route helper in there?

tbuehlmann
  • 9,032
  • 5
  • 27
  • 33

2 Answers2

89

UPDATE: Now there is a gem that does this for you: js-routes


The problem is that Sprockets is evaluating the ERB outside of the context of your Rails app, and most of the stuff you're expecting isn't there.

You can add things to your Sprockets context like so:

Rails.application.assets.context_class.class_eval do
  include Rails.application.routes.url_helpers
end

That's all well and good, but getting the helpers that require an id to work is a little trickier. I'm going to use a technique called a URI Template:

var event_path = "<%= CGI.unescape event_path('{event_id}') %>";

which returns /events/{event_id} which you could render into a url using an object like { event_id: 1 }. See SugarJS's String#assign method as example implementation of this. You could also roll your own like I did.

Community
  • 1
  • 1
Adam Lassek
  • 35,156
  • 14
  • 91
  • 107
  • Noob question, but how do you find the `MyRailsApp` path bit? – Mild Fuzz Mar 22 '12 at 15:22
  • 2
    @MildFuzz It's the name you gave the project when you created it. Look in `config/application.rb` if you don't remember. – Adam Lassek Mar 25 '12 at 23:37
  • 8
    Is there a better way to do it? I use this `::Rails.application.routes.url_helpers.new_user_session_path` – firedev May 12 '14 at 03:42
  • @Nick `Rails.application` vs `MyRailsApp::Application` are basically equivalent here. – Adam Lassek May 13 '14 at 22:20
  • @AdamLassek Yes, except you don't need to remember what your app is called. – firedev May 14 '14 at 10:28
  • 1
    @Nick to be honest I can't imagine that ever being a problem. – Adam Lassek May 15 '14 at 02:07
  • @Nick although I do see the value for documentation purposes, you can give people working code instead of a fake namespace. – Adam Lassek May 15 '14 at 02:22
  • This answer should be updated to include @Nick's fix. It's actually really helpful to avoid stating the name of your application. Say you have to port the code elsewhere or extract it to an engine. You should avoid referencing your own application by name as much as possible. – Justin Force May 16 '14 at 23:25
  • @sidewaysmilk route helpers are very specific to your particular application by design. Using a generic reference is of limited usefulness. – Adam Lassek May 23 '14 at 01:00
  • AdamLassek: Respectfully, I disagree. Consider view helpers that take an object and generate a URL. Making it generic eases code reuse and encourages good code hygiene. Furthermore, it's more explicit and more obvious how the value is obtained. Also, we're talking about embedding Ruby in JavaScript. I can't tell you how many times I've reused JavaScript that I've written across applications. Finally, at least including @Nick's contribution as a "you might also try" footnote in your answer might help future knowledge seekers. I think it deserves a mention since it's the answer that helped me.:) – Justin Force May 23 '14 at 17:45
  • @sidewaysmilk I'd say the comments here already serve that purpose :) Plus if you're reusing route helpers on the backend, you'd be doing that via a Rails Engine, in which case the engine class will always be there, and Rails.application would no longer be appropriate. – Adam Lassek May 23 '14 at 22:40
1

You could move the file to views where it has access to the proper context, then pull it down to the client from a JS source tag. Referring to MyRailsApp::Application.routes.url_helpers may not be the best if you are writing an engine.

Peter Hawkins
  • 373
  • 4
  • 7