Is there an easy way to have a rails action load up an external file of commands and then execute them?
For example, I'm trying to write a bunch of rails create methods to pre-populate a bunch of tables in a database.
Ideally, I'd like the action to check for the existence of the file, if it exists, run all of the commands, and then delete the file so it doesn't get executed again.
So, the external file would basically look like this:
MyTable.create :name => "New 1"
MyTable.create :name => "New 2"
Is this easy to accomplish in rails?
Some elaboration:
The idea would be that if a certain set up tables need to be touched up after a release, and that you can't do it through a migration script (i.e. you're initializing the database from the schema.rb file), you could:
Create a file called "update_data.rb" for example
Place it in an admin directory
Target some action in the browser (i.e. /admin/update_data)
Rails would then read in the file, executing the commands line-by-line, and then
Delete the file when finished so that the actions weren't accidentally executed again
Does that help? It would be a file for one-time actions that need to be executed after a release. If there is a better method, I'm certainly all ears!
Another option would be rake. You can create a new file in lib/tasks - we'll call yours bootstrap.rake
namespace :db do
desc 'Load an initial set of data'
task :bootstrap => :environment do
if your_file_exists
puts 'Loading data...'
this_is_where_the_magic_happens
end
end
end
Then from the console you can run rake db:bootstrap and schedule it with crontab if you like.
For step 4:
load("update_data.rb")
I believe this would load and execute your script.
Sounds like a job for script/runner.
http://www.ameravant.com/posts/recurring-tasks-in-ruby-on-rails-using-runner-and-cron-jobs
Related
I’m using Rials 4.2.5. I want to create some seed data for a new model, user_images, I just created in an existing project. However, I already have a db/seeds.rb file that has been run on my database. Where do I put the seed data for this new model? I assume i can’t use db/seeds.rb because it has already been run. It is not an option to blow away the database and start again.
Thanks, - Dave
You can use seeds.. I use, for example:
Person.find_or_create_by(name: 'Bob')
Lots of them, as required, then run as many times as I like.. I run seeds on each auto deployment for example, so I don't forget..
Link to command: http://apidock.com/rails/v4.2.1/ActiveRecord/Relation/find_or_create_by
create a custom rake task in lib/tasks. The file should end in .rake. Then you run it by the name. For example:
task :do_something => :environment do
p "do something"
end
You'd run this task by calling rake do_something in terminal.
I want my app to execute a task (download CSV files from another website & parse them) just before the server starts.
In which file exactly should I put the code for this?(maybe db/seeds.rb?)
Also, any idea on how to test this with RSpec?
The initializers folder is the proper place to set this tasks.
Just create a file with .rb extension, and everything else will be performed on start.
http://guides.rubyonrails.org/configuring.html#initializers
From the Rails Guides:
In the rare event that your application needs to run some code before Rails itself is loaded, put it above the call to require 'rails/all' in config/application.rb.
Inside initializers folder, can create any .rb file and can write any logical code in that file. It will be executed on start.
But it may slow down server start, because in your case csv download and parsing may take time to execute.
http://guides.rubyonrails.org/configuring.html#running-code-before-rails
One solution, this may be not right
in lib/tasks/say_hello_rake.rake
namespace :sample do
task :your_task_name do
puts 'Hello my task ... '
end
end
before rails s
rake sample:your_task_name
I need to create a custom task for each of the existing task I have. For example in /lib/tasks I have two files with tasks: update.rake,service.rake, etc. I have several tasks in each of these files. I have for example: rake update:users. Now I want to have rake custom_behaviour: for each of the tasks I have defined for example: rake custom_behaviour:update:users. I found the following code:
Rake::Task.tasks.each do |task|
task "custom_behaviour:#{task.name}" do
puts "Custom Behaviour Task: rake #{task.name}"
end
end
And this works properly if the file where I'm storing this code starts with "z", this is because it is the last file to be executed, but if I name the file as custom_behaviour.rake all the tasks defined in the files that are after the "c" are not "custom_behavioured" because the tasks are not loaded yet...
So my question is: What's the proper way of doing this? Where should I put the "custom_behaviour" code so when it's executed "all the tasks" are loaded?
I'd use the filename convention. This happens with other stuff that's order dependent, like Rails initializers.
The alternate that might allow you to accomplish what you need (I'm assuming you're looking have some custom behavior before/after the standard task) with is rake_hooks: https://github.com/guillermo/rake-hooks
I know I can have the following to call a list of sub-tasks and have each one utilize the Rails environment of my project:
task :main_task => [:sub_task1, :sub_task2] do
end
task :sub_task1 => :environment do
Model1.some_class_method
end
task :sub_task2 => :environment do
Model2.some_class_method
end
My questions are
Is there any way in :main_task to pass the :environment so that I don't have to explicitly put it in each sub-task?
Is there any way to make the sub-tasks be considered "private"? That is, I don't want them to be explicitly called individually. They would only ever execute from :main_task. Basically I need to read data out of one database (SQLServer) and populate another (MySQL - the Rails project's db), but I want to keep the "read" task separate from the "populate" task for good readability.
You can list the :environment task once in the parent task before the other two to have it listed only once.
task :main_task => [:environment, :sub_task1, :sub_task2] do
end
There are no "private" tasks, however you can keep them from being listed by rake -T by not putting a desc line above them. You could enforce them manually by throwing an exception if they are called directly (detecting something the parent does, or some such).
However, you would probably have a better time putting the code in a shared method or class which is not directly exposed as a rake task.
Where and how do I run a simple script that uses my rails environment. Specifically I have one column that holds multiple pieces of information, I've added columns now for each piece of information and need to run a ruby script that can run to call a method on each row of the database to extrapolate data and save it to the new column.
Using a migration sounds like the right way to go if I am understanding your use case.
However, if you really do want to write a standalone script that needs access to your Rails application's models, you can require the environment.rb file from inside your standalone script.
Example:
#!/bin/env ruby
ENV['RAILS_ENV'] = "production" # Set to your desired Rails environment name
require '/path/to/railsapp/config/environment.rb'
# After this point you have access to your models and other classes from your Rails application
model_instance = MyModel.find(7)
model_instance.some_attribute = "new value"
model_instance.save
I have to agree with David here. Use a migration for this. I'm not sure what you want to do, but running it from inside your environment is much, much more efficient then loading up the app environment manually. And since your initial post suggests you're only doing this once, a migration is the way to go:
rails g migration MigrateData
.. generates:
class MigrateData < ActiveRecord::Migration
def self.up
# Your migration code here
end
def self.down
# Rollback scenario
end
end
Of course, you will always want to perform this locally first, using some test data.
Agree with everyone, for this specific case it sounds like migration will be way to go, however, to do this regularly, or write some other task/script that interacts rails app environment make rails generate a rake task for you! This gets saved with your rails app, and can be run again and again :)
Easiest way to generate a rake task that interact with rails app/models is to make Rails generate Rake tasks for you!! :)
Here's an example
run rails g task my_namespace my_task
This will generate a file called lib/tasks/my_namespace.rake which looks like:
namespace :my_namespace do
desc "TODO: Describe your task here"
task :my_task1 => :environment do
#write any ruby code here and also work with your models
puts User.find(1).name
end
end
Run this task with rake my_namespace:my_task
Watch your ruby code task that interacts with rails modal run!
Seeding data:
http://railscasts.com/episodes/179-seed-data
Adding data with migrations
http://railscasts.com/episodes/23-counter-cache-column
Working with Rake Tasks
http://railscasts.com/episodes/66-custom-rake-tasks
I prefer to use migrations for adding some data in your case.
If it's a one-time thing, use a migration.
If this is something that needs to be done multiple times, use a rake task for it.