简体   繁体   中英

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

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 %>

What about using an already existing url plus concatenation? Ie 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.

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 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM