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.
Related
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
I'm trying to use carrierwave to upload images to S3. It works locally but when I go to deploy to heroku I get the following error:
ArgumentError: Missing required arguments: aws_access_key_id, aws_secret_
access_key
The keys are definitely set because I can see them when I run heroku:config
I've searched every answer I could find on stack and I searched through every answer on the first 3 pages of Google. None of them have worked.
I know the uploading works so it's not the code that's a problem. What settings or variables do I have to set to make this work?
Please help, I can't move forward with my app until this is done (so I can deploy to heroku again without it being stopped because of this error.)
Some info:
Environment Variables
You've got a problem with the calling of your environment variables in
Heroku. ENV vars are basically variables stored in the OS /
environment, which means you've got to set them for each environment
you attempt to your deploy application
heroku config should should the ENV vars you've set. If you don't see ENV['AWS_ACCESS_KEY'] etc, it means you've not set them correctly, which as explained is as simple as calling the command heroku config:add YOUR_ENV_VAR=VAR
Figaro
I wanted to recommend using Figaro for this
This is a gem which basically stores local ENV vars in config/application.yml. This allows you to store ENV variables locally; but more importantly, allows you to sync them with Heroku using this command:
rake figaro:heroku
This will set your env vars on Heroku, allowing you to use them with Carrierwave as recommended in the other answers
It sounds like you have set the ENV variables on Heroku, but you need to hook those up to CarrierWave.
In config/initializers/fog.rb
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS',
:aws_access_key_id => Rails.configuration.s3_access_key_id,
:aws_secret_access_key => Rails.configuration.s3_secret_access_key,
}
end
In your environments/<environment>.rb file
Rails.application.configure do
config.s3_access_key_id = ENV['S3_ACCESS_KEY_ID']
config.s3_secret_access_key = ENV['S3_SECRET_ACCESS_KEY']
end
This sets your Rails config to the ENV variables on Heroku which makes them available as Rails.configuration.<key>
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.
I usually git-ignore config/environment.rb file. I add ENV['RAILS_ENV'] setting into that file so it should be different on different machine.
However, Heroku requires that file in git. Without it, the application crashes.
How do you handle it?
Thanks.
Sam
You shouldn't ignore config/environment.rb. As Zeke already answered, you can set environment variables in a live Heroku app.
To see a list of environment variables available to your heroku app run heroku config. To set the value of an specific variable run heroku config:add RAILS_ENV=staging --app yourapp.
But what about your development app running in your own machine? There are some options, one is exporting an environment variable in your shell:
$ export RAILS_ENV=staging
$ echo $RAILS_ENV
staging
But I prefer another approach. This is what I have in my config/environment.rb:
# Load the rails application
require File.expand_path('../application', __FILE__)
# Load environment vars from local file
env_vars = File.join(Rails.root.to_s, 'config', 'env_vars.rb')
load(env_vars) if File.exists?(env_vars)
# Initialize the rails application
MyApp::Application.initialize!
If there is a config/env_vars.rb file, it will be loaded. This is the contents of a sample env_vars.rb file:
ENV["REDISTOGO_URL"] = 'redis://localhost:6379'
ENV["AWS_ACCESS_KEY"] = '283983483'
ENV["AWS_SECRET"] = '743843934'
ENV["S3_BUCKET"] = 'myapp-development'
This way you could have different sets of environment variables for your development, staging and production apps.
You will want to git-ignore this file.
While I'm running my development app I want to send files to a myapp-development S3 bucket. But I want my production app (in Heroku) to send files to a myapp-production S3 bucket.
$ heroku config:add S3_BUCKET='myapp-production' --app myapp
And a different bucket for my staging app (also running in Heroku):
$ heroku config:add S3_BUCKET='myapp-staging' --app myapp-staging
Since you'll git-ignore config/env_vars.rb, it will not be present in your apps running in Heroku, and so they'll get their environment variables from the above heroku config:add configurations.
Since I work with other people, I often include an example env_vars.rb.example file in the project, which is not ignored by git:
File config/env_vars.rb.example:
# Copy this file to config/env_vars.rb
# MAKE SURE THAT YOUR .gitignore INCLUDES IT!
#
# This file is used to set environment variables that would be present on
# Heroku, and are needed for our development and test instances to run.
ENV["REDISTOGO_URL"] = 'redis://localhost:6379'
ENV["AWS_ACCESS_KEY"] = 'xxx'
ENV["AWS_SECRET"] = 'xxx'
ENV["S3_BUCKET"] = 'some-bucket'
if Rails.env.test?
HOST = "example.com"
else
HOST = "development.intranet"
end
Notice that an advantage of loading this env_vars.rb file is that you can do different things programmatically, for example setting the HOST constant to a different value if you are running your tests, like above.
Heroku has pretty great documentation. To answer your question directly, they provide and interface to configure environment variables. They even provide a mechanism that makes deploying to two+ Heroku-hosted apps with different environments quite easy.
I keep getting the error "not authorized" whenever i try to visit:
appname.herokuapp.com/admin_data
I've created an admin.rb file with
AdminData.config do |config|
#comment
config.is_allowed_to_view = lambda {|controller| return true if (Rails.env.development? || Rails.env.production?) }
end
(I know the above following has a safety issue but I'm just trying to get it work before I check for administration.)
I've tried
bundle exec rake assets:precompile
and also
RAILS_ENV=production rake assets:precompile
prior to pushing to heroku but i can't seem to get past that error.
I've followed the instructions from
https://github.com/bigbinary/admin_data
but can't seem to get it to work on production.
On my development machine it works.
http://localhost:3000/admin_data shows everything belonging to my dev environment.
Are you certain that your heroku instance is in production mode? Sometimes instances on Heroku are configured as staging.
Try this:
heroku config --app your_app_name
This will return the config variables of your instance. You will see a variety of config variables. Look for these:
RACK_ENV => production
RAILS_ENV => production
Are they set to production or staging?
Have you read the Production Configuration section of https://github.com/bigbinary/admin_data/wiki/admin_data-security-configuration-for-a-Rails3-application - seems like there are extra steps you need to take when your application is running in production mode.
ah it was a dumb mistake. i was not pushing from my master branch and my app was never being updated