Rails: make custom URL helper behave like built in _path & _url helpers

rails url helpers
rails path helper

I'm having a hard time figuring out the "Rails Way" to add a email confirmation URL to a mailer.

I'm opting not to do this purely RESTfully because, well, it's difficult with text email because they can't PUT requests.

so here's my routes.rb: get 'confirm/:id' => 'Confirmations#confirm'

and in my mailer I'd like to put email_confirm_url(@user.email_token) where I want the URL to occur.

I created a helper:

#app/helpers/confirmations_helper.rb
module ConfirmationsHelper
  def email_confirm_url(token)
    "/confirm/#{token}"
  end  
end

this all works, sort of, except when I call email_confirm_url(@user.email_token)

I literally get: "/confirm/abcdefg…"

When what I want is: http://myhostname/confirm/abcdefg…

Or in development: http://localhost:3000/confirm/abcdefg…

How can I make my URL helper behave more like the built in <resource>_path and <resource>_url helpers in Rails? though realistically I suppose I really only need _url.

#Edit: I have this in my environment config:

#config/environments/development.rb
...
config.action_mailer.default_url_options = { :host => "localhost:3000" }

In order to access the request object you should implement this function in the controller for your mailer and pass it to the template with a variable.

app/mailers/emailer.rb

@tracking_url = "http://#{request.host}:#{request.port}/confirm/#{token}"

app/view/emailer/template_name.html.erb

<%= link_to 'name', @tracking_url %>

routes, How can I make my URL helper behave more like the built in <resource>_path and <resource>_url helpers in Rails? though realistically I suppose I really only  The singleton url_for on Rails.application.routes.url_helpers isn't the same as the url_for you get when you include the module in your class as the latter has support for polymorphic style routes, etc. whereas the former accepts only a hash and is the underlying implementation defined on ActionDispatch::Routing::RouteSet.

What about using an already existing url plus concatenation? I.e. you can use root_path and root_url, then you concatenate and the behavior is exactly the same as rails!

For example you can do this:

def mystrangemethod_url(option1, option2)
  "#{ root_url }/#{ option1 }/#{ option2 }"
end

And you are done. Easy and the only requirement is set set your root path in routes.rb. Also with the option you have set in development.rb, it will work also in mailers too.

The 10 Most Common Mistakes That Rails Developers Make, A better way to handle something like this is to make sure the object returned by Rails generators conveniently build a helper directory and a new helper class  Rails link_to Options & Arguments. The first argument for link_to is the text on the link. The second argument? It’s the URL you’re linking to. You can hardcode it if you want, but most of the time you’ll be using a Rails model, or a _path method. Rails will figure things out when you follow the proper conventions. For example: Or:

I recently wrote a helper to convert my _path method into a _url method.

Rails uses ActionDispatch::Http::URL.full_url_for to produce the _url methods, and passes in Rails.application.routes.default_url_options to set the host, port, and protocol.

This means you can generate a URL from a given path with

ActionDispatch::Http::URL.full_url_for(Rails.application.routes.default_url_options.merge(path: path))

My work in progress helper looks like:

def self.url_helper(route_name)
  define_method("#{route_name}_url") do |*args|
    path = public_send(:"#{route_name}_path", *args)
    options = Rails.application.routes.default_url_options.merge(path: path)
    ActionDispatch::Http::URL.full_url_for(options)
  end
end

This could then be used in combination with your path helper to build an email_confirm_url method:

url_helper :email_confirm
def email_confirm_path(token)
  "/confirm/#{token}"
end 

ActionDispatch::Routing::Mapper::CustomUrls, Define custom URL helpers that will be added to the application's routes. passed to direct must be a valid set of arguments for url_for which will actually build the URL string. Rails.application.routes.url_helpers.browse_path NOTE: The direct method can't be used inside of a scope block such as namespace or scope  I'm all 👍 deprecating and eventually removing *_path helpers from mailers to protect uses from the 90% cases where they actually want a URL, but we should also have a explicit-but-not-super-difficult way for the cases where you really want to generate a path for whatever reason.

README, In Sinatra, a route is an HTTP method paired with a URL-matching pattern. do # matches /download/path/to/file.xml params['splat'] # => ["path/to/file", "xml"] end You may customize the Mustermann options used for a given route by with built-in support for using String patterns and regular expressions as route matches. So if we want to render a relative link path to our posts' index page, the method would be posts_path or posts_url. The difference between _path and _url is that _path gives the relative path and _url renders the full URL. If you open up the rails console, by running rails console, you can test these route helpers out.

Creating Rails Admin Pages from Scratch (Part 1 , If we look at the routes and the path/url helper methods for this route (using rake We would like to add our Admin model as a resource to our routes so this is what we Rails also provides a generator that will build the controller and associated partial email addresses in and have the filter act more like a search function. When using url helpers like _url or _path methods outside of a controller, we usually have to add include Rails.application.routes.url_helpers in the class. However, Sorbet does not allow code that includes dynamic module. Sorbet Rails provides a drop-in replacement module for the dynamic url_helpers module, called GeneratedUrlHelpers

Routing, page_path is an example of what Phoenix calls a path helper, and we'll talk The router supports other macros besides those for HTTP verbs like get , post , and put . Router.resources/4 macro describes additional options for customizing port, and SSL information needed to construct the full URL from the configuration  There is Rails.application.routes.url_helper module that contains such helpers but appending Rails.application.routes.url_helper.send :include, AdsHelper to the helper file does not work. There are some other examples of custom url helpers that I have.

Comments
  • ActionView::Template::Error: undefined method 'host' for nil:NilClass I think I remember something about not having access to host or host_with_port in Mailers?!? Any way around this?
  • updated answer based on the above comment, let me know if that works.
  • I think the Q is more like how to transparently access mystrangemethod_url from a view.