How to handle one-off deployment tasks with capistrano? - ruby-on-rails

I am currently trying to automate the deployment process of our rails app as much as possible, so that a clean build on the CI server can trigger an automated deployment on a test server.
But I have run into a bit of a snag with the following scenario:
I have added the friendly_id gem to the application. There's a migration that creates all the necessary tables. But to fill these tables, I need to call a rake task.
Now, this rake tasks only has to be called once, so adding it to the deployment script would be overkill.
Ideally, I am looking for something like migrations, but instead of the database, it should keep track of scripts that need to be called during a deployment. Does such a beast already exist?

Looks like after_party gem does exactly what you want.

I can't think of anything that does exactly what you want, but if you just need to be able to run tasks on remote servers in a one off fashion you could always use rake through capistrano.
There's an SO question for that here: How do I run a rake task from Capistrano?, which also links to this article http://ananelson.com/said/on/2007/12/30/remote-rake-tasks-with-capistrano/.
Edit: I wonder if it's possible to create a migration which doesn't do any database changes, but just invokes a rake task? Rake::Task["task:name"].invoke. Worth a try?

I would consider that running that rake task is part of the migration to using friendly_id. Sure, you've created the tables, but you're not done yet! You still have to do some data updates before you've truly migrated.
Call the rake task from your migration. It'll update the existing data and new records will be handled by your app logic in the future.

Related

Rake tasks and migration on Heroku without downtime

