Is it possible to directly connect to a Heroku database from localhost? - ruby-on-rails

If I have a DATABASE_URL, is it possible to connect to it from localhost? I'm using the following code:
db = URI.parse(database_url)
connection = ActiveRecord::Base.establish_connection(
:adapter => db.scheme == 'postgres' ? 'postgresql' : db.scheme,
:host => db.host,
:username => db.user,
:password => db.password,
:database => db.path[1..-1],
:encoding => 'utf8'
)
When running the code from my pc, I keep getting errors like:
could not connect to server: Connection timed out
Is the server running on host some_host.amazonaws.com and accepting
TCP/IP connections on port 5432?
I'm using the same code to share a database between two apps that are running on Heroku and it works. This leads me to believe that connecting to a Heroku database is restricted unless you perform it from a Heroku host. Is that true?

Indeed SSL is required for outside connections. The underlying postgres adapter can be forced to use SSL with the sslmode=require parameter. You can pass arbitrary parameters down from the ActiveRecord connection options, like so:
ActiveRecord::Base.establish_connection(
adapter: 'postgresql',
host: 'host',
username: 'user',
password: 'pass',
database: 'database_name',
encoding: 'utf-8',
port: '5432', # could be a non-standard port
sslmode: 'require' # force SSL
)
I've verified this locally, and here's a full session showing it work. Please make sure you're not mistyping anything:
heroku pg:credentials yellow -a my-app Connection info string:
"dbname=ddbolrs4g89dsi host=ec2-23-21-91-108.compute-1.amazonaws.com port=5432 user=itkdrxzjmwcjtw password=wU-4tT3YbF8AZ3U5kwu-2KYPEX ssl
mode=require"
$ irb
> require 'active_record'
=> true
> ActiveRecord::Base.establish_connection(adapter: 'postgresql', database: 'ddbolrs4g89dsi', host: 'ec2-23-21-91-108.compute-1.amazonaws.com', username: 'itkdrxzjmwcjtw', password: 'wU-4tT3YbF8AZ3U5kwu-2KYPEX', sslmodel: 'require')
=> #<ActiveRecord::ConnectionAdapters::ConnectionPool:0x007f7f9ba6f0f0 #mon_owner=nil, #mon_count=0, #mon_mutex=#<Mutex:0x007f7f9ba6f078>, #spec=#<ActiveRecord::Base::ConnectionSpecification:0x007f7f9ba64150 #config={:adapter=>"postgresql", :database=>"ddbolrs4g89dsi", :host=>"ec2-23-21-91-108.compute-1.amazonaws.com", :username=>"itkdrxzjmwcjtw", :password=>"wU-4tT3YbF8AZ3U5kwu-2KYPEX", :sslmodel=>"require"}, #adapter_method="postgresql_connection">, #reserved_connections={}, #queue=#<MonitorMixin::ConditionVariable:0x007f7f9ba6f000 #monitor=#<ActiveRecord::ConnectionAdapters::ConnectionPool:0x007f7f9ba6f0f0 ...>, #cond=#<ConditionVariable:0x007f7f9ba6efd8 #waiters=[], #waiters_mutex=#<Mutex:0x007f7f9ba6ef88>>>, #timeout=5, #size=5, #connections=[], #automatic_reconnect=true>
> ActiveRecord::Base.connection.execute("SELECT version()").first
=> {"version"=>"PostgreSQL 9.1.4 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3, 64-bit"}
> exit
$ # remove db, leaked creds ^
$ heroku addons:remove HEROKU_POSTGRESQL_YELLOW -a my-app --confirm my-app
Removing HEROKU_POSTGRESQL_YELLOW on my-app... done, v490 (free)

Outside connection to the postgresql server require SSL on Heroku. Have a look at the docs as well.

Related

ActionCable and Heroku Redis configuration

