Creating MongoDB indexes via Mongoid in non-Rails environment - ruby

I am trying to build a Roda-based (non-Rails) API using MongoDB as my database. I installed Mongoid gem and configured the connection. Unfortunately, when I am trying to create defined indexes using rake db:mongoid:create_indexes, the task fails due to the lack of environment one. What should I do/include in my Rakefile to provide the required task?
Backtrace:
rake aborted!
Don't know how to build task 'environment' (See the list of available tasks with `rake --tasks`)
/home/tomasz/.rvm/gems/ruby-2.7.1/bin/ruby_executable_hooks:24:in `eval'
/home/tomasz/.rvm/gems/ruby-2.7.1/bin/ruby_executable_hooks:24:in `<main>'
Tasks: TOP => db:mongoid:create_indexes
(See full trace by running task with --trace)
Relevant part of my Rakefile:
require 'mongoid'
path = Gem::Specification.find_by_name('mongoid')
load "#{path.gem_dir}/lib/mongoid/railties/database.rake"
rake -T output:
rake db:create_indexes # Create indexes specified in Mongoid models
rake db:drop # Drops all the collections for the database for the current Rails.env
rake db:mongoid:create_indexes # Create indexes specified in Mongoid models
rake db:mongoid:drop # Drop the database of the default Mongoid client
rake db:mongoid:purge # Drop all non-system collections
rake db:mongoid:remove_indexes # Remove indexes specified in Mongoid models
rake db:mongoid:remove_undefined_indexes # Remove indexes that exist in the database but are not specified in Mongoid models
rake db:mongoid:shard_collections # Shard collections with shard keys specified in Mongoid models
rake db:purge # Drop all collections except the system collections
rake db:remove_indexes # Remove indexes specified in Mongoid models
rake db:reset # Delete data and loads the seeds
rake db:seed # Load the seed data from db/seeds.rb
rake db:setup # Create the database, and initialize with the seed data
rake db:shard_collections # Shard collections with shard keys specified in Mongoid models

You need to:
Define a task called environment,
In this task load all of your model classes.
How to load your model classes depends on your application.

Related

Hanami rake task does not load repositories

I have hanami 1.3.0 app named booking. There is rake task in /rakelib/motel.rake :
require_relative '../lib/booking' # it requires booking/motel/booker file
namespace :motel do
task :book do
Booking::Motel::Booker.new.book
end
end
booking/motel/booker requires booking_repository file, and tries to instantiate BookingRepository, but fails with error:
NameError: uninitialized constant Hanami::Repository
<root>/lib/booking/repositories/booking_repository.rb:1:in <top (required)>'
However, when I run Booking::Motel::Booker.new.book in hanami console, it loads BookingRepository without problems.
Looked at numerous stack questions regarding hanami rake, but couldn't find an answer.
As it turns out, it was a foolish mistake. I forgot to add :environment to my task.
namespace :motel do
task book: :environment do
Booking::Motel::Booker.new.book
end
end
That fixed it and dropped the need to use manual file loading, of course.

ActiveRecord::NoEnvironmentInSchemaError

