I am using Action Mailer and have my configuration settings for Action Mailer in my environment.rb file. I would like to post my project in a public repository along with an environment.rb file, but I do not want to include my mail server's login information. How does one configure Capistrano's deploy.rb so that it prompts the user for the mail server settings and then modifies or creates an environment.rb file during Capistrano's deployment.
Thanks for looking =)
There are lots of other variations on this... see this blog post for more ideas:
http://www.simonecarletti.com/blog/2009/06/capistrano-and-database-yml
Here a start...
Add this into your production.rb environment file:
ActionMailer::Base.smtp_settings = File.expand_path(File.join(RAILS_ROOT, 'config', 'actionmailer.yml'))
And in a capistrano task, you can do something like this:
desc "Generate actionmailer.yml file"
task :generate_actionmailer_yml, :roles=>:app do
secret_password = Capistrano::CLI.ui.ask "Enter your secret mail password:"
template = File.read("config/deploy/actionmailer.yml.erb")
buffer = ERB.new(template).result(binding)
put buffer, "#{shared_path}/config/actionmailer.yml"
end
desc "Link actionmailer.yml from shared"
task :link_actionmailer_yml, :roles=>:app do
run "rm -f #{current_path}/config/actionmailer.yml && ln -s #{shared_path}/config/actionmailer.yml #{current_path}/config/actionmailer.yml"
end
after "deploy:finalize_update", "deploy:link_actionmailer_yml"
Then, you create a template actionmailer.yml.erb file:
address: "my.smtp.com"
port: 587
authentication: :plain
user_name: "user#name.com"
password: <%= secret_password %>
I would add to the answer of #jkrall by suggesting the use of the Capistrano::CLI.password_prompt method instead of the Capistrano::CLI.ui.ask method, so that the password will not echo to stdin.
Related
I am familiar with Rails but this is my first time uploading to production. I am able to successfully upload my app to AWS and deploy it. However, every time I do that, I have to ssh into my server and run the necessary rake tasks to clean up my models and fully prep my website. Is there a file like production.rb where you can write a script to be run on every production upload. For instance run all tests and rake tests ? Is there a simple example of a script someone. This is the example of my rake file.
Note: I am using AWS Beanstalk, super easy to deploy, just want to run some post production ready scripts.
This is the rake file I want to run commands of post deployment.
require "#{Rails.root}/app/helpers/application_helper"
include ApplicationHelper
namespace :db do
desc "Generate a new blog post markdown"
task new_article: :environment do
cp 'lib/assets/articles/template.md', "lib/assets/articles/NEW_ARTICLE#{Time.now.strftime("%s")}.md"
puts 'new article created!'
end
task populate: :environment do
Article.destroy_all
if User.count == 0
User.create!(name: "AJ", email: "aj#psychowarfare.com")
end
puts Dir.pwd
a = File.join("lib", "assets", "articles", "*.md")
Dir.glob(a).reject { |name| /.*(template|NEW_ARTICLE).*/ =~ name }.each do |file|
File.open(file, "r") do |f|
contents = f.read
mkdown = Metadown.render(contents)
md = mkdown.metadata
unrendered_content = contents.sub(/^---(\n|.)*---/, '')
#puts unrendered_content
article = Article.create!(title: md["title"],
content: markdown(unrendered_content),
header_image: md["header_image"],
published: md["published"],
useful_links: md["useful_links"],
people_mentioned: md["people_mentioned"],
written_at_date: md["written_at_date"],
timestamp: md["timestamp"],
embedded_link: md["embedded_link"],
user: User.first)
article.add_tag(md["tags"])
puts article.useful_links
puts article.people_mentioned
puts article.header_image
puts article.tags
end
end
puts "Article Count: #{Article.count}"
end
end
For post deployment, you can try the following way.
Create a file in .ebextensions/01_build.config
commands:
create_post_dir:
command: "mkdir /opt/elasticbeanstalk/hooks/appdeploy/post"
ignoreErrors: true
files:
"/opt/elasticbeanstalk/hooks/appdeploy/post/99_build_app.sh":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
cd /var/app/current/app/
Your-Post-Deploy-Command1
Your-Post-Deploy-Command2
Your-Post-Deploy-Command3
What this config does is:
create the “post” directory if it doesn’t already exist (it won’t by
default) – ignore any errors (such as if the directory already
existed)
deploy the shell script with the appropriate permissions into the right directory
For more details look at the following references: Blog-Article & Stackoverflow-Question
I created a new Rails app called sample_app and I use postgresql as my db (I already created a postgresql username and password). I use this setup guide https://gorails.com/setup/ubuntu/16.04
So I run this command rails new sample_app -d postgresql. And then I have to edit the config/database.yml to match the username and password to my postgresql's username and password I just created. But I don't want to hard-code because I will be using git.
I found this tutorial from digital ocean which suggest to use:
username: <%= ENV['APPNAME_DATABASE_USER'] %>
password: <%= ENV['APPNAME_DATABASE_PASSWORD'] %>
Is this the correct code? If so, since my app is called sample_app, my code should be?
username: <%= ENV['SAMPLE_APP_DATABASE_USER'] %>
password: <%= ENV['SAMPLE_APP_DATABASE_PASSWORD'] %>
If this is not the correct one, can you help me? Thank you!
There are many ways you can set the environment variables.
Here are two of them,
Option One: Setting ENV variables via a yml file
Create a file config/local_env.yml:
config/local_env.yml:
SAMPLE_APP_DATABASE_USER: 'your username'
SAMPLE_APP_DATABASE_PASSWORD: '******'
The above are the names you will use like,ENV['SAMPLE_APP_DATABASE_USER']. these can be names as your wish. you can take any name, but we should use the same name in the ENV reference.
add it to gitignore:
/config/local_env.yml
Change some code in application.rb
application.rb:
config.before_configuration do
env_file = File.join(Rails.root, 'config', 'local_env.yml')
YAML.load(File.open(env_file)).each do |key, value|
ENV[key.to_s] = value
end if File.exists?(env_file)
end
The code opens the config/local_env.yml file, reads each key/value pair, and sets environment variables.
Using Environment Variables:
username: <%= ENV['SAMPLE_APP_DATABASE_USER'] %>
password: <%= ENV['SAMPLE_APP_DATABASE_PASSWORD'] %>
Option Two: Use the Figaro Gem
The gem takes advantage of Ruby’s ability to set environment variables as well as read them. The gem reads a config/application.yml file and sets environment variables before anything else is configured in the Rails application.
Here’s how to use it. In your Gemfile, add:
gem 'figaro'
and run bundle install
The gem provides a generator:
$ bundle exec figaro install
The generator creates a config/application.yml file and modifies the .gitignore file to prevent the file from being checked into a git repository.
You can add environment variables as key/value pairs to config/application.yml:
SAMPLE_APP_DATABASE_USER: 'your username'
SAMPLE_APP_DATABASE_PASSWORD: '******'
The environment variables will be available anywhere in your application as ENV variables:
ENV["SAMPLE_APP_DATABASE_USER"]
Here are the remaining ways you can achieve the same.
You can call it anything you want...
username: <%= ENV['CARROTS'] %>
password: <%= ENV['BEANS'] %>
You just have to make sure your deploy script sets the variables CARROTS and BEANS correctly.
try this gem dotenv-rails
add this to Gemfile:
gem 'dotenv-rails', :groups => [:development, :test]
bundle it. Now create a .env file on your apps's directory with following content:
SAMPLE_APP_DATABASE_USER: "devuser"
SAMPLE_APP_DATABASE_PASSWORD: "devuser"
restart the server you're good to go. these variables are exported when you boot your app which you can access in your database.yml file
username: <%= ENV['SAMPLE_APP_DATABASE_USER'] %>
password: <%= ENV['SAMPLE_APP_DATABASE_PASSWORD'] %>
read dotenv-rails documentation for more info
I generated a skeleton application using Rails Composer and included Figaro. It runs successfully locally. Before I modify it, I am pushing it down to Heroku. However, the heroku run rake db:seed failed. I've come to find out that the app/config/application.yml is .gitignored. So, I need to use rake figaro:heroku to set the environment variables before I run heroku run rake db:seed. But, the rake Figaro:heroku is failing as follows:
D:\BitNami\rubystack-2.0.0-11\projects\myapp>rake figaro:heroku
! Usage: heroku config:set KEY1=VALUE1 [KEY2=VALUE2 ...]
! Must specify KEY and VALUE to set.
This looks like it is just ignoring my app/config/application.yml and asking for line directed input to me, but I don't know. Again, the application runs successfully locally, so that application.yml should be correct. Here it is:
MANDRILL_USERNAME: valid.address#gmail.com
MANDRILL_APIKEY: a.valid.apikey
ADMIN_NAME: Admin Name
ADMIN_EMAIL: valid.address#gmail.com
ADMIN_PASSWORD: validpassword
ROLES: [admin, user, VIP]
The failure occurs in seeds when I issue heroku run rake db:seed. The file is:
puts 'ROLES'
YAML.load(ENV['ROLES']).each do |role|
Role.find_or_create_by_name(role)
puts 'role: ' << role
end
puts 'DEFAULT USERS'
user = User.find_or_create_by_email :name => ENV['ADMIN_NAME'].dup, :email => ENV['ADMIN_EMAIL'].dup, :password => ENV['ADMIN_PASSWORD'].dup, :password_confirmation => ENV['ADMIN_PASSWORD'].dup
puts 'user: ' << user.name
user.confirm!
user.add_role :admin
It fails on the first access to variable role because ENV['ROLES'] is uninitialized. It would be initialized by application.yml, and is locally, but it is .gitignored. Thus, the need for rake Figaro:heroku to succeed.
This seems so simple, especially since it runs smoothly locally. OBTW, I have tried application.yml as shown and with the strings double-quoted but it doesn't seem to make a difference in any case so...
Ideas? Thanks...
I understand from the path you're mentioning that this is a Windows question. Problem is that the arrays are not correctly dealt with on Windows. Workaround I once made is to override the "vars" method of Heroku in a rake file in lib/tasks, like
module Figaro
module Tasks
class Heroku # < Struct.new(:app)
def vars
Figaro.env(environment).map { |key, value|
if value.start_with? "["
value = "'#{value.gsub('"', '')}'"
elsif value.include? " "
value = "'#{value}'"
end
"#{key}=#{value}"
}.sort.join(" ")
end
end
end
end
I'd surmise the problem will likely be with Figaro's processing of your different variable types:
MANDRILL_USERNAME: "valid.address#gmail.com"
MANDRILL_APIKEY: "a.valid.apikey"
ADMIN_NAME: "Admin Name"
ADMIN_EMAIL: "valid.address#gmail.com"
ADMIN_PASSWORD: "validpassword"
ROLES: ["admin", "user", "VIP"]
Try removing any spaces & ensuring you only send KEY: "VALUE" to Figaro. Your spaces are basically going to cause the system to misinterpret it
Currently, I am using the pg gem in my rails rake task which is perfect for what I want to do. I create a variable pg_conn and pass in the connection details to the PGconn.connect method. I just don't want to change this rake task everytime the database usernames/ passwords change. How can I pass in the login details from my yaml file to the pg_conn command. Take a look at my code below:
namespace :update_table do
task :import => :environment do
$pg_conn = PGconn.connect(host = "samsi-postgres-90s", port = 6433, options = '', tty ='', dbname = "installs", login = "reports_m", password = "password")
my_query = "select * from all_tables"
conn.query(my_query) do |raw_row|
puts raw_row
end
end
end
Ideally, I would like to pass a hash of credential details to the pg_conn connection variable like so:
$pg_conn = PGconn.connect(yamlfile[:host], yamlfile[:port], '', '', yamlfile[:database], yamlfile[:username], yamlfile[:password])
How can I do this? Thank you for your help!
For Rails3, you can use Rails.configuration in your rake task:
config = Rails.configuration.database_configuration
host = config[Rails.env]["host"]
database = config[Rails.env]["database"]
username = config[Rails.env]["username"]
password = config[Rails.env]["password"]
Just make sure you inherit the environment in your rake task such as
task :users => :environment do
Given this Yaml file:
:host: samsi-postgres-90s
:port: 6433
:database: installs
:username: reports_m
:password: password
you can load it this way:
require 'yaml'
yamlfile = YAML.load(open('your_file_path'))
then you can write:
yamlfile[:host] # => "samsi-postgres-90s"
etc.
I am not able to run ar_sendmail command from my terminal. I don't think i have missed its configuration. Below is my code;
development.rb
++++++++++++++++++++++++++++++++++++++++++++++++++++
ActionMailer::Base.delivery_method = :activerecord
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 25,
:domain => "www.google.com",
:authentication => :plain,
:user_name => "ashis.lun#gmail.com",
:password => "kathmandu",
:enable_starttls_auto => true
}
require "action_mailer/ar_mailer"
Gemfile
+++++++++++++++++++++++++++
gem "ar_mailer", "1.5.1"
My Mailer
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
class Postoffice < ActionMailer::ARMailer
def recover_password_email(account, name, address)
#recipients = address
#from = "ashis.lun#gmail.com"
#subject = "Your Account at #{account.org_name} is Ready"
#body["subdomain"] = account.subdomain
#body["name"] = name
#body["org_name"] = account.org_name
#body["password"] = password
#body["email"] = address
end
end
My controller
++++++++++++++++++++++++++++++++++++++++++++++++++++
def reset_password
#user = User.find_by_email(params[:email])
begin
if #user
password = get_new_password
#user.update_attributes!(:password => password)
Postoffice.deliver_recover_password_email(#account, #user.individual.firstname, #user.email, password)
flash[:notice] = "Your password has been e-mailed to you. It should show up in a minute!"
redirect_to '/sessions/new'
end
rescue
flash[:notice] = "Sorry, there was a problem resetting your password."
redirect_to '/sessions/new'
end
end
end
Whenever I run ar_sendmail command I just get below message. If i hit RAILS_ROOT in console then I it shows /Users/me/Dev/a5his
Usage: ar_sendmail [options]
ar_sendmail scans the email table for new messages and sends them to the
website's configured SMTP host.
ar_sendmail must be run from a Rails application's root or have it specified
with --chdir.
If ar_sendmail is started with --pid-file, it will fail to start if the PID
file already exists or the contents don't match it's PID.
Sendmail options:
-b, --batch-size BATCH_SIZE Maximum number of emails to send per delay
Default: Deliver all available emails
--delay DELAY Delay between checks for new mail
in the database
Default: 60
--max-age MAX_AGE Maxmimum age for an email. After this
it will be removed from the queue.
Set to 0 to disable queue cleanup.
Default: 604800 seconds
-o, --once Only check for new mail and deliver once
Default: false
-p, --pid-file [PATH] File to store the pid in.
Defaults to /var/run/ar_sendmail.pid
when no path is given
-d, --daemonize Run as a daemon process
Default: false
--mailq Display a list of emails waiting to be sent
Setup Options:
--create-migration Prints a migration to add an Email table
to stdout
--create-model Prints a model for an Email ActiveRecord
object to stdout
Generic Options:
-c, --chdir PATH Use PATH for the application path
Default: .
-e, --environment RAILS_ENV Set the RAILS_ENV constant
Default:
-t, --table-name TABLE_NAME Name of table holding emails
Used for both sendmail and
migration creation
Default: Email
-v, --[no-]verbose Be verbose
Default:
-h, --help You're looking at it
ar_sendmail must be run from a Rails application's root to deliver email.
/Users/me/Dev/a5his does not appear to be a Rails application root.
Thanks in advance <><
How about using Delayed Job? I've used ar mailer in the past and find delayed job a much better solution.
https://github.com/collectiveidea/delayed_job
Not sure if it'll make a difference, but it says here to put
require "action_mailer/ar_mailer"
in environment.rb, not development.rb or production.rb. Other than that, I can't see anything you missed.
Try ar_sendmail --chdir /Users/me/Dev/a5his or changing into the root of your rails app before running the command
ar_sendmail must be run from a Rails application's root to deliver email.
/Users/me/Dev/a5his does not appear to be a Rails application root.
Are you running the command in the application's root?
try
cd #{Rails.root.to_s} && bundle exec ar_sendmail_rails3 -e production
If you look at the source (shown below), this message is displayed if loading config/environment fails. One instance of this I ran into was where a dependency was unmet, which was causing an exception to fire when config/environment was being loaded. To address this, you can use an irb session and try requiring config/environment to see what error may be causing the require to fail.
Dir.chdir options[:Chdir] do
begin
require 'config/environment'
rescue LoadError
usage opts, <<-EOF
#{name} must be run from a Rails application's root to deliver email.
#{Dir.pwd} does not appear to be a Rails application root.
EOF
end
end