81

I have a module with a function. It resides in /lib/contact.rb:

module Contact
  class << self
    def run(current_user)
      ...
    end
  end
end

I want to access the URL helpers like 'users_path' inside the module. How do I do that?

sizzle
  • 2,222
  • 2
  • 21
  • 32
  • 2
    possible duplicate of [Can Rails Routing Helpers (i.e. mymodel\_path(model)) be Used in Models?](http://stackoverflow.com/questions/341143/can-rails-routing-helpers-i-e-mymodel-pathmodel-be-used-in-models) – Daniel Rikowski Jul 05 '13 at 16:59

5 Answers5

149

In your module, just perform a :

 include Rails.application.routes.url_helpers
ronnieonrails
  • 2,129
  • 1
  • 14
  • 13
  • 3
    Doesn't work for me... :( could you give more details, please? – Augustin Riedinger Feb 13 '14 at 17:58
  • it should be noted that doing that include in a seperate class inside a rails application will erase existing initialized url_helpers causing the error : Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true – 3pns Oct 05 '18 at 06:54
  • 6
    If you just need it once or twice, you can just use it directly inline, like `Rails.application.routes.url_helpers.users_path`. I find that more explicit and helpful to others reading your code. – Joshua Pinter Jan 03 '19 at 20:51
35

Here is how I do it in any context without include

routes = Rails.application.routes.url_helpers
url = routes.some_path

That works in any context. If you're trying to include url_helpers - make sure you are doing that in the right place e.g. this works

module Contact
  class << self
    include Rails.application.routes.url_helpers
  end
end

and this does not work

module Contact
  include Rails.application.routes.url_helpers
  class << self
  end
end

One more example with Capybara tests

feature 'bla-bla' do
  include Rails.application.routes.url_helpers
  path = some_path #unknown local variable some_path
end

and now the right one

include Rails.application.routes.url_helpers
feature 'bla-bla' do
  path = some_path #this is ok
end
Anton Chikin
  • 1,746
  • 2
  • 17
  • 22
33

Delegation to url_helpers seems much better than including the whole module into your model

delegate :url_helpers, to: 'Rails.application.routes' 
url_helpers.users_url  => 'www.foo.com/users'

reference

Community
  • 1
  • 1
Naveed
  • 11,057
  • 2
  • 44
  • 63
  • should be `url_helpers` not `url_helper`, I think. – davmac Dec 03 '14 at 12:47
  • Hi there, how did you know it was Rails.application.routes that url_helpers should be delegated to? Where do you find this documentation? Thank you! – Nik So Dec 09 '15 at 20:33
  • 1
    @NikSo api.rubyonrails.org is good place to start exploring. Here is documentation for URL helpers http://api.rubyonrails.org/classes/ActionController/UrlFor.html And including whole module seems overkill, delegation is better option but again its personal opinion :) – Naveed Dec 10 '15 at 23:13
8

I've been struggling with the niceties the helper is expecting from the default controller and stack (default_url_options, etc.), and didn't want to hardcode the host.

Our URL helpers are provided by our nifty module, of course:

include Rails.application.routes.url_helpers

But include this as is, and (1) the helper is going to look for default_url_options, and (2) won't know about the request host nor the request.

The host part comes from the controller instance's url_options. Hence, I pass the controller context into my former module, now a class:

class ApplicationController
  def do_nifty_things
    HasAccessToRoutes.new(self).render
  end
end

class HasAccessToRoutes
  include Rails.application.routes.url_helpers
  delegate :default_url_options, :url_options, to: :@context

  def initialize(context)
    @context = context
  end

  def render
    nifty_things_url
  end
end

Might not fit every case, but it's been useful to me when implementing a sort of custom renderer.

In any way:

  • if you want access to the default url options seamlessly, or the host of the request, you need to pass controller/request context in
  • if you just need the path, no host, and don't care about the url options, you can just make some dummy methods.
Jonathan Allard
  • 18,429
  • 11
  • 54
  • 75
3
delegate :url_helpers, to: 'Rails.application.routes' 
url_helpers.users_url  => 'www.foo.com/users'

to Augustin Riedinger, that delegation code needs to refer to url_helpers (plural), otherwise you get

undefined method `url_helper'

Jerome
  • 5,583
  • 3
  • 33
  • 76