How to create a script in rails and run it using console - ruby-on-rails

I am trying to modify my database in rails for that I want to write a script that would modify my model accordingly when executed. I have no idea how to create a script and run it using rails console. Please somebody guide me.
Eg -: Suppose i want to write a script that has Model.all written in it and when I execute it using console Model.all should run

Use Rails tasks instead:
lib/tasks/mytasks.rake
namespace :mytasks do
desc "This is a Hello world task. All it does it say hello"
task :hello => :environment do
puts "Hello!"
end
end
Then in the console you do:
rake mytasks:hello

One the quick temporary solution adds a new class method to your Model:
class Model
def self.modify_db
Model.find_each do |item|
end
end
end
In console just type: Model.modify_db

Related

How temporarily disable "needs_migration?" check when testing migration?

I've written the spec to test my migration but when I run it I got an error:
ActiveRecord::PendingMigrationError:
Migrations are pending. To resolve this issue, run:
bin/rake db:migrate RAILS_ENV=test
I've tried to disable the migration check in the before section but that check is running before all tests.
How to disable the migration check for testing purposes?
Testing Rails migration is a bit of a pain so I would rather step back and think about if this needs to be in a Rails migration / tested in a Rails migration.
There are basically two different types of migrations
Schema migrations
Use mostly Rails built in functions. Unless you do some handcrafted SQL I wouldn't bother testing this and trust the framework here.
Data migrations
Data migrations are used to backfill or change data. As data is one of your most valuable assets and loosing or corrupting it is very painful I would definitely recommend to write tests for data migrations.
As mentioned, testing migrations is a bit of a pain so I would try to abstract the data migration code in it's own (service) class. Something like
class DataMigration::UpdateUsername
def self.run
new.run
end
def run
User.all do |batch|
user.update(name: user.name.capitalize)
end
end
end
You can now test the data migration like a normal class like this:
it 'does capitalize the name' do
user = create(:user, name: 'name')
DataMigration::UpdateUsername.run
expect(user.reload.name).to eq('NAME')
end
Now we can use this class in our Rails migration or e.g. just use it in a Rake task. Using it in a Rake task also has the advantages that we can pass in parameters, run several data migrations in parallel (e.g. you have a large data set) or even in a background job which you can't in a Rails migration.
Example
class DataMigration::UpdateUsername
def initialize(start_id:, finish_id:)
#start_id = start_id
#finish_id = finish_id
end
def run
User.find_in_batches(start: start_id, finish: finish_id) do |batch|
batch.each do |user|
user.update(name: user.name.capitalize)
end
end
end
end
Now we can create a custom task for this
namespace :db do
desc "Runs user data migration"
task :update_user, [:start, :finish] do |task, args|
DataMigration::UpdateUsername.new(start_id: args[:start], finish_id: args[:finish])
end
end
rake db:update_user[0, 10000]
rake db:update_user[10000, 20000]
# ...
In config/environments/test.rb add the line
config.active_record.migration_error = false

Uninitialized constant error when trying to refer to a database record within a service

I'm trying to create a rake task that uses a service. Within that service, I want to load the last saved record of a MonthlyMetrics table within my database.
Within my rake file:
require 'metrics_service'
namespace :metrics do
#metrics_service = MetricsService.new
task :calculate_metrics => [:check_for_new_month, :update_customers, :update_churn, :do_more_stuff] do
puts "Donezo!"
end
# ...more cool tasks
end
And my MetricsService within lib/metrics_service.rb:
class MetricsService
def initialize
#metrics = MonthlyMetric.last
#total_customer_count = total_customers.count
assign_product_values
end
# Methods to do all my cool things...
end
Whenever I try to run something like rake:db:migrate, I get the following error:
NameError: uninitialized constant MetricsService::MonthlyMetric
I'm not sure why it's trying to refer to MonthlyMetric the way it is... As a class within the MetricsService namespace..? It's not like I'm trying to define MonthlyMetric as a nested class within MetricsService... I'm just trying to refer to it as an ActiveRecord query.
I've done other ActiveRecord queries, for example User, in other services within the same directory.
What am I doing wrong here?
I think if you just add => :environment to the end of your rake task, that may fix the problem.
As in:
task :calculate_metrics => [:check_for_new_month, :update_customers, :update_churn, :do_more_stuff] => :environment do
I've run into similar problems where Rails does not initialize the correct environment without this tacked on to each rake task.