I'm trying to perform database related operations on my newly upgraded app(Rails 5) and I'm unable to perform destructive database commands locally.
rails db:reset or rails db:drop .
The trace results with the following data,
rails db:drop --trace
** Invoke db:drop (first_time)
** Invoke db:load_config (first_time)
** Execute db:load_config
** Invoke db:check_protected_environments (first_time)
** Invoke environment (first_time)
** Execute environment
** Invoke db:load_config
** Execute db:check_protected_environments
rails aborted!
ActiveRecord::NoEnvironmentInSchemaError:
Environment data not found in the schema. To resolve this issue, run:
bin/rails db:environment:set RAILS_ENV=development
What I've tried so far are,
Setting bin/rails db:environment:set RAILS_ENV=development, doesn't change anything still the error occurs.
Setting Environment variable manually to development.
None of these helped. I'm Looking for a fix or workaround.
Two Fixes to ActiveRecord::NoEnvironmentInSchemaError
The other answers here describe the problem very well, but lack proper solutions. Hoping this answer helps someone experiencing this issue.
Why this error is happening
This incorrect error message is a result of this pull request designed to prevent destructive actions on production databases. As u/pixelearth correctly points out, Rails 4.2 defines the 'key' field in the ar_internal_metadata table to be an integer, and Rails 5+ (including Rails 6) expects this to be a string with the value, environment. When Rails 5 and Rails 6 run this safety check, they incorrectly raise an ActiveRecord::NoEnvironmentInSchemaError as the code is incompatible with the Rails 4 schema format.
Fix #1: Override the safety check in Rails 5+
**Please remember, the safety check was implemented as a result of so many users dropping their production databases by accident. As the question describes, the operations are destructive.
From the terminal:
rails db:drop RAILS_ENV=development DISABLE_DATABASE_ENVIRONMENT_CHECK=1
# and/or
rails db:drop RAILS_ENV=test DISABLE_DATABASE_ENVIRONMENT_CHECK=1
As noted here, the DISABLE_DATABASE_ENVIRONMENT_CHECK=1 flag disables the environment check. After, you can run a rake db:create RAILS_ENV=development, for example, to recreate your database with the correct schema in the ar_internals_metadata table.
Fix #2: Revert to Rails 4, drop database, go back to Rails 5+ and recreate
From the terminal:
git log
# grab the commit hash from before the upgrade to Rails 5+
git checkout **hash_from_rails_4**
rake db:drop RAILS_ENV=development
rake db:drop RAILS_ENV=test
git checkout master
# now things should work
rails db:migrate
Again, please ensure you are not pointing at a production database when overriding this functionality. Alternatively, it would be possible to directly modify the schema of this table. If you're experiencing this error in production, you may need to take this approach.
This happened because, for some reason, your table ar_internal_metadata got deleted or changed.
If you cannot drop the database via the command line, you need to do it via your DBMS or database client.
Then, just run rails db:create db:migrate to create and run the migrations.
For posterity, my issue was that this schema was generated by a rails 4 app and the current app using it is rails 5. With rails 5 the structure of the ar_internal_metadata table has changed slightly. The key field needs to be a string and contain the word 'environment', not an integer. This error only goes away when this is changed.
It should look like this in Rails 5
ie, change the type of ar_internatl_metadata #key to string...
My situation is a bit uncommon involving a rails 4 app and a rails 5 app sharing the same db. When I need to "update", I have a task:
puts "Modifying Rails 4 schema to fit Rails 5 schema"
file_name = "./db/schema.rb"
rails_4_ar_internal_metadata = 'create_table "ar_internal_metadata", primary_key: "key", force: :cascade do |t|'
rails_5_ar_internal_metadata = 'create_table "ar_internal_metadata", primary_key: "key", id: :string, force: :cascade do |t|'
new_schema = File.read(file_name).gsub(rails_4_ar_internal_metadata, rails_5_ar_internal_metadata)
File.write(file_name, new_schema)
Console rails
bin/rails db:environment:set RAILS_ENV=development
I had
bundle exec rake db:drop
rake aborted!
ActiveRecord::NoEnvironmentInSchemaError:
Environment data not found in the schema. To resolve this issue, run:
rails db:environment:set RAILS_ENV=development
And, indeed, simply running rails db:environment:set RAILS_ENV=development made the problem go away.
Why did this happen?
It happened because I tried to drop the database and create it / migrate it, however, I had a syntax error in the migration (datatype and column name in the wrong places). Check your migration file for any silly errors
Specifically I had
t.submitted :boolean, default: false
instead of
t.boolean :submitted, default: false

Ruby Rake ActiveRecord Migrate