Last week RedisToGo was terminated on Herokum, leaving me with no choice but to find an alternative. I got a new subscription from Heroku: Heroku Redis.
Everything seems to work fine (all tasks/jobs) except things related to ActionCable.
[ActionCable] [#######] Registered connection (#########)
2022-08-17T00:40:23.213184+00:00 app[web.1]: #<Thread:0x00007e######/app/vendor/bundle/ruby/2.6.0/gems/actioncable-5.1.7/lib/action_cable/subscription_adapter/redis.rb:144 run> terminated with exception (report_on_exception is true):
2022-08-17T00:40:23.213206+00:00 app[web.1]: /app/vendor/bundle/ruby/2.6.0/gems/redis-4.1.4/lib/redis/client.rb:268:in `rescue in io': Connection lost (ECONNRESET) (Redis::ConnectionError)
I spent the last few days trying all sort of trick, but nothing work.
My cable.yml file looks like:
production:
adapter: redis
url: <%= ENV['REDIS_URL'] %>
my redis.rb file looks like this:
uri = if Rails.env == 'production'
URI.parse(ENV["REDIS_URL"])
else
URI.parse("redis://localhost:6379")
end
Resque.redis = Redis.new(host: uri.host, port: uri.port, password: uri.password, ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE })
Am I missing certain parameters that results in the error ?
I use Heroku Redis and here's what my cable.yml looks like:
development:
adapter: redis
url: redis://localhost:6379/1
channel_prefix: myapp_development
test:
adapter: redis
url: redis://localhost:6379/1
channel_prefix: myapp_test
production:
adapter: redis
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
channel_prefix: myapp_production
ssl_params:
verify_mode: <%= OpenSSL::SSL::VERIFY_NONE %>
If your tasks and jobs don't use Redis (if ActionCable is the only thing trying to use Redis) then your Redis might not actually be set up properly. Here's the documentation.
Check to make sure Heroku actually set a REDIS_URL env variable:
$ heroku config | grep REDIS
> REDIS_URL: redis://h:asdfqwer1234asdf#ec2-111-1-1-1.compute-1.amazonaws.com:111
Make sure your instance has a normal configuration:
https://devcenter.heroku.com/articles/heroku-redis#configuring-your-instance
Two other helpful sources:
How to solve the SSL error for Redis 6 on Heroku
ActionCable Redis adapter crashes with Heroku Redis 6

rails environment mongoid connection issue

I have rails app 3.2.17, deployed in staging environment with unicorn 4.6.3 monitored by bluepill 0.0.66 using mongid 3.1.5
When I deploy for staging environment all works find including active_record except mongoid queries with result with following error:
Error during failsafe response:
Problem:
No configuration could be found for a session named 'default'.
Summary:
When attempting to create the new session, Mongoid could not find a session configuration for the name: 'default'. This is necessary in order to know the host, port, and options needed to connect.
Resolution:
Double check your mongoid.yml to make sure under the sessions key that a configuration exists for 'default'. If you have set the configuration programatically, ensure that 'default' exists in the configuration hash.
mongoid.yml file in deployed station
staging:
sessions:
default:
database: mydb
username: user
password: password
hosts:
- localhost:27017
options:
options:
myapp.pill file in deployed station
Bluepill.application('myapp', log_file: '/var/log/bluepill/myapp.log') do |app|
app.process('myapp-app') do |process|
process.pid_file = '/home/user/myapp/current/tmp/pids/unicorn.pid'
process.working_dir = '/home/user/myapp/current'
process.start_command = '/home/user/.gem/ruby/1.9.1/bin/bundle exec unicorn -c config/unicorn.rb -D -E staging'
process.stop_command = 'kill -QUIT {{PID}}'
process.restart_command = 'kill -USR2 {{PID}}'
process.uid = 'user'
process.gid = 'user'
process.start_grace_time 30.seconds
process.stop_grace_time 30.seconds
process.restart_grace_time 60.seconds
process.monitor_children do |child_process|
child_process.stop_command 'kill -QUIT {{PID}}'
child_process.checks(:mem_usage,
:every => 30.seconds,
:below => 1024.megabytes,
:times => [3,4]
)
child_process.checks(:cpu_usage,
:every => 30.seconds,
:below => 90,
:times => [3,4]
)
end
end
end
I suspect that mongoid is not receiving the RAILS_ENV, but I'm not sure, I check indentation in mongoid.yml. Should another reason that I not find out.
in /config/application.rb type
require 'mongoid'
Mongoid.load!(File.expand_path('mongoid.yml', './config'))
It may be do it via initializer.

Setting up Redis To Go with Heroku and Rails 4.0.0

I am attempting to setup Redis To Go on my Rails 4 app. I want to be able to deploy it to Heroku as well.
So far, this is what I've done:
Through the dashboard.heroku site, I used the one click install for the Nano version of Redis To Go to install the addon to my app.
I added gem 'redis' to my gemfile.
In config/environments/development.rb I added this line:
ENV["REDISTOGO_URL"] = 'redis://redistogo:b9fc604b1c86a1f6c232ce1dd16cd989#albacore.redistogo.com:10280/'
Then, I created a config/initializers/redis.rb file which looks like this:
uri = URI.parse(ENV["redis://redistogo:b9fc604b1c86a1f6d872ce1dd16cd989#albacore.redistogo.com:10280/"] || "redis://localhost:6379/")
REDIS = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
When running a Redis command in my console now, I get this error:
Redis::CannotConnectError: Error connecting to Redis on 127.0.0.1:6379 (ECONNREFUSED)
What am I doing wrong here, and what do I need to do to ensure that I can test in development and deploy to Heroku without any issues?
ENV["REDISTOGO_URL"] should be in the environment on Heroku. I'd remove it from config/environments/development.rb altogether and change the redis.rb initializer to:
uri = URI.parse(ENV.fetch("REDISTOGO_URL", "redis://localhost:6379/"))
REDIS = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
As long as that ENV var isn't set in development, it'll fall back to the local redis installation.
To update brandonhilkert's answer for Rails 4:
uri = ENV["REDISTOGO_URL"] || "redis://localhost:6379/"
REDIS = Redis.new(:url => uri)
Also, you might want to use Redis.current instead of setting a REDIS variable (see here).
For Rails 4 I did the following
In the console:
heroku addons:create redistogo
heroku config:set REDIS_PROVIDER=REDISTOGO_URL
In my Procfile I added:
worker: bundle exec sidekiq
In my 'gemfile.rb' I added:
gem 'redis'
I added the following file, config/initializers/redis.rb:
uri = ENV["REDISTOGO_URL"] || "redis://localhost:6379/"
REDIS = Redis.new(:url => uri)

Error while connecting to a remote solr instance from Sunspot

I am using Sunspot rails(1.1.0). Everything works when I run my Rails
application and the Solr server on the same machine. When I run Solr
server on a different machine, I get the following error:
Errno::ECONNREFUSED: Connection refused - Connection refused
from /opt/tibco/jruby-1.4.0RC1/lib/ruby/1.8/net/http.rb:560:in `initialize'
from /opt/tibco/jruby-1.4.0RC1/lib/ruby/1.8/net/http.rb:560:in `new'
from /opt/tibco/jruby-1.4.0RC1/lib/ruby/1.8/net/http.rb:560:in `open'
After debugging through Sunspot code, I realized that the Solr::Client is connecting to localhost rather than the remote host configured in sunspot.yml. My sunspot.yml file is as follows:
production:
solr:
hostname: kingkong
port: 8983
log_level: WARNING
The build_session method(sunspot_rails-1.1.0/lib/rails.rb:line 24) tries to establish a slave session. The slave_config method ignores the configuration provided in sunspot.yml file. Here is the slave_config method:
def slave_config(sunspot_rails_configuration)
config = Sunspot::Configuration.build
config.solr.url = URI::HTTP.build(
:host => configuration.hostname,
:port => configuration.port,
:path => configuration.path
).to_s
config
end
Is this the intended behavior? Also, has anybody successfully connected to Solr running remotely?
Note:
I was able to work around this issue by monkey patching the
Sunspot::Rails.slave_config method. I added file called sunspot.rb in
configurations/initializers directory.
module Sunspot::Rails
def slave_config(sunspot_rails_configuration)
config = Sunspot::Configuration.build
config.solr.url = URI::HTTP.build(
:host => sunspot_rails_configuration.hostname,
:port => sunspot_rails_configuration.port,
:path => sunspot_rails_configuration.path
).to_s
config
end
end
Sunspot.session = Sunspot::Rails.build_session
I am not sure if this is the correct approach. Please let me know if I am missing something basic.

Different DB connection for individual model depending on environment

I have a Model (MessageImporter) that connects to a different Database than the other models using self.establish_connection. Everything works fine when I pass the connection info hardcoded. Now I need the connection to depend on the current environment. So I added the info to my application_config.yml (it's a simple nifty_config). I got stuck at how to pass the connection info to self.establish_connection.
Here's my current code:
class MessageImporter < ActiveRecord::Base
self.establish_connection lambda {{
:adapter => APP_CONFIG[:external_messages][:adapter],
:host => APP_CONFIG[:external_messages][:host],
:database => APP_CONFIG[:external_messages][:database],
:username => APP_CONFIG[:external_messages][:username],
:password => APP_CONFIG[:external_messages][:password]
}}
# […]
I get an undefined method 'symbolize_keys' for #<Proc:0x2564224>-. Error I also tried it without the lambda, but that does not work either and I get an even weirder error:
Please install the adapter: `gem install activerecord--adapter` (no such file to load -- active_record/connection_adapters/_adapter)
Or is there a better/Rails-ish way to set a different db-connection for individual models?
Little different approach and it works:
Adding the connection info to the regular database.yml:
development:
adapter: mysql
encoding: utf8
reconnect: false
database: […]
pool: 5
username: root
password:
socket: /tmp/mysql.sock
message_import:
adapter: mysql
encoding: utf8
username: […]
password: […]
database: […]
host: […]
Note the nesting! message_import ist nested beneath development.
Within the message_importer.rb:
class MessageImporter < ActiveRecord::Base
establish_connection configurations[RAILS_ENV]['message_import']
Still wondering why my first approach didn't work but this does just as expected.
According to the documentation, the establish_connection method accepts a hash as input. Did you try this?—
class MessageImporter < ActiveRecord::Base
establish_connection {
:adapter => APP_CONFIG[:external_messages][:adapter],
:host => APP_CONFIG[:external_messages][:host],
:database => APP_CONFIG[:external_messages][:database],
:username => APP_CONFIG[:external_messages][:username],
:password => APP_CONFIG[:external_messages][:password]
}

Resources