How can I get the base url in an ActionMailer? - ruby-on-rails

I want to send out an email with a deep link back into my app, but I'd rather not have to hard-code the URL or else I have to switch it when I move from one environment to the next. How can I obtain the base url of a web app from within an ActionMailer? For example, I'd love to be able to have something like:
<%= base_uri %>listCreate?first=foo&second=bar
render something like the following in my testing environment:
http://localhost:30000/myApp/listCreate?first=foo&second=bar
and the following in production:
http://www.myDomain.com/myApp/listCreate?first=foo&second=bar

Set the defult url option in config/environments/production.rb
config.action_mailer.default_url_options = { :host => 'your.app.com' }
and in mail template
the link should be
<%= link_to 'myapp', myapp_list_url %>
Hope this could help
You can refer the Action Mailer doc

You can set the default_url_options for your mailer in the controller where you have the current host for the request.
In my case, I send an email when I receive information in some lead creation form, so I have a LeadMailer. My solution was to create a before filter to set the host in the mailer.
Of course, you don't need to do it in a before filter, you could set it in your action.
My solutions looked like this:
class LeadsController < ApplicationController
before_action :set_host, on: [:create]
def set_host
LeadsMailer.default_url_options = { host: request.host_with_port }
LeadsMailer.asset_host = request.protocol + request.host_with_port
end
end
I set the asset_host config because I wanted to use my images from the assets pipeline.
Now you can use the _url helpers as usual
<%= link_to 'something', something_url %>
Or your asset helpers
<%= image_url('logo.png')%>

Related

Rails 4 link to static file in public in mailer

In a Rails 4 app, I have a static file stored in the /public directory. And I have a view partial that links to that file like this:
<%= "Please download the #{link_to 'Static file', '/static_filename.docx'}".html_safe %>
The partial is used in both a regular view and in a mailer view. In the regular view, this works perfectly, and the link url is like this:
www.example.com/static_filename.docx
But in the mailer, the url comes out like this, missing the host name:
/static_filename.docx
This, despite the fact that I took care to configure the default url in config/environments/production.rb as such:
config.action_mailer.default_url_options = { :host => 'http://www.example.com' }
I'm puzzled as to what I am doing wrong, and why the regular view works when the mailer does not work.
Any help would be greatly appreciated!
You should your asset host for action mailer
config.action_mailer.asset_host = "http://www.yourdomain.com"
Secondly, use the asset_path() wrapper on your asset, ie
<%= "Please download the #{link_to 'Static file', asset_path('/static_filename.docx')}".html_safe %>

Rails: configuring a form action's host using custom URL from settings

