32

For example, I have constructed a string called "new_work_path", now I want to call that helper as a method.

I've tried send("new_work_path", vars) and calling the same send from many objects. But I don't think that I've found the right object to call these helpers.

To do object.send("new_work_path", vars), what object should I be looking for?

I've tried to look for this online for a while but couldn't find anything. If anyone can shine some lights on this one, it would be great!

Thanks!

Adam Mihalcin
  • 14,242
  • 4
  • 36
  • 52
gtr32x
  • 2,033
  • 4
  • 20
  • 32
  • 3
    Helper methods can only be called from within a view context, not a model if that's what you're trying to do. Can you be more specific about where you're trying to execute this? A standard `send` call should be sufficient if you have the right context. – tadman Mar 07 '12 at 05:18
  • I'm trying to execute this in the application_helper where a standard route helper call would function properly. – gtr32x Mar 07 '12 at 05:28
  • 3
    What's the error you're getting, then? Can you post an example? If calling `new_work_path` directly works, then `send(:new_work_path)` should be equivalent. – tadman Mar 07 '12 at 05:40
  • Wow, this time it worked. I must have missed something the first time then. Indeed send(:new_work_path) works just like that. Now I'm feeling irritated by my stupidity. Haha thanks! – gtr32x Mar 07 '12 at 05:48
  • How do I close a question btw? – gtr32x Mar 07 '12 at 05:50
  • If you can figure out what the problem was, you can always post an answer to your own question. – tadman Mar 07 '12 at 06:04

3 Answers3

41

try Rails.application.routes.url_helpers.send(...)

Edit:

As Larry Gebhardt mentioned the url_helpers module is no longer being cached.

Another workaround would be:

cached_helpers = Class.new do
  include Rails.application.routes.url_helpers
  include Rails.application.routes.mounted_helpers
end.new

cached_helpers.send(...)
Ahmed Ali
  • 555
  • 5
  • 7
  • Works well. Deserves "best answer" :) – Mick F Nov 22 '13 at 16:55
  • 1
    This works well. Let's say you want to link to a nested resource, you could write `Rails.application.routes.url_helpers.send("new_#{@model.class.name.downcase}_comment_url", "#{@model.class.name.downcase}_id".to_sym => @model)`, since you need a parent `model_id`. – Avishai Dec 23 '14 at 23:45
  • If you are trying to access `url_helpers` from a mounted `Rails::Engine`, try `"::Engine".constantize.routes.url_helpers.send(...)' where `` is from the `mount` line in your `routes.rb` file. – erroric May 07 '15 at 13:56
  • 1
    I believe this answer should no longer be considered valid. Rails is no longer caching the anonymous module returned by `url_helpers`. This could result in a large number of modules containing the helper methods being generated. See https://github.com/rails/rails/commit/07dfd2ea097706ef0240f1dda5236cdc5f2c8843. – Larry Gebhardt Jun 05 '19 at 21:49
  • 1
    Seems like caching of url_helpers [was brought back](https://github.com/rails/rails/commit/37e778b6b44ae087ce052ff380b1e3aaee31473d#diff-8cb3fb539a8c272b689394a45bc55877071bc4d01a3b4dc69a9c54c7ae6499aa) in rails 6.1 – Fizvlad Aug 31 '21 at 11:20
11

My bad, as per @tadman suggested, I tried to use send(:new_work_path, args) again and it worked! Must have mistyped it before.

Before finding out that send works right away, I had found another solution which is also of interest:

new_polymorphic_path(Work, args)

Which seems to offer some syntactic sugar as well.

gtr32x
  • 2,033
  • 4
  • 20
  • 32
0

My two cents to the accepted answer.
Please always keep in mind that send is a risky command that you should avoid if possible, or at least having a white list of available options to be accepted by your send call. In case you don't want to use it, Rails have its own way to get paths dynamically with .url_for:

[5] pry(main)> include Rails.application.routes.url_helpers
=> Object
[6] pry(main)> url_for(controller: 'one_path/the_controller', action: 'valid_path')
=> "http://localhost:3000/one_path/the_controller/valid_path"
[7] pry(main)> url_for(controller: 'one_path/the_controller', action: 'some_h4cky_thing')
ActionController::UrlGenerationError: No route matches {:action=>"some_h4cky_thing", :controller=>"one_path/the_controller"}

also .link_to has its own built-in option for this purpose:

<%= link_to "A link to #{option}", {controller: 'one_path/the_controller', action: option}, target: '_blank' %>
Alter Lagos
  • 12,090
  • 1
  • 70
  • 92