Context
I'm using Heroku to serve my rails API (v5.2) with a PostgreSQL database,
Frequently, after some migrations, I have to manually run some specific rake tasks.
Those rake tasks typically delete all the rows of a table before recreating them with different data.
This is problematic for me because it create a downtime for approx. 20 minutes, twice a week (by turning on and off Maintenance mode).
Problem
I would like to avoid downtime between my migrations.
Intended solution
for this, I planned on using Heroku preboot alongside release phase tasks.
After activated preboot for my app, I will put a script in my Procfile
release: ./release-tasks.sh
And in the release-tasks.sh file something like:
heroku run rake my_rake_task --app myApp
Questions
Is it a good/ok solution?
Is it sure that during the migration phase, users will be able to
query the "old" database before the new one is live?
Is there a way to activated release scripts on demand? (e.g using an
env var in Heroku? -- I won't need it for every migrations).
This is a good solution, yes. Release Phase is meant exactly to help running migrations whenever the app is deployed.
This won't prevent downtime in your specific case though. Release phase doesn't start a new database with every release. It just runs a one-off dyno with your command.
Your only solution here is to change your migration strategy to avoid deleting and recreating everything. Depending on what you're doing, you may be able to just update/add/remove the data you need.
Or you could create a new temporary table with the new data, and then delete the old table and rename the new one to its permanent name.
Both those solutions are something you need to write your own code for though.

Any gotchas running a Rails installation after repeatedly copying it?

My basic question is: if I repeatedly copy a Rails app, so there are many generations of the same repo (i.e., various iterations of a Rails app's directory and files), what do I need to do to ensure that the server runs normally and avoid major issues?
I'm writing a learning app that drills the user on programming tasks. Right now it supports only single-file tasks. I want to add support for multiple-file tasks next, involving HTML/CSS/JS and Rails tasks (e.g., "add a model that does such-and-such" or "add a Minitest test for such-and-such feature"). The user will be required to edit the Rails code directly, and my app will then automatically run the server and show the results. After each question is answered (i.e., each task is performed), my app will migrate down the database automatically as necessary and copy the repo anew from a tarball--basically, preparing the stage for the next time the user tackles the task. (Well, I hope it's a good idea.)
Since Rails apps are so big and complex, of course it's not feasible to build and add a separate Rails app for every question. Instead, I will have many questions/tasks that are based on the same repo (installation). After each question is answered (i.e., each task is performed), the database will be migrated down as necessary and the repo copied anew from a tarball. So far, so good? (I anticipate problems using Git to do this...so I would just use Minitar for this.)
But of course I will have to make other versions of the same repo (using the same database, or maybe a copy) when I make other clusters of questions. For example, I might want a bunch of questions/tasks related to using AJAX in Rails, and for that I need to prep an installation in various ways. But if I'm just building on a copy of a previous repo that has its own tasks, will the copying process cause issues for the later repo and its tasks?
I have done some testing. I have already confirmed that if I simply execute cp -r repo1/ repo2/ and then run rails s in repo2, the server for the latter starts normally. While data written in repo2 does not appear in repo1, I can't create an identically-named model (which is a little puzzling). I imagine this might be a problem for some questions--i.e., I don't really want them running from one and the same database for all repos, even if later database versions are based on earlier versions. So whenever I copy a repo, I guess I'll want to make a copy of the database as explained here. Sound right?
Is there anything else I'd need to do in building this feature that would prevent issues related to repeatedly copying different iterations of the same repo (and database)?
I think you're making it more complicated than it needs to be. This can all be done in git by leveraging git feature branches, e.g. question-1, question-2, for each derivation and combining that with the rails rake database tasks, e.g. rake db:drop, rake db:create, rake
db:migrate, rake db:seed, to ensure your database is bootstrapped properly for each branch.
An alternative approach could be to add SQL dumps of your final database state to each feature branches and load them via a rake task to bootstrap your database to your desired state.

Ruby: Inserting records to existing rails database using non-rails script

I have a rails app that only allows users to search and view the contents of its (MySQL) database. To add records to the database, I'd like to run a ruby script automatically twice a day which generates the contents of the database and then updates the db. Is this possible, or does my script have to be a part of the rails web app?
Just to lead you in the right direction - you can use a Rake task for this. These are usually put in the lib/tasks directory.
It's a good idea to separate non-web related things such as seeding or updating a database. If this is a scheduled job, you can use whenever to hook the rake task to cron.
Solved this using rails runner command

Where do I put a recurring script that updates database from api in rails

I have a Rails app set up with a model Account that should be updated every morning with data coming from an external API I'm calling (a CRM). Basically either I create new accounts in my app that I find in the CRM and some of the fields that are mapped with my columns, either I find the account if it already exists and I update it.
So far, I've been putting this code into the seeds.rb file and from Heroku, where the app is hosted, I set up a scheduler with the command : rails db:seed that runs periodically.
My issue is that I'm sure there is a better way of doing this. I've read about rake tasks but I did not quite understand how that applied to my case. Otherwise I thought of putting my method in the models/account.rb file as a self method. But I don't really know how I can invoke it in a rake command to allow me to set up a scheduler in Heroku.
Any idea on where would be the best place to put this method, and how to call it from command line?
Thanks in advance.
You can create a script directory in your project, and put your script from db/seeds.rb into this directory, maybe called update_accounts.rb. Then you can run it with
rails runner script/update_accounts.rb
and schedule that task in heroku. More info about rails runner here.
I would suggest using a background processor such as Sidekiq: https://github.com/mperham/sidekiq
Once using Sidekiq, you need a scheduler like https://github.com/moove-it/sidekiq-scheduler to make sure it happens periodically as you require.
This will become easier to maintain as your application grows and you need more workers. It also moves your scheduling into version control.

Rails 3 Rake Clone Database for Testing Environment

Is there a rake command in Rails 3 to clone my development database data? I noticed rake db:test:prepare and rake db:test:clone are mentioned throughout various blogs, but running them seems to do nothing. Furthermore, rake -T shows no db:test cases. I've resorted to loading a sql dump for now, but it would be great if I could just clone my existing development data for up-to-date testing.
EDIT --
I desire to test on a database since I am dealing with legacy data that I run through model filters when accessed. Factories won't work for me in this context, since data passed through create is defined as a different schema than that of the legacy data.
rake db:test:prepare is still there even though it doesn't show up in rake -Tdb. I guess the Rails team decided to de-clutter the rake -T output?
I would suggest you not clone your development database but rather rely on factories to give you predictable data you can craft for your exact test cases. Sooner or later, relying on having reliable test data in a database you can access will break your tests. It will also break the tests of anyone else who works on the project. And changes/additions to the data will not propagate to other developers as would your carefully constructed factories.
Look over Machinist, FixJour, FactoryGirl and the lot. They really solve the test data problem well and you check them into version control so the rest of your team has access to them.

Resources