For the first time I have a question to an answer I already solved, this is more about WHY my little fix solved it in the first place.
I'm following the Learn Rails book tutorial by Daniel Kehoe, creating an application that is supposed to subscribe people to a MailChimp list. I'm using the Gibbon gem, and in the book this is (part of) the code in the model used to set the variables:
def subscribe
mailchimp = Gibbon::API.new(Rails.application.secrets.mailchimp_api_key)
result = mailchimp.lists.subscribe({
:id => Rails.application.secrets.mailchimp_list_id,
<more code here for email and stuff>
end
My secrets.yml file for the variables in question looks like this:
mailchimp_api_key: <%= ENV["MAILCHIMP_API_KEY"] %>
mailchimp_list_id: <%= ENV["MAILCHIMP_LIST_ID"] %>
And, since I'm on Windows, I set the actual value of them in application.yml: [Edit: As people have pointed out, this comes from the Figaro gem and may or may not be part of the tutorial]
MAILCHIMP_API_KEY: mysecretkey
MAILCHIMP_LIST_ID: mysecretid
This, I should note, works perfectly fine locally. I can run my server and subscribe. However, pushing it to Heroku and setting the ENV variables via heroku config:set MAILCHIMP_API_KEY=mysecretkey and the same thing for MAILCHIMP_LIST_ID, it doesn't work. More specifically, it returns the error Invalid Mailchimp List ID:.
So, despite setting it and checking that it is actually set, it has no value at all for the List ID.
I fixed the problem by searching through Heroku's own help text on Config Vars, where it recommends the following: "Set up your code to read the vars at runtime. For example, in Ruby you access the environment variables using the ENV['KEY'] pattern"
I changed my code in the model, so instead of using Rails.application.secrets.mailchimp_list_id it's now this:
def subscribe
mailchimp = Gibbon::API.new(Rails.application.secrets.mailchimp_api_key)
result = mailchimp.lists.subscribe({
:id => ENV['MAILCHIMP_LIST_ID'],
<more code here for email and stuff>
end
And, what do you know, it works in Heroku (and locally)! Why, though? I mean, it did understand the same kind of code for the API Key, but not for the list ID, which seems strange to me. Also, how come the book in question doesn't reflect on this? The author seems willing to update it very regularly, and I see him answer questions on it with an almost religious dedication. Am I the only one to run into this problem?
Edit: Solved below. I feel a bit silly now, and as usual things have a very easy solution. I will note that the book did in fact have the keys duplicated into production in the secrets.yml file, I just missed that part, probably because I had to find an alternative solution to the whole problem of environmental variables and using the Figaro gem. If I have any criticism of the book, it's that it doesn't cater to us poor Windows users. :)
Figaro creates the config/application.yml file and according to its documentation, adds it to your .gitignore:
This creates a commented config/application.yml file and adds it to your .gitignore. Add your own configuration to this file and you're done!
This is done to prevent sensitive secrets (like passwords and salts) from being committed into your Git repository, where those secrets would be compromised.
Figaro does have a feature which you can use to transfer all the settings in application.yml to Heroku at once by running
figaro heroku:set -e production
As it turns out, the config/secrets.yml did not repeat the Mailchimp keys in the production section. To fix this, it should look like this:
development:
mailchimp_api_key: <%= ENV["MAILCHIMP_API_KEY"] %>
mailchimp_list_id: <%= ENV["MAILCHIMP_LIST_ID"] %>
production:
mailchimp_api_key: <%= ENV["MAILCHIMP_API_KEY"] %>
mailchimp_list_id: <%= ENV["MAILCHIMP_LIST_ID"] %>
Had almost the exact same error, but a slightly different cause.
Double check to make sure your secrets.yml is properly configured. Mine looked like the following:
...
production:
mailchimp_api_key: <%= ENV["MAILCHIMP_API_KEY"] %>
mailchimp_list_id: ENV["MAILCHIMP_LIST_ID"]
...
I didn't see the missing <%= %> after scanning the file MANY times, even after I ended up on this page. I'll leave this answer up in case Google sends others with the same typo here.
Related
I'm trying to setup SMS texting with Twilio. I'm going thru their guide here: https://www.twilio.com/blog/2017/12/send-sms-ruby-rails-5-coffee.html but am running into an issue with the ERB in credentials.yml.enc not being parsed for the twilio credentials.
I've tried adding the credentials without using the ERB recommended in the guide, which works, but which would stop me from being able to define these as environment variables.
# config/credentials.yml
twilio_account_sid: <%= ENV.fetch("TWILIO_ACCOUNT_SID", "XXXXXXX") %>
twilio_auth_token: <%= ENV.fetch("TWILIO_AUTH_TOKEN", "XXXXXXX") %>
twilio_phone_number: <%= ENV.fetch("TWILIO_PHONE_NUMBER", "XXXXXXX") %>
# config/initializers/twilio.rb
Twilio.configure do |config|
config.account_sid = Rails.application.credentials.twilio_account_sid
config.auth_token = Rails.application.credentials.twilio_auth_token
end
I ran this in the console:
client = Twilio::REST::Client.new
client.messages.create({
from: Rails.application.credentials.twilio_phone_number,
to: '+11231234',
body: 'Hello there! This is a test'
})
I end up getting:
URI::InvalidURIError (bad URI(is not URI?): https://api.twilio.com/2010-04-01/Accounts/<%= ENV.fetch("TWILIO_ACCOUNT_SID", "XXXXXXX") %>/Messages.json)
I'm guessing this is because Rails 5.2's new encrypted credentials.yml file doesn't get processed with ERB. Anyone have a good workaround? Am I missing something?
Thanks!
I think you're misusing the config/credentials.yml.enc file.
Before that feature, people would use environment variables to store secrets (since it would be bad practice to commit them into your code repository). This was a hassle.
So then, Rails 5.2 introduced the encrypted store. The point is that you don't anymore have to manage environment variables, you just commit directly your secrets into your codebase (but encrypted of course).
So either you write directly your secrets into the config/credentials.yml.enc file, either you want to keep them in environment variables and then just use an initializer file in config/initializers/. Don't do both at the same time.
Have not played with Rails in ages so walking through the Learn Ruby on Rails tutorial which is excellent.
I'm having issues with google authentication, the example code calls the config/secrets.yml variables (which are read from ENV in the shell) from the app/models/contact.rb model update_spreadsheet method below
def update_spreadsheet
connection = GoogleDrive.login(Rails.application.secrets.gmail_username, Rails.application.secrets.gmail_password)
I have the ENV variable set via my ~/.bash_profile and have confirmed using the following code I can make things work, but it's not the example code so I'm just hacking.
def update_spreadsheet
connection = GoogleDrive.login(ENV["GMAIL_USERNAME"], ENV["GMAIL_PASSWORD"])
I can make it work but, I wanted to follow the tutorial and know how to troubleshoot better. if anyone has a pointer it would be appreciated.
Inside my config/secrets.yml file looks like:
development:
gmail_username: <%= ENV["GMAIL_USERNAME"] %>
gmail_password: <%= ENV["GMAIL_PASSWORD"] %>
Thank you
Rails reads secrets.yml but getting the value from secrets.yml is little different then how you had used it, check the code below:
secrets.yml:
development:
secret_key_base: 3b7cd727ee24e8444053437c36cc66c3
some_api_key: SOMEKEY
This is how you can access the value:
Rails.application.secrets.some_api_key returns SOMEKEY
I was having the same issue here and followed all the instructions here and was still experiencing difficulties. My gmail password does not have any special characters, but in my .bash profile I just tried putting single quotes around the contents of the double quotes for both GMAIL_USERNAME and GMAIL_PASSWORD, and it finally worked!
The above solution did not work for me. However, I found the solution on How do I use variables in a YAML file?
My .yml file contained something like:
development:
gmail_username: <%= ENV["GMAIL_USERNAME"] %>
gmail_password: <%= ENV["GMAIL_PASSWORD"] %>
In your .rb file,access the yml file as:
template = ERB.new File.new("path/to/config.yml.erb").read
processed = YAML.load template.result(binding)
So when you introduce a scriptlet tag in .yml file, it is more of erb template. So read it as a erb template first and then load the yml as shown above.
I want to install New Relic on one of my open source rails applications (v 3.2.12). I don't want to have the license key in the repo. I'd like to load it with something like ENV.
By default that's loaded in the newrelic.yml file.
Where is that YAML file loaded? I guess I could manually merge it with a hash that loads the license from the ENV hash.
Any hints on how to do that?
I use the Figaro gem to handle secret keys with ENV environment variables, similar to you. For New Relic, I have:
config/application.yml (.gitignored and not pushed to source control)
# ...
NEW_RELIC_LICENSE_KEY: {{MY_KEY}}
which is then referenced in config/newrelic.yml:
# ...
license_key: <%= ENV['NEW_RELIC_LICENSE_KEY'] %>
A file called config/application.example.yml gets pushed up to the source code repo with instructions to put your own license key in:
config/application.example.yml
# ...
NEW_RELIC_LICENSE_KEY: # put your license key here
Also see this StackOverflow Q&A for more details:
What should be removed from public source control in Ruby on Rails?
I got a useful answer on IRC. newrelic.yml is erb interpolated. Meaning I can just add <%= ENV["NEWRELIC"] %> to the yml file.
Yes to the above answers. also, If you're on Heroku. After installing the NewRelic Addon, you can download newrelic.yml file and change
license_key: to:
license_key: <%= ENV['NEW_RELIC_LICENSE_KEY']%>
This will use the NEW_RELIC_LICENSE_KEY env variable set by the NewRelic addon
This doesn't necessarily answer the exact question you are asking, but this may solve your end goal.
Typically for this type of situation I add the newrelic.yml file to .gitignore and then create a newrelic.yml.example with all the non sensitive fields filled out and a place holder for the key.
This way I can add it into my newrelic.yml file for development and also have the template checked in for others use.
This might be (read: probably is) a dumb question, but here goes...
Is there a simple, preferably non third-party, way to display Rails logs in the browser? It gets kind of old opening a log file, then closing it and re-opening it on the next error. It would be superfantastic to just to go domain.tld/logs, which would require user authentication, of course.
For reference, there is a very simple way to do this. However, you would want to protect this page with some sort of authentication/authorization.
Controller:
lines = params[:lines]
if Rails.env == "production"
#logs = `tail -n #{lines} log/production.log`
else
#logs = `tail -n #{lines} log/development.log`
end
Log File View:
<pre><%= #logs %></pre>
View to display link:
<%= link_to "log file", log_path(lines: 100) %>
Routes:
get 'logs/:lines' => "pages#log", as: "log"
All you need is to open log file and put its content into browser.
Realted topic: ruby: all ways to read from file.
Also you should know that your logs grow very fast, and it's not a good idea to show whole log in browser. You can just open last 100-200 rows. Related topic: Reading the last n lines of a file in Ruby?
Also you can try this solution: http://newrelic.com/. It is more complex and little oftopic, but quite useful.
I created a for this purpose called browserlog.
Installing is just a matter of adding the gem to the Gemfile:
gem 'browserlog'
Afterwards all you need is to mount the engine on the route you want:
MyApp::Application.routes.draw do
mount Browserlog::Engine => '/logs'
end
Once that's set up, accessing /logs/development (or production, test, etc) will show a window like this:
(source: andredieb.com)
Pimp my Log can be used to visualization many types of logs including Ruby on Rails.
It also includes the management of users and notification.
[Edited]
By default, the PimpMyLog does not support Ruby on Rails logs. It's necessary to implement the regex to works with it.
[/Edited]
Trying to use my active record translations in config/locales/de.yml also in my views. I thought I am clever using this:
de:
activerecord:
attributes:
user:
login: "Benutzerkennung"
comment: "Bemerkungen"
And in my view this:
<%= label_tag :login, t('activerecord.attributes.user.login') %>
But instead of the translation value ("Benutzerkennung") I am getting the infamous
"translation missing: de, activerecord, attributes, user, login"
Has anybody got this working (not using the label translation plugin (I am wary of potential side effects), or User.humanize_attribute_name)? What am I missing? (it does work when I use "activerecord1" or something else than activerecord, so my setup seems to be fine)
Thanks!
Ok, my bad, it does work just fine. I fell in the YML formatting trap :(
To help you debug along the way, use "script/console" and the following statements:
- I18n.locale --> should output the locale you want to examine
- I18n.t('activerecord.attributes') --> should give you all the key/value pairs for your translation, if not, you made a formatting error in your YML file or it could not be found
And btw - the plugin works quite well http://github.com/iain/i18n_label/
if you don't like the result of ".human_name" (which the plugin uses), just fall back to I18n.t('your key')
Another method:
<%= label_tag :login, User.human_attribute_name(:login) %>
You should upgrade Rails gem to v2.3.11 (I tried to use 2.3.9, but now days it is not available so I suggest you 2.3.11)!
gem install -v=2.3.11 rails
You can find this issues documented here: Rails 2.3.9 Release notes