View helper link_to in Model class

There are some reasons that you may need link_to in a model. Yes, @andy, it's a violation of MVC, but that doesn't mean you should get points for not answering the question.

@schwabsauce, it's easier than that. The first line isn't even strictly necessary if you do it in an initializer or something. Same thing works for .sanitize and .raw and a whole load of other awesome functions.

ActionView::Base.send(:include, Rails.application.routes.url_helpers)
ActionController::Base.helpers.link_to(whatever)

If you want to use autopaths you may have to do this inside your link_to:

Rails.application.routes.url_helpers.page_path(@page)

Be very careful following the advice outlined in Chuck's post if you're doing this in Rails 3.2.1 . It would seem as though that approach is not a safe way to go about including the link_to helper in non-view classes in Rails 3.2.1. There is a safer way (that works for us in any case) outlined below.

When we used the approach in Chuck's post in one of our classes, it ended up having very troubling and difficult to debug consequences. It ended up causing side effects / bugs that only turned up in very specific (and rare) circumstances.

The problem, as far as we can tell, is that this line:

ActionView::Base.send(:include, Rails.application.routes.url_helpers)

Is telling ActionView::Base to include the Rails.application.routes.url_helpers, which ActionView::Base apparently already does on its own. Having it include the url_helpers a second time, seems to cause re-initialization of the routes state (@_routes in classes that have included the ActionDispatch::Routing::UrlFor module).

This leads to seemingly random and unexplained "undefined method 'url_for' for nil:NilClass" exceptions in views that attempt to call, directly or indirectly, the url_for method after ActionView::Base has included the url_helpers the second time.

The solution that worked for us was instead of telling ActionView::Base to include the url_helpers again, just include the UrlHelper module yourself wherever you might need it.

Then when you need to use link_to and have access to the path you can simply do this (assuming login_path is valid for your app):

include ActionView::Helpers::UrlHelper
...
link = link_to('here', Rails.application.routes.url_helpers.login_path)

It took us a very long time and quite a lot of head scratching to track down the bugs caused by the double-include and I just wanted to warn others to be careful when tweaking the behavior of the Rails base classes.


I got this to work with the following inclusions:

include ActionView::Helpers::UrlHelper
include ActionController::UrlFor
include Rails.application.routes.url_helpers

cattr_accessor :controller
def controller; self.class.controller; end
def request; controller.request; end

Then in my controller I populated the attribute (creating a controller from scratch requires a significant amount of data in the arguments hash).

Lead.controller = self