Use root_url in config.action_mailer.default_url_options - ruby-on-rails

I have a staging app and a production app on Heroku. I'm using Devise for authentication, which for my production app requires that I set
# in config/environments/production.rb
config.action_mailer.default_url_options = { host: 'myapp.com' }
For my staging app, I have to set host: 'myapp-staging.herokuapp.com'
I would rather not have to change it when deploying to different apps, as I am bound to forget that at some point. Is there a way to use root_url in place of the string for host?

Related

Rails/Devise - recoverable password not working in production (works in development)

I am using Devise for user authentication in my Rails app, and I am working on setting up the recoverable password feature. I am able to get this working correctly in my local development environment, but when I deploy to Heroku, it does not work.
In config/environments/development.rb, I have
config.action_mailer.default_url_options = {:host => 'localhost'}
which works perfectly.
In config/environments/production.rb, I have
config.action_mailer.default_url_options = {:host => 'fake-name-92356.herokuapp.com'}
but this generates an error page and the message in my log:
ActionView::Template::Error (Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true)
I have tried various solutions, such as using
default_url_options[:host] = 'fake-name-92356.herokuapp.com'
but to no avail. What am I doing wrong here, that this works in development but not in production?
This will not work as Heroku does not provide an email service. These are facilitated by Add-ons.
The Heroku platform itself doesn’t provide an email service - but
instead provides add-ons that act as backing services - that can be
attached to your app to provide the service. Consult the Heroku
Add-ons marketplace for an appropriate email service that matches your
requirements.
Taken from https://devcenter.heroku.com/articles/smtp

How to generate URL with host in Rails development environment?