I have a Rails app that I am feeding cross domain in production. It needs absolute references. Because of this, I have enabled the following in my config/environments/production.rb:
config.action_controller.asset_host = "http://myapp.herokuapp.com"
That works fine for images and resources but my input form that looks like this:
<%= form_tag('/plans/collapse_plans', :method => 'post', :remote => true ) do %>
is still getting this in the console:
Failed to load resource file://localhost/plans/collapse_plan
How can I change it so that form action will automatically include the specified host, instead of defaulting to localhost? Can I set this anywhere in config?
This seems like it will work:
https://github.com/binarylogic/settingslogic
Then I can just do:
<%= form_tag mysettings.myspecifiedhost + plans_collapse_plans_path, :method => 'post', :remote => true do %>
I may be on the wrong track here, but:
Asset host is not your application's host, asset host is a host that serves you /app/assets folder and this is configurable so you can set up a CDN for example, it's not intended for hosting action points.
If you want to target the full url of your own host use rake routes to get the route name corresponding to /plans/collapse_plans which probably looks something in the lines of plans_collapse_plans and then you can use plans_collapse_plans_url and rails will render the correct full URL for you.
If you're using the default host name rails provides automagically this will "just work", i.e.
[2] pry(#<#<Class:0x000000048fd780>>)> account_edit_url
=> "http://dev:3000/account/edit"
If this doesn't "just work", you can override all url helpers in the app by overriding default_url_options in your ApplicationController:
def default_url_options
{:host => HOST}
end
and be sure to set the HOST constant in your application's environment, for example:
[1] pry(#<#<Class:0x00000005047d10>>)> account_edit_url
=> "http://o7ms:3000/account/edit"
If you need to override this just in certain situations you can leave the ApplicationController alone and do:
[3] pry(#<#<Class:0x000000048fd780>>)> account_edit_url(host: MY_HOST_FOR_THE_OTHER_THINGY)
=> "http://foo:3000/account/edit"
In all cases you'll set up a config option in one place and all endpoints in the app will adjust.
EDIT
If you want to go fancy,
see default_url_options and rails 3,
by overriding url_options you may be able to implement pretty calls like account_edit_url(ajax_host: true), the url_options method would look something like this if this works:
def url_options
options = super
if super.delete(:ajax_host)
{host: AJAX_HOST}.merge(options)
else
options
end
end
what you are trying cannot be done normally for ajax calls.
see http://en.wikipedia.org/wiki/Same-origin_policy
Two approaches:--
1.) <%= form_tag root_url + plans_collapse_plans_path, :method => 'post', :remote => true do %>
concatenation:-- root_url + plans_collapse_plans_path
2.) in config/environments/production.rb
MyApp::Application.configure do
# general configurations
config.after_initialize do
Rails.application.routes.default_url_options[:host] = 'root_url' #'localhost:3000'
end
end

url_for not using default_url_options[:host] value

I've got a view for an ActionMailer that includes a few different links. I'm running it on localhost:3000 right now, and so I've set that as such in a file called setup_mail.rb in app/initializers (as indicated here):
ActionMailer::Base.default_url_options[:host] = "localhost:3000"
When I go to use url_for in the view, it doesn't seem to pull this value. If I then add :host => "localhost:3000" to each url_for tag, they work properly. But they don't work without that included.
I have another tag, project_url, which is as it appears: a link to a specified Project. This functions, including the host value, with just project_url(#project). Why would one work but not the other?
From everything I've read, setting the default_url_options[:host] in an initializer should allow me to omit the :host value in the url_for tag. Obviously, it's not the worst thing in the world to just add that value, but it seems unnecessary and it means that when I eventually host the project somewhere I'll have to go through and change that value all over the place. But worse than that, it's something that I don't understand. I'm still learning as I go here and so I'd like to know what I'm doing wrong.
The documentation is pretty clear on this
When you decide to set a default :host for your mailers, then you need to make sure to use the :only_path => false option when using url_for. Since the url_for view helper will generate relative URLs by default when a :host option isn’t explicitly provided, passing :only_path => false will ensure that absolute URLs are generated.
You could create your own helper to use instead of the url_for to force :only_path to be false
def your_url_for(options = {})
options.reverse_merge! only_path: false
url_for(options)
end
You could also monkey patch rails to force this as the default, but that's left up to you :)
This all would be in addition to adding
config.action_mailer.default_url_options = { host: "YOUR HOST" }
to config/application.rb or equivalent.
It seems :only_path option is false which is by default. so that is why you need to provide [:host] either explicitly for every tag or set default options for url_for which would apply to all tags. here is how to set default host:
put this code in your Application controller & it should work.
helper_method :url_for
def default_url_options(options)
{ host: 'localhost:3000' }
end
For more details check set url_for defaults
Instead of tampering with the global default setting which imho shouldn't be changed after initialization you can simply define a method default_url_options in your mailer just like you can do it in a controller:
class UserMailer < ActionMailer::Base
def default_url_options
{ host: Tenant.current(true).host }
end
def confirm(user)
#user = user
mail(to: #user.email, subject: t(".subject_confirm"))
end
end
You're setting the default in ActionMailer::Base, but appear to expect it to reset the default for ActionController::Base.
A <%= link_to %> inside your mailer view doesn't necessarily know anything about the fact that it's inside a mailer view.

How to generate correct URLs in mailer templates?

I am using Ruby on Rails 3.1.0 and I would like to properly generate URLs in HTML email messages. In my environment file I set
config.action_mailer.default_url_options = { :host => 'my_site.org' }
In the email view file (.html.erb) I state
<%= link_to #user.name, users_url(#user) %>
When I go to see the received email the generated URL is http://users/1, of course no correct. So, how can I generate correct URLs in mailer templates so to have http://my_site.org/users/1 links in body messages?
I also tryed to set the default_url_options in my mailer.rb file
class MyCustom::Mailer < ActionMailer::Base
default_url_options[:host] = 'my_site.org'
def test_sending
...
end
end
but it doesn't work.
users_path is the relative path (/users/1). For an email, you want the absolute path, so use users_url(#user), which will give http://myapp.com/users/1 instead.
your action_mailer setting is correct.
But you should be using _url and not _path for the link_to,
<%= link_to #user.name, users_url(#user) %>
See that you set the config option. To be sure it uses the absolute path use:
<%= link_to, "My Profile", users_url(:only_path => false, #user) %>
OR set the host specifically in the link:
<%= link_to, "My Profile", users_url(:host => "example.com", #user) %>
It is explained here:
ActionView Helpers

Problem with url_for and named routes in ActionMailer View: "Need controller and action"

I'm attempting to provide a confirmation link in my user welcome email and I'm getting the following Rails error:
Need controller and action!
It makes a fuss about this line:
<p>Please take a moment to activate your account by going to:
<%= link_to confirm_user_url(:id => #user.confirmation_code) %>.</p>
In my development.rb environment, I have the following line:
config.action_mailer.default_url_options = {
:host => "localhost", :port => 3000
}
There's no problem with the #user variable. I've tested the email with things like #user.username and #user.confirmation_code. I'm only getting trouble with url_for and named routes like confirm_user_url.
When I check my routes with rake routes, confirm_user shows up, so it's not an issue with the named route not existing.
I can't seem to figure it out. What gives?
ActionMailer isn't a real Rails controller, so routes aren't available in your mailer templates. You need to set up instance variables in your mailer class to pass values to the template.
eg. if your mailer is SampleMailer:
class SampleMailer < ActionMailer::Base
def confirmation_mail(user)
subject 'Confirmation'
recipients user.email
from 'sample#example.com'
sent_on Time.now
body :greeting => 'Sample Greeting', :email => user.email,
:confirm_user_url => confirm_user_url(:id=>#user.confirmation_code)
end
end
Then in the template:
<%= link_to "Confirmation link", #confirm_user_url %>
This is explained somewhat cryptically in the api in the "ActionMailer" section, and in more detail in Agile Web Development with Rails, 3rd Ed., Chapter 25.
Since having a clickable url is what you said in your where after in your comment, here you go macek
<p>Please take a moment to activate your account by going to:
<%= auto_link confirm_user_url(:id => #user.confirmation_code) %>.</p>
I've used the auto_link helper in some of my mailers to make urls clickable and it has worked out pretty well. I think that does email addresses also, check out the full api for all the options. Enjoy.

Resources