Heroku - Rails 6 - multi-database - ruby-on-rails

rails: gem "rails", "6.0.0.rc2"
I have multiple databases. None are replicas (I am reading and writing in all 3):
Before rails 6, I used multiverse gem and everything looked fine.I followed rails 6 and multiverse change to rails 6 docs. But I cannot run db:migrate in Heroku, even though, everything works perfectly locally.
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
establish_connection :primary
end
.
class ObsRecord < ActiveRecord::Base
self.abstract_class = true
establish_connection :obs
end
.
class AbcRecord < ActiveRecord::Base
self.abstract_class = true
establish_connection :abc
end
database.yml
staging:
primary:
<<: *default
adapter: postgresql
url: <%= ENV['DATABASE_URL'] %>
username: <%= ENV['DATABASE_USER'] %>
password: <%= ENV['DATABASE_PASSWORD'] %>
obs:
<<: *default
adapter: postgresql
url: <%= ENV['OBS_DATABASE_URL'] %>
username: <%= ENV['OBS_DATABASE_USER'] %>
password: <%= ENV['OBS_DATABASE_PASSWORD'] %>
migrations_paths: db/obs_migrate
abc:
<<: *default
adapter: postgresql
url: <%= ENV['ABC_DATABASE_URL'] %>
username: <%= ENV['ABC_DATABASE_USER'] %>
password: <%= ENV['ABC_DATABASE_PASSWORD'] %>
migrations_paths: db/abc_migrate
rails db:migrate shows nothing, as if there are no migrations but when I run rails c I see the following error. And yes, I am sure the lates code is pushed.
heroku restart is not helping
Heroku error:
Traceback (most recent call last):
102: from /app/bin/rails:4:in `<main>'
101: from /app/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0.rc2/lib/active_support/dependencies.rb:322:in `require'
.
.
4: from /app/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.0.rc2/lib/active_record/connection_handling.rb:50:in `establish_connection'
3: from /app/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.0.rc2/lib/active_record/connection_handling.rb:180:in `resolve_config_for_connection'
2: from /app/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.0.rc2/lib/active_record/connection_adapters/connection_specification.rb:140:in `resolve'
1: from /app/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.0.rc2/lib/active_record/connection_adapters/connection_specification.rb:219:in `resolve_connection'.
.
/app/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.0.rc2/lib/active_record/connection_adapters/connection_specification.rb:251:in `resolve_symbol_connection': The `abc` database is not configured for the `staging` environment. (ActiveRecord::AdapterNotSpecified)
Available databases configurations are:
default
prod_uat_default
development
test
staging
uat
production
^^ I am expecting primary, abc, and obs under staging.
Also, rails -T doesn't show anything regarding to my second and 3rd database

Used the 6.0-stable version and it worked:
gem "rails", github: "rails/rails", branch: "6-0-stable"

Related

Separate read/write configuration/setup for Rails 7 application

rails 7
AWS Aurora RDS Cluster with one write endpoint and one read endpoint
I would like to configure my Rails application to use one endpoint to write and one endpoint to read for the production environment, and a single endpoint for reading/writing in the test environment.
Reading through the documentation, it seems as what I need to do, is that I need to do the following (assuming a production .
In /config/database.yml:
production:
primary:
database: my_primary_database
username: root
password: <%= ENV['PRIDUCTION_ROOT_PASSWORD'] %>
adapter: mysql2
primary_replica:
database: my_primary_database
username: root
password: <%= ENV['PRIDUCTION_ROOT_PASSWORD'] %>
adapter: mysql2
replica: true
test:
database: my_test_database
username: root
password: <%= ENV['TEST_PASSWORD'] %>
adapter: mysql2
Note: the documentation mentions that the username for the writers and replicas should be different, but the AWS Aurora cluster will not allow me to do that. Is this a recommendation or a must?
And this is what I should have in my /app/models/application_record.rb:
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class
if Rails.env == 'production'
connects_to database: { writing: :primary, reading: :primary_replica }
end
end
Then, run the following command:
rails g active_record:multi_db
Which will generate the file: config/initializers/multi_db.rb and inside that file do:
Rails.application.configure do
if Rails.env == 'production'
config.active_record.database_selector = { delay: 2.seconds }
config.active_record.database_resolver =
ActiveRecord::Middleware::DatabaseSelector::Resolver
config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
end
end
Am I missing anything, or do I need to add the following to config/environments/production.rb?
config.active_record.writing_role = :default
config.active_record.reading_role = :readonly
Anything else?

make rake db:create setup another database besides development, test or production

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

ActiveRecord task executing in wrong environment with Whenever

I have to run a Cron task involving some data cleaning in my ActiveRecord database. I am using Whenever gem. Here is the code :
schedule.rb
every 1.hour do
rake 'notifications:clear'
end
notifications.rake
namespace :notifications do
task clear: :environment do
Rpush::Notification.delete_all
end
end
Running this gives me the following error:
rake aborted!
ActiveRecord::NoDatabaseError: FATAL: role "user_prod" does not exist
I am in development environment. Here is my database.yml file :
default: &default
adapter: postgresql
encoding: unicode
# For details on connection pooling, see Rails configuration guide
# http://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development:
<<: *default
database: development_database
test:
<<: *default
database: test_database
staging:
<<: *default
database: staging_database
username: user_staging
password: <%= ENV['DATABASE_PASSWORD'] %>
production:
<<: *default
database: production_database
username: user_prod
password: <%= ENV['DATABASE_PASSWORD'] %>
Any ideas on why my ActiveRecord instruction seems to connect to my production environment ? Thanks in advance !
Update Your code with below :-
In schedule.rb file :-
every 1.hour do
rake 'notifications:clear', :environment => "development"
end
And finally executed this command :-
whenever --update-crontab
OR
Clear existing cron jobs.
crontab -r
Update cronjob with the environment.
whenever --update-crontab --set environment='development'

Passing ENV variables to database.yml in Rails

Here is my database.yml config:
development:
adapter: ibm_db
username: "username"
password: "password"
database: '*LOCAL'
schema: <%= ENV['CA_SCHEMA'] %>
ibm_i_isolation: 'none'
Here is my initializer:
module Ca2eModelExtractor
class Application < Rails::Application
config.before_configuration do
ENV['CA_SCHEMA']= 'XAMDL'
end
end
end
After running rails c I did ENV['CA_SCHEMA'] and saw XAMDL as an output, so it works as expected. But when I run ActiveRecord::Base.configurations, I got a hash, where schema is nil. Any ideas?

undefined method `geometry' for ActiveRecord::ConnectionAdapters::PostgreSQL

