Locking database while executing rake script - ruby-on-rails

I have created a rake script to send e-mails to some users.
The rake script first needs to delete some old database records, and then proceed with the e-mails.
The trouble is that during the time that the script is running, some users may view/delete the data themselves. If the data is deleted by the script, then the views should be refreshed, in order to accommodate the new data.
The first obvious solution that I can think of is to never display the old data in the views , and so avoid the possibility that a record is deleted after it has already been deleted.
But I still think that I have a race condition possibility here, and I would like to know how could I lock the database while executing the script.
I am using Mysql as my database system.

I would approach this by setting up a rake task that calls a method on a model to delete the database records. I would then wrap the code to delete the old mails in a transaction. That will lock the database while deleting the emails and allow you to handle any exceptions thrown when anyone else tries to delete the data.

Related

Preventing Rails from connecting to database during initialization

I am quite new at Ruby/Rails. I am building a service that make an API available to users and ends up with some files created in the local filesystem, without any need to connect to any database. Then, once every few hours, I want to run a piece of ruby code that takes these local files, uploads them to Amazon S3 and registers their location into a Postgres database.
Right now both codes live together in the same project. I am observing that every time a user does something the system connects to the database. I have seen this answer which recommends to eliminate all traces of ActiveRecord in my code, but given that I want to have my background bookkeeping process connect to the database I am stuck on what to do.
Is it possible to define two different profiles (one with database and one without) and specify which profile a certain function call should run on? would this work?
I'm a bit confused by this, the db does not magically connect to the database for kicks on every request, it does so because of a specific request requires it. Generally through ActiveRecord but not exclusively
If your system is connecting every time you make a request, then that implies you have some sort of user metric or authorisation based code in there. Just killing off the database will cause this to fail, and likely you'll have to find it anyways, to then get your system to work. I'd advise locating it.
Things to look for are before_filters in controllers, or database session management, for example, or look for what is in the logs - the query should appear - and that will tell you what is being loaded, modified or whatnot.
It might even work to stop your database, just before doing a user activity, and see where the error leads you. Rinse and repeat until the user activity works, without the database.

Rails - seed data dynamically from with the result of API calls

I'm fairly new to Ruby on Rails and I'm having some trouble designing the db.
So right now I have a table with about 100 records, populated from seeds.rb. Now I want to use this data to make an API call per record to get more information and I want to update the row with this new info I got from the API call. Is this possible in any way?
For example if I have this in seeds.rb,
Example.create(fruit: 'orange')
and I want to call this API which gives me the colour of this fruit,
color = api.param(fruit)
and I want to update the record,
fruit:'orange', color:'orange'
like so.
Can this be done as part of the seeding procedure? My vision is to run this migration every month or so to prevent outdated data.
Thanks in advance for the help!
You seem to be confused with your terminology.
A migration is a change to the database schema, not the data itself.
Database seeding is the initial seeding of a database with data and should only be done once in the beginning of development (or when an application in development is transferred to another developer).
What you need is not a migration, but a scheduled job that runs a rake task that calls your external API and updates your local database.
Create a rake task (this is an old but still relevant tutorial) that calls your external API, gets the data, and updates the database. Then schedule this task to run at the interval you require, you can use the whenever gem to do it.

Store Result From DB Query Rails

I've got a legacy database that has a temperamental (at best) connection. The data on this database gets updated maybe once a week. The users of my app just need read access.
The problem I encounter is, occasionally, queries to the DB return nil, so all sorts of bad things happen in my app.
Is there a way I can query the database until I get a valid response, then store that response somewhere in my rails app? That way, the stored version will be returned to my users. Then, maybe once a week, I can re-query the database until it returns a valid object?
To add complications to this, the legacy db is sql server, so I've had to install and use rails-sqlserver, which works pretty well, but might be adding to the problem somehow.
The problem you'd encounter doing this in the request cycle is that the request that actually fetched the data would probably run glacially slowly (since it would need to request until the result isn't nil, which could potentially take awhile), so your users would hammer the refresh button and just queue more requests until your SQL server or application is inundated.
If I were to do this, I would probably have a Resque task set up to fetch all the data you require (possibly a full dump of the database) every week or every day. Dump the resulting data to a datastore: either your local database, or something like redis or memcached if you don't particularly care about persistence. Because it's asynchronous, you can take as many times as you need to get the data fetch right. On your app side, don't even try to connect to the temperamental database; consider the "middle" database authoritative for all requests. So if the data isn't present there, assume it didn't exist on the SQL server either.
The downside to this method, of course, is that if the SQL server has a very large database, you can't just copy all of it to a more stable middle location. You'd have to choose either a subset of the data or rely on a per-request caching method, as you suggested yourself... but I don't think that's the best way to do this if you can avoid it.

Rails Testing Question

I am trying to test a functionality, which inserts few details into the DB. In the test.log, it shows the insert command that is generated and also the log messages that I have placed to show the progress and everything seems to be working fine except the actual data is not getting inserted into the DB. I am checking whether data is inserted in db/test.sqlite3. No exception is generated when the test cases are run. Is there a setting, which I have to set inorder to insert data into the test DB? or am i missing anything else
Thanks
Are you checking the database after the test is run?
By default Rails runs all tests usings transactions. This means after each test is run, the database is rolled back.
This is preferred for testing. Otherwise you may have one test tainting the data or state which affects another test.
Test data is usually cleaned up. Once the test cases are run. So I don't think there is anything in a test database. After each test transaction is run, the database is rolled back.

The ruby on rails can't manually delete records?

I have a database the have orders, and which order many order items, that kinds of thing. I deleted one product carelessly, and it is related to the order items, so it can't load successfully. So, I use the SQLite Database Browser to delete the orders and order items. But after I restart the server, it prompt me that :
We're sorry, but something went wrong.
We've been notified about this issue
and we'll take a look at it shortly.
Notice that I am using the development mode.
Did you save the database and close the SQLite browser? Your database may be locked.
You may also have forgotten to delete certain orders, so it's looking for a product that doesn't exist.
In the future, make sure you're in development mode, since that tends to offer more descriptive error messages.
This is a standard Rails error message.
You should look the development log to figure out what exactly is happening.
You can manually modify your record as soon as your changes don't break data integrity.
It's recommended you use ActiveRecord :dependent association option to specify what ActiveRecord should to when a record of that specific class is destroyed.
Also note that record.delete is different than record.destroy. The first one doesn't execute associated callbacks.

Resources