I am working on an application that has set its default host to localhost:
config.action_controller.default_url_options = { host: "localhost" }
config.action_mailer.default_url_options = { host: "localhost" }
This works fine if you're serving your app on a specific port (like http://localhost:3000). I am using Pow so that I can access the app from a URL like http://myapp.dev.
How can I change this setting so that it will work with my domain as well as the other developers using localhost? I need to generate full URLs since they will be used in emails. Is it possible to pass some sort of config value to Pow?
This is the best way I found:
1- Create a config/smtp_settings.example.yml file:
development:
:method: :letter_opener
:url_options:
:host: localhost
:port: 3000
production: &production
:method: :smtp
:url_options:
:host: www.the_site.com
:smtp_settings:
address: smtp.gateway.com
port: 465
user_name: someone#somewhere.com
# etc ...
staging:
<<: *production
test:
:method: :test
:url_options:
:host: test.host
Notes:
This uses letter_opener as development mailer, change to your own method
There is a staging environment defined as an exact copy of the production environment, remove if you don't use staging
2- Remove config.action_mailer.delivery_method and config.action_mailer.default_url_options and config.action_mailer.smtp_settings from all files under config/environments/ folder
3- Add in the file config/application.rb the following:
config.action_mailer.delivery_method = config_for(:smtp_settings)[:method]
config.action_mailer.default_url_options = config_for(:smtp_settings)[:url_options]
config.action_mailer.smtp_settings = config_for(:smtp_settings)[:smtp_settings] if config_for(:smtp_settings)[:method] == :smtp
Notes: config_for has been introduced in the latest version of Rails (4.2.0 as per writing). If you use an older version of rails you must manually load the yml files
And the trick on top of all of that to answer your question:
Push to your repository the file config/smtp_settings.example.yml and ignore the file config/smtp_settings.yml.
Each developper of your team would have to create their own config/smtp_settings.yml by copying the file smtp_settings.example.yml and changing the host to match their machine's IP address, so the mail send by each developer leads to their own machine.
You off course requires you to start the local development server binded to 0.0.0.0 so it's accessible from other hosts (considering your security environment off course)
You could use an environment variable to configure a default host. See Luc Boissaye's answer on how to set this up with dotenv. If you don't add the .env to your repo, each developer can create his own .env and configure his (or her) own preferences.
But you can also use existing environment variables to configure the default_url_options. For example Pow.cx sets the POW_DOMAINS variable:
config.action_mailer.default_url_options = {
ENV['POW_DOMAINS'].present? ? 'my-app.dev' : 'localhost'
}
As far as I know you only need to set the config.action_controller.default_url_options if you want to force it to some default. When you use the rails _path helpers in your views, this will generate a relative URL (/path). If you use the _url helpers, this will generate an absolute URL (http://your.host/path), but both the protocol (http) and host (your.host) are request based.
In development, I like to use dotenv gem(https://github.com/bkeepers/dotenv).
I put in .env :
DOMAIN=myapp.dev
And I put inside config/route.rb:
MyApplication::Application.routes.draw do
default_url_options host: ENV['DOMAIN']
In production I define on heroku my domain with this command :
h config:set DOMAIN=myapp.herokuapp.com
or with a custom domain :
h config:set DOMAIN=superdomain.com
This will check if Application root directory is symlinked in .pow of current user and set the host accordingly.
if File.exists?(Dir.home+"/.pow/#{Rails.root.basename}")
config.action_mailer.default_url_options = { host: "#{Rails.root.basename}.dev" }
else
config.action_mailer.default_url_options = { host: "localhost" }
end
Described on Action Mailer Basics:
Unlike controllers, the mailer instance doesn't have any context about the incoming request so you'll need to provide the :host parameter yourself.
As the :host usually is consistent across the application you can configure it globally in config/application.rb:
config.action_mailer.default_url_options = { host: 'example.com' }
Because of this behavior you cannot use any of the *_path helpers inside of an email. Instead you will need to use the associated *_url helper. For example instead of using
<%= link_to 'welcome', welcome_path %>
You will need to use
<%= link_to 'welcome', welcome_url %>
The use of Pow makes things a little trickier but thankfully it integrates with XIP.io so you can access myapp.dev from machines on the local network. Just follow the instructions here: Accessing Virtual Hosts from Other Computers.
The question doesn't mention this, but it might be useful information - If you'd like to actually send mail in your dev (or perhaps test/staging) environment, Instead of seeing mail just in the rails console (with something like powder applog), I'd recommend just hooking it up to a gmail.
You need to override default_url_options in your application controller (at least in rails 3)
http://edgeguides.rubyonrails.org/action_controller_overview.html#default_url_options
class ApplicationController < ActionController::Base
def default_url_options
if Rails.env.production?
{:host => "myproduction.com"}
else
{}
end
end
end

Ruby on Rails 4 with SendGrid - authentication fails , but only on production server on Linode

In my application I have set up sendgrid SMTP service. I am using Figaro gem for setting ENV variables for SMTP configuration.
Everything is fine on development mode - I can send e-mails. But when I deploy to my VPS on Linode, every time when I try to send mail I get:
Net::SMTPAuthenticationError (535 Authentication failed: Bad username / password
On the Rails console of the production server I can verify that ENV["GRID_USER'] and ENV["GRID_PASS"] are correct. The same result I get when I'm checking for Figaro.env.grid_user and Figaro.env.grid_pass (in production mode).
The credentials are correct.
What could be the reason for failing authentication, surprisingly only in production mode?
Here you can see my smtp config in production.rb :
config.action_mailer.smtp_settings = {
address: "smtp.sendgrid.net",
user_name: ENV['GRID_USER'],
password: ['GRID_PASS'],
domain: "why.bio",
port: 587,
authentication: 'plain',
enable_starttls_auto: true
}
Here is the way I declare my credentials in application.yml :
GRID_USER: "MySendGridUserName"
GRID_PASS: "very_wierd_password"
I have checked a hundreds of questions in StackOverflow and a number of blogs, but could not find the solution.
You need to use ENV['GRID_PASS'] and not just ['GRID_PASS'] in your configuration.

how to place SMTP configuration on a separate file?

I'm configuring my app to send emails through gmail smtp, so I'm writing the action_mailer setup in the production.rb file.
Though I don't want to have my gmail credentials written in the production.rb file, which is git versioned.
this is what I have made so far:
in production rb:
require "SmtpData"
config.action_mailer.default_url_options = {:host => 'my server's ip'}
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
enable_starttls_auto: "true",
address: SmtpData::ADDRESS,
port: SmtpData::PORT,
domain: "pjforex.com",
authentication: :plain,
:user_name => SmtpData::USER,
:password => SmtpData::PASS
}
then I created config/initializers/smtp_data.rb containing:
class SmtpData
USER = 'user#gmail.com'
PASS = 'password'
ADDRESS = "smtp.gmail.com"
PORT = "587"
end
But when my capistrano tries to precompile the assets, I get :
rake aborted!
uninitialized constant SmtpData
any clue on how to solve this. or better approach to this issue?
thanks,
You need to store your configuration in a file excluded from Git but shared between deployments. Assuming you are using Capistrano 3, it would be something like this:
1) On your server create a file shared/config/smtp.yml (using YAML is not something crucial, but it's just cleaner for configs) in Capistrano root folder with the following content:
user: user#gmail.com
pass: your_password
address: smtp.gmail.com
port: 587
2) Add this file to your linked_files in config/deploy.rb (ideally, config/database.yml should be stored this way too):
set :linked_files, %w{config/database.yml config/smtp.yml}
3) Read SMTP config in production.rb from config/smtp.yml.
4) You can also have config/smtp.yml locally for your development environment, but don't forget to add it to your .gitignore then.
I believe that production.rb gets loaded before smtp_data.rb, which is why production.rb isn't able to access the class you have defined.
One solution we use, to keep sensitive credentials out of our git versions, is to create (as in your example) production.rb.template and add this to your git repository. This file is pretty much a copy of what you currently have for production.rb, except that you would have placeholders for where credentials should go. For example,
:username => USERNAME GOES HERE
Then, we remove production.rb from the repository (and, optionally, set it to be ignored by git). When you check out your local copy of the repository, you copy production.rb.template as production.rb, and you fill in the credential information. This will only exist in your local deployment and would not be pushed to git.

How to setup two host configs for Devise?

I am using Devise. I need to push the same rails project to two different heroku apps. Is there a way to setup different hosts for the two apps?
For concreteness, for appA, the production.rb should contain the config.action_mailer.default_url_options = {:host => 'appA.heroku.com'}
and for appB, the production.rb should contain config.action_mailer.default_url_options = {:host => 'appB.heroku.com'}.
However, it seems that it is not possible to have both lines in the same production.rb.
You can use environment variables on your heroku instance to differentiate constants in your rails app.
For example:
# production.rb
config.action_mailer.default_url_options = { :host => ENV['ACTION_MAILER_HOST'] }
Then, on your local machine:
% cd /path/to/project/A
% heroku config:add ACTION_MAILER_HOST=appA.heroku.com
% cd /path/to/project/B
% heroku config:add ACTION_MAILER_HOST=appB.heroku.com
For reference and more examples, see this heroku article on environment variables.
You should use a config var for this. That way the value is set per heroku deployment and not in the source code.
See the heroku documentation for more information.

Resources