I have created a rails application using postgres database. I am using postgis extension for geo queries. The app is running successfully on my development(local) machine but after deploying my code on heroku server when I run heroku run rake db:migrate it is throwing an error, saying undefined method geometry for ActiveRecord ConnectionAdapters PostgreSQL.
I have geometry datatype in some migrations for storing latitude and longitude.
Note that I have also created PostGIS extension on heroku. And migrations that does not contain geometry datatype executed successfully.
My files are:
Gemfile
ruby "2.3.0"
gem 'rails', '>= 5.0.0.beta3', '< 5.1'
gem 'pg', '~> 0.18'
gem 'rgeo'
gem 'rgeo-activerecord', "~> 5.0.0.beta"
gem "activerecord-postgis-adapter", "~> 4.0.0.beta2"
psql --version is: 9.5.2 on heroku server
psql --version is: 9.4.7 on local server
database.yml
default: &default
adapter: postgis
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development:
<<: *default
database: ad_development
production:
<<: *default
database: ad_production
username: ad
password: <%= ENV['DATABASE_PASSWORD'] %>
create_cities migration
def change
create_table :cities do |t|
t.string :name
t.references :state, foreign_key: true
t.geometry :lat_lan
end
heroku run rake db:migrate stops here only.
I am totally confused whether I have used inappropriate gems or I have misconfigured something. Please help!
If using the DATABASE_URL environment variable to set the database connection string, ensure it has the postgis:// (not postgres://) prefix.
ie. postgis://username:password#db_server_url:5432/dbname
url: <%= ENV.fetch('DATABASE_URL', '').sub(/^postgres/, 'postgis') %>
EDIT:
It replaces the url scheme postgres://somewhere.com to postgis://somewhere.com.
It changes to the GIS "protocol", like changing http to https.
You have to replace postgresql with postgis in your database.yml file for the adapter option.
E.g.
default: &default
adapter: postgis
encoding: unicode
pool: <%= ENV["DB_POOL"] || ENV['MAX_THREADS'] || 5 %>
url: <%= ENV['DATABASE_URL'] %>
development:
<<: *default
database: yourapp_development

Resources