I was wondering how to write a rake task for backing up the default rails database. I tried the following. However, nothing seems to be getting written in the file.
namespace :mockdb do
desc "Back up the database"
task :backup => :environment do
puts "Backing up the database.."
system "sqlite3 .dump > #{dump_path}"
puts "Phew! All data has been backed up!"
end
def dump_path
Rails.root.join('db/mock.sql').to_path
end
end
Apparently the system was not able to find sqlite3. I had to give the installation path. Following is the final snippet
namespace :mockdb do
sqlite_path = "/usr/bin/sqlite3"
sql_file = "db/#{Rails.env}.sqlite3"
desc "Back up the database"
task :backup => :environment do
puts "Backing up the database.."
system "#{sqlite_path} #{sql_file} .dump > #{dump_path}"
puts "All data has been backed up!"
end
def dump_path
Rails.root.join('db/mock.sql').to_path
end
end
Related
Seeking to move all my shared models to an engine which can be included in each of my micro apps.
This engine should provide a model layer to all our legacy data, including:
Model files
Schema files
Migrations (we're following Pivotal Labs' pattern, this isn't the issue)
Model files are being patched in automatically, that's fine.
Schema files are being monkey-patched in using Nikolay Strum's db.rake:
namespace :db do
namespace :schema do
# desc 'Dump additional database schema'
task :dump => [:environment, :load_config] do
filename = "#{Rails.root}/db/foo_schema.rb"
File.open(filename, 'w:utf-8') do |file|
ActiveRecord::Base.establish_connection("foo_#{Rails.env}")
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
end
end
end
namespace :test do
# desc 'Purge and load foo_test schema'
task :load_schema do
# like db:test:purge
abcs = ActiveRecord::Base.configurations
ActiveRecord::Base.connection.recreate_database(abcs['foo_test']['database'], mysql_creation_options(abcs['foo_test']))
# like db:test:load_schema
ActiveRecord::Base.establish_connection('foo_test')
ActiveRecord::Schema.verbose = false
load("#{Rails.root}/db/foo_schema.rb")
end
end
end
We need rake db:create and rake db:schema:load to work,
The db.rake patches only affect db:schema:dump and db:test:load_schema (part of tests_prepare, I assume). I've attempted to patch them into db:schema:load using:
namespace :db do
# Helpers
def mysql_creation_options(config)
#charset = ENV['CHARSET'] || 'utf8'
#collation = ENV['COLLATION'] || 'utf8_unicode_ci'
{:charset => (config['charset'] || #charset), :collation => (config['collation'] || #collation)}
end
def load_schema(schema_name)
abcs = ActiveRecord::Base.configurations
ActiveRecord::Base.connection.recreate_database(abcs[schema_name+'_test']['database'], mysql_creation_options(abcs[schema_name+'_test']))
# like db:test:load_schema
ActiveRecord::Base.establish_connection(schema_name+'_test')
ActiveRecord::Schema.verbose = false
load("#{Rails.root}/db/#{schema_name}_schema.rb")
end
namespace :schema do
# desc 'Dump additional database schema'
task :dump => [:environment, :load_config] do
dump_schema = -> (schema_name) {
filename = "#{Rails.root}/db/#{schema_name}_schema.rb"
File.open(filename, 'w:utf-8') do |file|
ActiveRecord::Base.establish_connection("#{schema_name}_#{Rails.env}")
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
end
}
dump_schema.call('kiddom')
dump_schema.call('kiddom_warehouse')
end
# When loading from schema, load these files, too
task :load => [:environment, :load_config] do
load_schema('kiddom')
load_schema('kiddom_warehouse')
end
end
namespace :test do
# desc 'Purge and load foo_test schema'
task :load_schema do
load_schema('kiddom')
load_schema('kiddom_warehouse')
end
end
end
But this gives me the error NoMethodError: undefined method 'recreate_database' for #<ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x007feb6bb43558>. Apparently, this only works on Oracle-type databases?
What are the Rails commands for the underlying DROP and CREATE DATABASE sql I'm trying to affect for the extra schema.rb's?
You are using SQLite as your database engine. Hope that is what you want to do.
Since you are creating SQLite Database , things differ a bit from other database adapters like MySQLAdpter or Postgress.
In case of MySQL, database has to be created prior to establish a connection by spending "CREATE DATABASE ... " SQL commands. So you must create the database before establishing connection.
But in case of SQLite, since the database reside in a file and one file can contain only one database, there is no separate step to create database. An attempt to establishing a connection to the database itself will cause the database file to be created.
Hence create_database method won't work when using SQLiteAdapter. You can simply remove that line from your code.
You may have a look at the source code for the Rake task db:create
https://github.com/rails/rails/blob/f47b4236e089b07cb683ee9b7ff8b06111a0ec10/activerecord/lib/active_record/railties/databases.rake
Also, the source code for 'create' method in SQLiteDatabaseTasks. As you can see, it simply calls the establish_connection method
https://github.com/rails/rails/blob/f47b4236e089b07cb683ee9b7ff8b06111a0ec10/activerecord/lib/active_record/railties/databases.rake
I am writing a Ruby on Rails application which has a Rake task that can parse a CSV file.
Here is the code:
desc "Import Channels into DB\n Usage: rake channel_import"
task :import_channels, :path_to_channel_list do |t, args|
require "#{Rails.root}/app/models/channel"
require "csv"
filePath = args.path_to_channel_list
puts "Filepath received = #{filePath}"
csv = CSV.read("#{filePath}", :encoding => 'windows-1251:utf-8')
csv.each_with_index do |row, i|
if [0].include?(i)
puts "Skipping over row #{i}"
next
end
if(row.nil?)
puts "row[#{i}] was nil"
else
channelName = nil
classif = nil
owner = nil
channelName = row[0].force_encoding('UTF-8')
classif = row[1].force_encoding('UTF-8')
owner = row[2].force_encoding('UTF-8')
if (channelName.nil?)
puts "Channel name for row #{i} was nil"
#add entry to Log file or errors database
next #skip this row of the csv file and go to next row
else
channel_hash = Hash.new("name" =>"#{channelName}", "classification" => "#{classif}", "owner" => "#{owner}" )
end
puts "\nChannel Name = #{channelName}\nClassification = #{classif}\n Ownership = #{owner}"
#If channel name exists in the Database, update it
xisting_channel = nil
xisting_channel = Channel.find_by channel_name: '#{channelName}'
if(xisting_channel.nil?)
#create a new channel
#new_channel = Channel.create(channel_hash)
puts "Inserted....#{#new_channel.inspect}"
else
#update existing channel
Channel.update(xisting_channel.id, :classification => "#{classif}", :ownership => "#{owner}" )
puts "Updated...."
puts "channel_hash = #{channel_hash.inspect} "
end#end if/else
end#end if/else
end #end CSV.each
end
When I run this code I get the following error message:
MRMIOMP0903:am AM$ rake import_channels[/XXXXXXXX/Channellist.csv]
Filepath received = /XXXXXXX/Channellist.csv
Skipping over row 0
Channel Name = APTN HD+
Classification = Specialty
Ownership = Aboriginal Peoples Television Network
rake aborted!
ActiveRecord::ConnectionNotEstablished
I tried to create a Channel object using IRB and it worked just fine. The DB is created and I'm seeing it using MySQL WorkBench. All tables are there, however, I am unable to create the Channel object from the Rake task.
My hypothesis is, perhaps outside of a certain folder/hierarchy the app cannot access the ActiveRecord::Base class or something like this.
Any suggestions on how to make this work?
UPDATE:
BAsed on the answer by Phillip Hallstrom
I changed the top line to load the environment
task :import_channels => :environment do|t, args|
Then tried rake import_channels and got this error:
rake aborted!
undefined method `safe_constantize' for #<Hash:0x007fbeacd89920>
You need to load the environment prior to running your Rake task. I'm not familiar with your multiple task name options there, but for a simple example, you'd want this:
task : import_channels => :environment do
I have a Rake script similar to below,but I am wondering if there is a more efficient way to do this, without having to drop the database, run all the migrations, reseed the database and then add the sample data?
namespace :db do
desc 'Fill database with sample data'
task populate: :environment do
purge_database
create_researchers
create_organisations
add_survey_groups_to_organisations
add_members_to_survey_groups
create_survey_responses_for_members
end
end
def purge_database
puts 'about to drop and recreate database'
system('rake db:drop')
puts 'database dropped'
system('rake db:create')
system('rake db:migrate')
system('rake db:seed')
puts 'Database recreated...'
end
def create_researchers
10.times do
researcher = User.new
researcher.email = Faker::Internet.email
researcher.save!
end
end
You should not fill your database with sample data via db:seed. That's not the purpose of the seeds file.
db:seed is for initial data that your app needs in order to function. It's not for testing and/or development purposes.
What I do is to have one task that populates sample data and another task that drops the database, creates it, migrates, seeds and populates. The cool thing is that it's composed of other tasks, so you don't have to duplicate code anywhere:
# lib/tasks/sample_data.rake
namespace :db do
desc 'Drop, create, migrate, seed and populate sample data'
task prepare: [:drop, :create, "schema:load", :seed, :populate_sample_data] do
puts 'Ready to go!'
end
desc 'Populates the database with sample data'
task populate_sample_data: :environment do
10.times { User.create!(email: Faker::Internet.email) }
end
end
I would suggest making rake db:seed self sufficient. By which I mean, you should be able to run it multiple times without it doing any damage, while ensuring that whatever sample data you need loaded gets loaded.
So, for your researches, the db:seed task should do something like this:
User.destroy_all
10.times do
researcher = User.new
researcher.email = Faker::Internet.email
researcher.save!
end
You can run this over and over and over and are ensured you will always end up with 10 random users.
I see this is for development. In that case, I wouldn't put it in db:seed as that might get run in production. But you can put it in a similar rake task that you can re-run as often as needed.
This comment says:
db:drop can run without failure when db does not exist
This is exactly what I need: I need to run db:drop but without throwing an exception or halt my whole process if the database doesn't exist, just delete the database if it exists or do nothing.
How can I do that? how can I tell db:drop not to destroy my life if the database doesn't exist?
This is the code I'm experiencing the problem with (it it help):
namespace :db do
task import: :environment do
Rake::Task["db:drop"].invoke # If the database doesn't already exist, the whole import process terminates!
Rake::Task["db:create"].invoke
Rake::Task["db:migrate"].invoke
database_config = Rails.configuration.database_configuration[Rails.env]
system "psql --username=#{database_config['username']} #{database_config['database']} < PostgreSQL.sql"
end
end
Why can't you go for simple exception handling
namespace :db do
task import: :environment do
begin
Rake::Task["db:drop"].invoke # If the database doesn't already exist, the whole import process terminates!
Rake::Task["db:create"].invoke
Rake::Task["db:migrate"].invoke
database_config = Rails.configuration.database_configuration[Rails.env]
system "psql --username=#{database_config['username']} #{database_config['database']} < PostgreSQL.sql"
rescue Exception => e
p "The Exception is #{e.message}"
end
end
end
I need to create a script that imports data from a file system source. How do I do that?
I already tried to create a rake task but there the models are not loaded. How do I get the whole rails environment into my task?
desc 'Do stuff with models'
task :do_stuff => :environment do
1000.times.each do |i|
Model.create :name => "model number #{i}"
end
end
You declare :environment as a dependency of your rake task. This loads up rails and all of your app code before it runs.