In my database.yml, I have:
staging:
adapter: <%= ENV['DATABASE_ADAPTER'] %>
encoding: <%= ENV['DATABASE_ENCODING'] %>
database: <%= ENV['DATABASE'] %>
host: <%= ENV['DATABASE_HOST'] %>
port: <%= ENV['DATABASE_PORT'].to_i %>
pool: <%= ENV['DATABASE_POOL'].to_i %>
username: <%= ENV['DATABASE_USERNAME'] %>
password: <%= ENV['DATABASE_PASSWORD'] %>
However, it does not read the ERB part when actually booting puma:
/usr/local/lib/ruby/gems/2.1.0/gems/activesupport-4.2.1/lib/active_support/dependencies.rb:274:in
`require': Could not load 'active_record/connection_adapters/<%= ENV['DATABASE_ADAPTER'] %>_adapter'.
Make sure that the adapter in config/database.yml is valid. If you use an adapter other than 'mysql', 'mysql2', 'postgresql' or 'sqlite3'
add the necessary adapter gem to the Gemfile. (LoadError)
which makes no sense, since in the Rails code to load the database configuration:
def database_configuration
yaml = Pathname.new(paths["config/database"].existent.first || "")
config = if yaml.exist?
require "yaml"
require "erb"
YAML.load(ERB.new(yaml.read).result) || {}
elsif ENV['DATABASE_URL']
# Value from ENV['DATABASE_URL'] is set to default database connection
# by Active Record.
{}
else
raise "Could not load database configuration. No such file - #{yaml}"
end
config
rescue Psych::SyntaxError => e
raise "YAML syntax error occurred while parsing #{paths["config/database"].first}. " \
"Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
"Error: #{e.message}"
rescue => e
raise e, "Cannot load `Rails.application.database_configuration`:\n#{e.message}", e.backtrace
end
(taken from the Rails 4.2 stable code, I'm running 4.2.1)
I'm absolutely baffled why this isn't working, any ideas?
I just experienced the same thing, and came across your post. I had been following a tutorial that had me create a puma.conf file that contained the code below:
ActiveRecord::Base.establish_connection( YAML.load_file( "#{app_dir}/config/database.yml" )[rails_env])
I modified to the following, and everything worked as expected:
require 'erb'
ActiveRecord::Base.establish_connection( YAML.load( ERB.new( File.read( "#{app_dir}/config/database.yml" )).result)[rails_env])
Related
I have a ERB(database.yml.erb) file template for database.yml for rendering using chef 11.10
I want to have an output(after rendering in chef) in database.yml, like below:
default: &default
adapter: mysql2
username: <%= ENV['diff_db_user'] || <username> %>
password: <%= ENV['diff_db_password'] || <password> %>
...
In the above yaml, I expect the values <username> and <password> are substituted from #node[:database][:username] & #node[:database][:password]
So, the reason I wanted to do this is, to use a different password just by setting the environment variable while running a rake job like db migration
So, I tried the above with using escaping the erb tag as mentioned in How do I escape the ERB tag in ERB but in the output yml I could see the value is not substituted, it just prints the variable itself
for example I had an erb like this:
default: &default
adapter: mysql2
username: <%%= ENV['diff_db_user'] || #node[:database][:username] %>
password: <%%= ENV['diff_db_password'] || #node[:database][:password] %>
...
The output I'm getting for it is:
default: &default
adapter: mysql2
username: <%= ENV['diff_db_user'] || #node[:database][:username] %>
password: <%= ENV['diff_db_password'] || #node[:database][:password] %>
...
So, wanted to know is there any other way for to get printed like the one I initially mentioned at the top, when using template in chef to render the erb to yml
You could add another item in database.yml
development_with_password:
adapter: mysql2
username:
password:
and call it in your rake task e.g.
RAILS_ENV=development_with_password rails db:migrate
Something like this?! You need yo use nested <% %> tags, escaping the outer ones. Also don't forget the quotes.
username: <%%= ENV['diff_db_user'] || "<%= #node[:database][:username] %>" %>
password: <%%= ENV['diff_db_password'] || "<%= #node[:database][:password] %>" %>
I'm using rails 4.2 and trying to configure (in a already established application) the Audited Gem following this second database approach.
My config/database.yml file was as follows:
default: &default
adapter: mysql2
pool: 5
timeout: 5000
development:
<<: *default
host: <%= ENV["MYSQL_HOST"] %>
username: <%= ENV["MYSQL_USER"] %>
password: <%= ENV["MYSQL_PASSWORD"] %>
database: <%= ENV["MYSQL_DATABASE"] %>
test:
<<: *default
host: <%= ENV["MYSQL_HOST"] %>
username: <%= ENV["MYSQL_USER"] %>
password: <%= ENV["MYSQL_PASSWORD"] %>
database: <%= ENV['TEST_ENV_DB'] %>
And I intend to make it work for another db, besides development, test or production. However the task rake db:create only creates my development and test database. Is this possible to accomplish in my rails version?
audition:
<<: *default
host: <%= ENV["MYSQL_HOST"] %>
username: <%= ENV["MYSQL_USER"] %>
password: <%= ENV["MYSQL_PASSWORD"] %>
database: <%= ENV["AUDITION_DATABASE"] %>
Note the new name for audition database
if you want to read/write to a seconds database in rails < 6
create a module
module AuditionConn
def self.included(base)
base.class_eval do
if Rails.env == 'development'
establish_connection "audition-development" # database.yml
else
establish_connection "audition-production" # database.yml
end
end
end
end
then include it in any model you want to read/write from/to auditions database
class AuditionDBModel < ActiveRecord::Base
include AuditionConn
end
migration for second database
def up
AuditionDBModel.connection.create_table ... do |t|
...
AuditionDBModel.connection.change_column ...
end
I think you want to create a new environment call audition, Right?!.
Clone an existing environment file for instance, config/environments/test.rb and rename it config/environments/audition.rb
Add a new configuration block in config/database.yml for your environment.
Update any other configuration file you might have under the config folder with your new environment, some gems need to config it.
Now you can start the server
rails server -e audition
I think this may help you:
create another model for audit:
class AuditModel < ActiveRecord::Base
connects_to database: { writing: :audit_db, reading: :audit_db}
end
or
ActiveRecord::Base.establish_connection(
adapter: "mysql2",
host: "localhost",
username: "myuser",
password: "mypass",
database: "somedatabase"
)
for details:
https://guides.rubyonrails.org/active_record_multiple_databases.html
https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionHandling.html
Here is the tutorial which I follow for implement: Finally Trying ActionCable
This code is too long, so I don't put this code into this question I just put some of the codes as like into the user model
def online_now?
$redis.get("users:online:#{id}").present?
end
and the view is:
<% User.all.each do |user| %>
<%= user.name %>
<div class="online-indicator">
<% if !user.online_now? && 'xs-none' %>
Online
<% else %>
Offline
<% end %>
</div>
<% end %>
but always throwing an error as like
NoMethodError - undefined method get' for nil:NilClass
Did you mean? gem:
app/models/user.rb:34:inonline_now?'
which indicating this line
$redis.get("users:online:#{id}").present?
I don't why throwing this error.
But it's working on rails console as like
irb(main):005:0> redis.set("mykey", "hello world")
=> "OK"
irb(main):006:0> redis.get("mykey")
=> "hello world"
Thanks
From comment #Ilya Konyukhov how do you define $redis variable in your model method. It's clear it should be a Redis API, but where do you connect to the Redis and store its connection?
Yes, that is a very nice comment & helpful for clearing the concept from a commentator.
If your Redis server is running in the system then need to configure this in Rails own way, I would writing some configuration files & if you already created that you can compare these & if you not created till now I think that is the issue & need to create ASAP if you need this feature.
First, install the gem redis-rails
gem 'redis-rails'
after that add this into environment file
config.cache_store = :redis_store, {
host: "localhost",
port: 6379,
db: 0,
password: "mysecret",
namespace: "cache"
}, {
expires_in: 90.minutes
}
create a file into app/config/initializer/ which redis.rb then put into this
$redis = Redis.new(:host => 'localhost', :port => 6379)
after all restart the server and check it out.
make sure redis-server is running.
Hope it will work.
I've been trying to debug my credentials file in my staging server. Whenever I try to edit the credentials on my staging server, I get the following error:
/var/www/bundle/ruby/2.5.0/gems/railties-5.2.0/lib/rails/application.rb:583:in `validate_secret_key_base': `secret_key_base` for staging environment must be a type of String`
My database.yml file looks like the following:
---
default: &default
adapter: postgresql
development:
<<: *default
database: dev_db
host: <%= Rails.application.credentials.database.fetch(:development).fetch(:host) %>
username: <%= Rails.application.credentials.database.fetch(:development).fetch(:username) %>
password: <%= Rails.application.credentials.database.fetch(:development).fetch(:password) %>
secret_key_base: <%= Rails.application.credentials.secret_key_base.fetch(:development) %>
test:
<<: *default
database: test_db
host: <%= Rails.application.credentials.database.fetch(:development).fetch(:host) %>
username: <%= Rails.application.credentials.database.fetch(:development).fetch(:username) %>
password: <%= Rails.application.credentials.database.fetch(:development).fetch(:password) %>
secret_key_base: <%= Rails.application.credentials.secret_key_base.fetch(:development) %>
staging:
<<: *default
database: <%= Rails.application.credentials.database.fetch(:staging).fetch(:name) %>
host: <%= Rails.application.credentials.database.fetch(:staging).fetch(:host) %>
username: <%= Rails.application.credentials.database.fetch(:staging).fetch(:username) %>
password: <%= Rails.application.credentials.database.fetch(:staging).fetch(:password) %>
secret_key_base: <%= Rails.application.credentials.secret_key_base.fetch(:staging) %>
production:
<<: *default
database: <%= Rails.application.credentials.database.fetch(:production).fetch(:name) %>
host: <%= Rails.application.credentials.database.fetch(:production).fetch(:host) %>
username: <%= Rails.application.credentials.database.fetch(:production).fetch(:username) %>
password: <%= Rails.application.credentials.database.fetch(:production).fetch(:password) %>
secret_key_base: <%= Rails.application.credentials.secret_key_base.fetch(:production) %>
I think my staging's secret_key_base is of type String. I generated my secret_key_base using rails secret. Locally, when I bring up the rails console, I can view the secret_key_bases for my staging environment:
[1] pry(main)> Rails.application.credentials.secret_key_base.fetch(:staging)
\=> "generated_using_rails_secret"
It returns a string but I still get the error message above whenever I try to access credentials in my staging environment.
I ended up looking at the stack trace and digging into the railties-5.2.0 gem.
Abbreviated stack trace:
ArgumentError: `secret_key_base` for staging environment must be a type of String`
/var/www/bundle/ruby/2.5.0/gems/railties-5.2.0/lib/rails/application.rb:583:in `validate_secret_key_base'
/var/www/bundle/ruby/2.5.0/gems/railties-5.2.0/lib/rails/application.rb:432:in `secret_key_base'
/var/www/bundle/ruby/2.5.0/gems/railties-5.2.0/lib/rails/application.rb:176:in `key_generator'
/var/www/bundle/ruby/2.5.0/gems/railties-5.2.0/lib/rails/application.rb:205:in `message_verifier'
I ended up looking in railties-5.2.0/lib/rails/application.rb:432: and seeing the following bit of code:
# The secret_key_base is used as the input secret to the application's key generator, which in turn
# is used to create all MessageVerifiers/MessageEncryptors, including the ones that sign and encrypt cookies.
#
# In test and development, this is simply derived as a MD5 hash of the application's name.
#
# In all other environments, we look for it first in ENV["SECRET_KEY_BASE"],
# then credentials.secret_key_base, and finally secrets.secret_key_base. For most applications,
# the correct place to store it is in the encrypted credentials file.
def secret_key_base
if Rails.env.test? || Rails.env.development?
Digest::MD5.hexdigest self.class.name
else
validate_secret_key_base(
ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
)
end
end
I had mistakenly thought I could specify a SECRET_KEY_BASE for an individual environment. Instead, I could only specify one secret key base. The secret key base apparently has nothing to do with database.yml. I need to read up on it and what it actually does.
If you run rails credentials:edit from the command line it will decrypt the config/credentials.yml.enc file.
You can then edit this file to add environment based secret keys like you would have previously added to config/secrets.yml.
When you save this file it will be encrypted again with the new information included.
There is no reason to have the "secret_key_base" in your database.yml file as this will not have any impact.
Nice Article on the new Rails credentials
Additionally just because rails now longer generates a config/secrets.yml file for you, as of rails 5.2, adding one will still work appropriately as it has in previous releases.
I am trying to setup Recaptcha in my rails 5 application as it's described in the documentation but it fails.
I use this gem: recaptcha (4.6.6), ruby 2.5.0 and rails 5.1.4
In view form:
<%= flash[:recaptcha_error] %>
<%= recaptcha_tags %>
In devise registrations controller:
prepend_before_action :check_captcha, only: :create
private
def check_captcha
unless verify_recaptcha
self.resource = resource_class.new sign_up_params
resource.validate # Look for any other validation errors besides Recaptcha
respond_with_navigational(resource) { redirect_to new_user_registration_path }
end
end
In my initializers/recaptcha.rb
Recaptcha.configure do |config|
config.site_key = Rails.application.config_for(:recaptcha)['site_key']
config.secret_key = Rails.application.config_for(:recaptcha)['secret_key']
end
In my recaptcha.yml:
default: &default
site_key: <%= ENV["RECAPTCHA_SITE_KEY"] %>
secret_key: <%= ENV["RECAPTCHA_SECRET_KEY"] %>
development:
<<: *default
test:
<<: *default
staging:
<<: *default
production:
<<: *default
In /etc/environments:
# RECAPTCHA
RECAPTCHA_SITE_KEY=6Lfg3ksUAAAAABOD_OXCtPO60*******
RECAPTCHA_SECRET_KEY=6Lfg3ksUAAAAAOmFGdAxdo8*******
PROBLEM
After adding ENV variables to /etc/environments, I exported it with this command:
for line in $( cat /etc/environment ) ; do export $line ; done
Then I check that Recaptcha module is configured correctly:
/home/deploy/apps/app_name/current$ bundle exec rails c
Loading staging environment (Rails 5.1.4)
2.5.0 :001 > Recaptcha::Configuration.new
=> #<Recaptcha::Configuration:0x0000000006601908 #skip_verify_env=["test", "cucumber"], #handle_timeouts_gracefully=true, #secret_key="6Lfg3ksUAAAAAOmFGdAxdo8H*************", #site_key="6Lfg3ksUAAAAABOD_OXCtPO*************">
2.5.0 :002 > Recaptcha::Configuration.new.site_key!
=> "6Lfg3ksUAAAAABOD_OXCtPO*************"
Also, I see these ENV variables when I run printenv command (so it's really loaded)
After that, I restarted rails and got an error
No site key specified.
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/recaptcha-4.6.6/lib/recaptcha/configuration.rb:47:in `site_key!'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/recaptcha-4.6.6/lib/recaptcha/client_helper.rb:79:in `recaptcha_components'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/recaptcha-4.6.6/lib/recaptcha/client_helper.rb:15:in `recaptcha_tags'
/home/deploy/apps/app_name/releases/20180310222304/app/views/users/registrations/new.html.erb:27:in `block in _app_views_users_registrations_new_html_erb___216558772140569572_69973306795360'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/actionview-5.1.4/lib/action_view/helpers/capture_helper.rb:39:in `block in capture'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/actionview-5.1.4/lib/action_view/helpers/capture_helper.rb:203:in `with_output_buffer'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/actionview-5.1.4/lib/action_view/helpers/capture_helper.rb:39:in `capture'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/actionview-5.1.4/lib/action_view/helpers/form_helper.rb:450:in `form_for'
/home/deploy/apps/app_name/releases/20180310222304/app/views/users/registrations/new.html.erb:21:in `_app_views_users_registrations_new_html_erb___216558772140569572_69973306795360'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/actionview-5.1.4/lib/action_view/template.rb:157:in `block in render'
I am posting here in case someone is looking for a Rails 5.2 solution to setting up Recaptcha keys. This solution utilizes the new config/master.key and config/credentials.yml.enc encryption file.
Add the Recaptcha keys to the credentials.yml.enc file by editing the file in your local terminal:
EDITOR="vim" rails credentials:edit
After adding the keys to the credentials file (see example below), save and exit the file. Upon exit, the credentials.yml.enc file will then be automatically encrypted. The master.key is necessary for decryption by your application. Before encryption:
recaptcha_site_key: 6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy
recaptcha_secret_key: 6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxx
3. Create a file named config/recaptcha.rb in your Rails application and add the following code to it:
Recaptcha.configure do |config|
config.site_key = Rails.application.credentials.dig(:recaptcha_site_key)
config.secret_key = Rails.application.credentials.dig(:recaptcha_secret_key)
end
This solution works locally and on Ubuntu/nginx in production. You won't need a gem or environment variables for it to work. If the master.key fails to decrypt, you may need to delete both the credentials.yml.enc file and possibly even the master.key file, then repeat this process locally (EDITOR="vim" rails credentials:edit, etc.) before copying over a new master.key to production and re-deploying.
I still don't know what is the cause of the "No site key specified" error.
I really don't like gem 'recapthca' works directly with ENV variables,
and also I spent too much time on investigations.
So, I decided to not use this gem and write my own code.
I use only Invisible Recaptcha in my application.
Config file (loads secret and site keys)
# /config/recaptcha.yml
default: &default
site_key: <%= ENV["RECAPTCHA_SITE_KEY"] %>
secret_key: <%= ENV["RECAPTCHA_SECRET_KEY"] %>
development:
<<: *default
test:
<<: *default
staging:
<<: *default
production:
<<: *default
Application helper (a button with Recaptcha helper)
# /app/helpers/application_helper.rb
module ApplicationHelper
def submit_with_recaptcha(text, custom_options)
unless custom_options[:data].has_key?(:form_id)
raise "Data Form Id option not found ('{data: {form_id: 'id_without_dash'}')."
end
options = {
type: 'button',
data: {
form_id: custom_options[:data][:form_id],
sitekey: recaptcha_site_key,
callback: "submit#{custom_options[:data][:form_id].camelize}#{Time.current.to_i}"
},
class: (custom_options[:class].split(' ') + ['g-recaptcha']).uniq.join(' ')
}
script_code = <<-SCRIPT
function #{options[:data][:callback]}() {
document.getElementById('#{options[:data][:form_id]}').submit();
}
SCRIPT
javascript_tag(script_code) + content_tag(:div, class: 'recaptcha_wrapper'){ submit_tag(text, options) }
end
private
def recaptcha_site_key
Rails.application.config_for(:recaptcha)['site_key']
end
end
Verification service (as it uses external API)
# app/services/google_recaptcha/verification.rb
module GoogleRecaptcha
# https://developers.google.com/recaptcha/docs/verify
class Verification
# response - params['g-recaptcha-response'])
def self.successful?(recaptcha_params, remoteip)
verify_url = URI.parse('https://www.google.com/recaptcha/api/siteverify')
verify_request = Net::HTTP::Post.new(verify_url.path)
verify_request.set_form_data(
response: recaptcha_params,
secret: secret_key,
remoteip: remoteip
)
connection = Net::HTTP.new(verify_url.host, verify_url.port)
connection.use_ssl = true
Rails.logger.info '[RECAPTCHA] Sending verification request.'
verify_response = connection.start { |http| http.request(verify_request) }
response_data = JSON.parse(verify_response.body)
Rails.logger.info "[RECAPTCHA] Verification response is#{' not' unless response_data['success']} successful."
response_data['success']
end
private
def self.secret_key
Rails.application.config_for(:recaptcha)['secret_key']
end
end
end
Controller Concern (Recaptcha verification in before_action)
# app/controllers/concerns/recaptchable.rb
module Recaptchable
extend ActiveSupport::Concern
included do
before_action :verify_recaptcha, only: [:create]
end
private
def verify_recaptcha
unless GoogleRecaptcha::Verification.successful?(recaptcha_params['g-recaptcha-response'], request.remote_ip)
render :new
return
end
end
def recaptcha_params
params.permit(:'g-recaptcha-response')
end
end
Usage
Add concern to your controller:
class MyController < ShopController
include Recaptchable
end
Add www.google.com/recaptcha/api.js javascript to your page
Add submit_with_recaptcha helper into your form
<%= form_for #delivery, url: users_delivery_path, method: 'post' do |f| %>
<%= submit_with_recaptcha t('order.deliver.to_confirmation'), data: {form_id: 'new_delivery'}, class: 'btn-round' %>
<% end %>
<%= javascript_include_tag "https://www.google.com/recaptcha/api.js?hl=#{I18n.locale}", 'data-turbolinks-track': 'reload' %>
That's it.
Note: I'm posting this answer here for people who may find this question. Here is how I solved the problem.
I use local_env.yml for my environment variables. I just started using the gem and added RECAPTCHA_SITE_KEY & RECAPTCHA_SECRET_KEY to local_env.yml. I got the same error.
It took a bit to figure out that the gem directly used the variables. I ended up putting the following statements in ~/.bashrc similar to what the documentation said but without the quotes around the values.
export RECAPTCHA_SITE_KEY=6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy
export RECAPTCHA_SECRET_KEY=6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx
I host my applications on Heroku. I executed the following terminal commands to set my environment variables in Heroku.
heroku config:set RECAPTCHA_SITE_KEY=‘6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy’
heroku config:set RECAPTCHA_SECRET_KEY=‘6LcGuI4U6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxxAAAAGAWMYRKFGfHUCSD0SPrMX2lfyl9’
Are you using nginx? Nginx removes ENV vars (except TZ) and it seems that the recaptcha gem is particularly sensitive to this. From experience, when using the dotenv gem other ENV vars work ok, recaptcha ENV vars are ignored.
You can solve the issue by adding the env vars to the top of your nginx.conf.
env RECAPTCHA_SITE_KEY=value1;
env RECAPTCHA_SECRET_KEY=value2;
Here's nginx's documentation on the matter.