I'm trying to build a simple ruby script that connects to a database and runs some basic queries.
The code is here: https://github.com/mastermindg/rack-activrecord-example
It's not a service - only a script that is run manually to do batch jobs. My problem is that I need to populate the database for testing purposes. I know how to do this in Sinatra and Rails but it's failing as-is:
NoMethodError: undefined method `set' for main:Object
Did you mean? send
/usr/src/app/app.rb:7:in `<top (required)>'
/usr/src/app/Rakefile:2:in `<top (required)>'
I've got the database.yml but I can't tell how to load it since set is failing.
How do I connect to and query a database using ActiveRecord with basic Rack?
1) Add this to your Rakefile after the requires:
DatabaseTasks.database_configuration = YAML.load(File.read(File.join(root, 'config/database.yml')))
2) Remove set :database_file, 'config/database.yml' from your app.rb file (I think set is a sinatra/activerecord method).
Running rake db:create may give you an error on your project now,because you're using json instead of JSON in your app.rb file (depending on your local versions), so. . .
3) Change puts json Resource.select('id', 'name').all to puts JSON Resource.select('id', 'name').all in your app.rb file.
Now rake db:create will throw a database error, but that's an error related to your specific database configuration, make an appropriate adjustment to that (this is off-topic from the original question, so I won't address it further) and your app should run as you desire.
More info:
This gist shows example contents of a Rakefile that you could use to run Active Record tasks without using Rails or Sinatra.

Sequel generate migration

I see that the Sequel gem supports migrations here, but I don't see any type of generator documented. Does one exist; or should I be manually creating all of my migrations (or alternately creating my own task to generate migrations)?
From the documentation:
Sequel doesn't come with generators that create migrations for you. However, creating a migration is as simple as creating a file with the appropriate filename in your migrations directory that contains a Sequel.migration call.
The contents of the migration file doesn't have to specify a timestamp or index and it's an extremely simple format.
I generally just copy a previous migration (maybe one similar to the migration I'm creating) and alter the filename. See existing migrations with:
$ ls -1 db/migrate/
20170320075430_check_postgres_extensions.rb
...
For running migrations, I use the rake task that's available here.
Sequel has no migration generator. But you can easily write your own, for example using a rake task. Here is one:
# Rakefile
require 'fileutils'
namespace :db do
MIGRATIONS_DIR = 'db/migrations'
desc "generates a migration file with a timestamp and name"
task :generate_migration, :name do |_, args|
args.with_defaults(name: 'migration')
migration_template = <<~MIGRATION
Sequel.migration do
up do
end
down do
end
end
MIGRATION
file_name = "#{Time.now.strftime('%Y%m%d%H%M%S')}_#{args.name}.rb"
FileUtils.mkdir_p(MIGRATIONS_DIR)
File.open(File.join(MIGRATIONS_DIR, file_name), 'w') do |file|
file.write(migration_template)
end
end
end
Then run the rake task like this rake db:generate_migration[my_migration_name]. This command will create a Sequel migration file 20220720233750_my_migration_name.rb in the directory db/migrations.

How can I load ActiveRecord database tasks on a Ruby project outside Rails?

ActiveRecord 3.2.14
I want to use ActiveRecord in a non-Rails Ruby project. I want to have available the rake tasks that are defined by ActiveRecord. How can I do that?
rake db:create # Create the database from DATABASE_URL or config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)
rake db:drop # Drops the database using DATABASE_URL or the current Rails.env (use db:drop:all to drop all databases)
rake db:fixtures:load # Load fixtures into the current environment's database
rake db:migrate # Migrate the database (options: VERSION=x, VERBOSE=false)
rake db:migrate:status # Display status of migrations
rake db:rollback # Rolls the schema back to the previous version (specify steps w/ STEP=n)
rake db:schema:dump # Create a db/schema.rb file that can be portably used against any DB supported by AR
rake db:schema:load # Load a schema.rb file into the database
rake db:seed # Load the seed data from db/seeds.rb
rake db:setup # Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)
rake db:structure:dump # Dump the database structure to db/structure.sql
rake db:version # Retrieves the current schema version number
The above list is the list of tasks that I want to be able to use on my non-Rails Ruby project that uses ActiveRecord. What do I have to write in my Rakefile?
Thanks in advance
The easiest thing to do is to load the tasks already defined in databases.rake. Here is a GIST of how it was done.
Inspired by this GIST by Drogus
Rakefile.rb
require 'yaml'
require 'logger'
require 'active_record'
include ActiveRecord::Tasks
class Seeder
def initialize(seed_file)
#seed_file = seed_file
end
def load_seed
raise "Seed file '#{#seed_file}' does not exist" unless File.file?(#seed_file)
load #seed_file
end
end
root = File.expand_path '..', __FILE__
DatabaseTasks.env = ENV['ENV'] || 'development'
DatabaseTasks.database_configuration = YAML.load(File.read(File.join(root, 'config/database.yml')))
DatabaseTasks.db_dir = File.join root, 'db'
DatabaseTasks.fixtures_path = File.join root, 'test/fixtures'
DatabaseTasks.migrations_paths = [File.join(root, 'db/migrate')]
DatabaseTasks.seed_loader = Seeder.new File.join root, 'db/seeds.rb'
DatabaseTasks.root = root
task :environment do
ActiveRecord::Base.configurations = DatabaseTasks.database_configuration
ActiveRecord::Base.establish_connection DatabaseTasks.env.to_sym
end
load 'active_record/railties/databases.rake'
You could try the standalone-migrations gem:
https://github.com/thuss/standalone-migrations
For Rails 3.x:
You need to manually create the tasks. As example here is how to add them (this example uses the environment variables like Rails):
namespace :db do
desc "Drop and create the current database"
task :recreate => :environment do
abcs = ActiveRecord::Base.configurations
ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
ActiveRecord::Base.connection.recreate_database(ActiveRecord::Base.connection.current_database)
end
end
and you'll have the task rake db:recreate available
For Rails 4.x:
If you want to have the ActiveRecord rake tasks available in your ruby app, take a look at the documentation.
Example usage of DatabaseTasks outside Rails could look as such:
include ActiveRecord::Tasks
DatabaseTasks.database_configuration = YAML.load(File.read('my_database_config.yml'))
DatabaseTasks.db_dir = 'db'
# other settings...
DatabaseTasks.create_current('production')
Also you have here an example on how to use ActiveRecord in your ruby aplication.
Create your own!
Reference the Rails one though:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/railties/databases.rake
Create a Rake Task file. To use Rake, generally you want a tasks folder filled with Rake task files. These files have the ".task" extension.
Study the file to link given.
Take parts of that file, or even the entire contents of the file, and add it to your new Rake task file.
Make sure your Rakefile loads those task files. Your Rakefile should have something like this
-
Dir[File.join(PROJECT_ROOT, 'tasks', '**', '*.rake')].each do |file|
load file
end
I believe you can use the sinatra-activerecord gem even if you're not using Sinatra. I just solved this problem by requiring that gem and then adding
require 'sinatra/activerecord/rake'
to my rakefile.
Once I added that require line the db tasks showed up in my rake -T!
If you are using Sinatra, you can use this gem:
https://github.com/janko-m/sinatra-activerecord
However, if you don't use it either, the source code inside provides a good example on how to implement AR rake tasks.

Resources