Method calls in one rake file task being handled by methods of same name in another rake file

Using Rails 2.3.*
Say I have a method called some_method() in two rake files - A.rake and B.rake.
I'm finding that if I call some_method() in B.rake, the method in A.rake is what actually gets called.
So what's the best approach to defining helpers methods inside rake files that will be "local" to the rake task defined in that file?
Thanks
You can define your helper within a task to make it available to that task and all subsequent ones:
desc 'has access to local helper'
task :accessible do
def helper
return "the helper"
end
puts "I have access to #{helper}"
end
desc 'has access too'
task 'after-accessible' => ['accessible'] do
puts "this ran after 'accessible' but still has access to '#{helper}"
end
desc 'does not have access to the helper'
task :outside do
puts helper # fails if runs before :accessible
end
Perhaps the best thing to do though is to refactor your Rakefiles and the helper code so that the two Rakefiles do not load each other.

Options with Rails for triggering an email to all (or some) users?

Newb question: We've got a live site with registered users. Some new functionality has been added (including support for Mailers). We would like to trigger an email to all existing users (similar but not identical to one that will now automatically go out to new users).
What options do we have for triggering the sending of that email? This message will likely only be sent once so we don't need the code (other than the message itself) in the Rails app. Nor do we really need to store who received it because it will be assumed that all users have received such a message once we can get this one out.
I'm thinking Rake task but all the examples I seem to be able to find are for build script?!? Or should we just use the Rails console in production? Perhaps get an array of all users we want to send email to and then deliver message to them?
Not sure. I haven't worked with ActionMailer much.
I'd probably do it like this:
In order to determine if the system has sent an email to a user, you should add an attribute let's say 'sent_email' which is basically just a boolean.
I'd create a cron job for a rake task that checks all users with sent_email=0. Then, I'll loop through each array and send the email and set sent_email=1. The cron job can be run daily, depending on your preference. You can use whenever gem to setup the cron job.
schedule.rb (whenever stuff)
job_type :run_script, "RAILS_ENV=:environment ruby :path/script/:task"
every 1.day do
run_script('send_email.rb')
end
script/send_email.rb
#!/usr/bin/env ruby
puts "Loading rails environment..."
require(File.dirname(__FILE__) + "/../config/environment") unless defined?(Rails)
class SendEmail
def send_email
users = User.send_email_to
users.each do |user|
OneTimeMailer.deliver_one_time_email(user)
end
end
end
mailers/one_time_mailer.rb
class OneTimeMailer < ActionMailer::Base
def one_time_email(user)
recipients user.email
from 'your system'
subject 'hello world'
body 'this is a one time email. thank you'
end
end
I hope this helps.
I suggest doing a rake task, run it once and you are done.
rails g task my_namespace my_task1 my_task2
Now you loop through your database:
namespace :sent_email_to_everyone do
desc "TODO"
task send_that_mail: :environment do
user = User.all
user.each do |user|
Yourmailer.send_email(user.email)
end
end
end
end
Now you just run it and done
rake sent_that_mail

Getting started with the Friendly ORM

I'm following this tutorial: http://friendlyorm.com/
I'm using InstantRails to run MySQL locally. To run Ruby and Rails, I'm using normal Windows installations.
When I run Friendly.create_tables! I only get an empty Array returned: => [] and no tables are created in my 'friendly_development' database.
Author of Friendly here.
You'll have to require all of your models before calling Friendly.create_tables! Otherwise, there's no way for Friendly to know which models exist. In a future revision, I'll automatically preload all your models.
I have a rake task, with help from a guy called Sutto, that will load in all your models and then call Friendly.create_tables! and print out all the tables involved.
namespace :friends do
desc "load in all the models and create the tables"
task :create => :environment do
puts "-----------------------------------------------"
Dir[Rails.root.join("app", "models", "*.rb")].each { |f|File.basename(f, ".rb").classify.constantize }
tables = Friendly.create_tables!
tables.each do |table|
puts "Table '#{table}'"
end
puts "-----------------------------------------------"
end
end
rake friends:create
not much to go on here. My guess is that it can't find your model file that you are creating in the path?

Resources