Using tagged logging in rake tasks - ruby-on-rails

Tagged logging in Rails is a neat way to make logs more readable and useful. Unfortunately, the way tagged logging was designed to work in Rails was via Rack middleware: tags are evaluated once per request. This means that tagged logging is not available, for example, to rake tasks.
I am looking for a way to add tagged logging to rake. ActiveSupport::TaggedLogging works with a block so that would typically mean having to wrap the entire of rake application execution for best results. Are there any good docs on the rake lifecycle or any example of these types of hooks you can think of? There is always reading the code...

Related

Is it possible to re-record VCR cassettes without running the test suite?

I have a ~ 2.5GB collection of VCR cassettes https://github.com/vcr/vcr. I am using version 3.0.1.
I need to re-record the cassettes from time to time. But, since running the tests takes considerably longer than just firing the requests and recording the answer in a cassette, I am searching for a way to only fire the requests that are already recorded and get them re-recorded.
Ideally I would have a rake task that would do this, e.g.:
rake vcr:cassettes:refresh
How should I go about this?
What I'm about to suggest won't work for every possible setup (for instance, those wrapping each connection in VCR.use_cassette, or those using VCR middleware with Faraday). But if you happened to set up VCR using configure_rspec_metadata!, like so:
https://www.relishapp.com/vcr/vcr/v/3-0-1/docs/test-frameworks/usage-with-rspec-metadata
...in other words, if every example or example group requiring VCR has :vcr or vcr: true as metadata, then you can run just the VCR-tagged specs on the command line using, for example:
$ rspec ./spec --tag #vcr
The --tag option is documented here.
If you're not using the metadata setup, and there's nothing preventing you from using it, switching to it will likely be faster than coming up with some other way to filter the specs, assuming they're thoroughly mixed in there. It's also makes it more convenient to add new VCR specs. One possible downside is that the cassette names might need to change, but since you're planning to re-record them, that shouldn't matter much.

Calling Models from Config Files

I am writing a ruby scheduler - namely rufus-scheduler and there are commands i need to write in the initializers section inside the config folder to perform a task every 1 minute or so. I am trying to access a method from a module within this. So my code would look like
scheduler.every("1m") do
puts("HELLO #{Time.now}")
ModelName.methodname("WHAT ARE YOU DOING")
end
This somehow doesn't perform the necessary operation in the model. Also im not sure if this is the right way to do things - such as call a model inside a config file. Is there a better place to put this code in the Model? Or is calling a Model within config files perfectly good practice. I looked over the internet to see the usage of different types of files in ruby but couldn't find a proper material. Any help or guidance appreciated.
If you want to access models from stand-alone tasks the best way is to use the rails runner wrapper. For example, you'd call your script as:
rails runner call_model.rb
This loads in the Rails environment and then executes your script, eliminating the need to do that yourself. Models on their own will not work since they are lacking the context of Rails.
If that's not sufficient, you may need to load the Rails environment more directly by including config/environment.rb into your rufus-scheduler configuration.
It sounds like you actually want a real scheduled action of some sort. config files are for configuration, not for actual working code of that sort.
There are tons of ways to run scheduled tasks in rails.
google "rails daemons" or "rails scheduled tasks" to start you off.
Here's a good list of scheduled-task best practices using cron:
A cron job for rails: best practices?

Rails - Is it okay (or possible) to run rake inside a controller?

I am using the sitemap_generator gem to build an xml sitemap. From the readme:
... run rake sitemap:refresh as needed to create/rebuild your Sitemap files
I'd prefer to do this any time the create action is ran in my Content controller. Is there a best practice for doing something like this?
It is possible, yes. But I would not recommend it. Rake tasks tend to take at least a few seconds to run which will occupy a server request and prolong the response to the client.
If you want to refresh the sitemap after every create, then I would recommend one of two solutions. Either analyse what the rake task sitemap:refresh does and use the code directly from your controller. But I would only do that as long as it doesn't take too much time to run and since I do not know much about sitemap_generator, I can't tell.
The other option would be to run the rake task from a delayed_job which I found to be the preferred alternative. That way, you can trigger the job from your create action but you don't have to wait for it to finish.

Rake task for scraping with rails

I'm starting to write scrapers to get data from different websites. I built the first scraper in a rake file and am now starting to write a second rake file to get data from a second site. For now, I am writing a scraper specific to each site I'm interested in (not trying to build a generic scraper).
I have 3 questions:
Is writing rake tasks a good choice for me? Are there alternatives I should consider?
How can I add functions/methods to my rake files? (sorry, very silly questions, but I can't figure out how to structure my code... so for now it's just 500 lines of uninterrupted code in a long method) for instance, I'd like a "get_description(section)" method that returns the description from the page. The method could be different depending on which site I'm scraping.
How can I test my task with RSpec? I'd like to give a link and make sure the output of my tasks matches what I expect to get
Thanks for your help!
As a general principle, rake tasks should be very minimal. Refer the actual behavior to real classes. These classes can then be easily tested.
Example:
task :scrape do
Scraper.scrape!
end
class Scraper
def self.scrape!
# do something
end
end
describe Scraper do
# your tests
end
You could, as #brad indicated, use thor, which has a regular class structure by itself, so in theory it should be easier to test the tasks themselves. I haven't done that though.
You can define methods in rake, but I don't know where they end up. You shouldn't do that, so don't bother. Keep task bodies minimal, write normal code to do the dirty work.
Sure rake is fine if you want to use it, you can also check out thor which uses more standard ruby-like syntax rather than the dsl rake provides you.
Rake is just another ruby library so you can include whatever you like in there. As such you can write your own library and load it in your rake file. Check out how Bundler does it for instance. They've just defined their own classes, then created tasks inside of it. It uses thor by the way, which, from what I can gather somehow proxies those tasks on to rake, haven't really looked through it thoroughly though so i could be wrong.
If you're defining things in your own library, just use rspec as you normally would for any other project, then hook that library into rake or thor with whatever means and you're off to the races

My rails tasks call model methods. How do I handle logging?

In order to keep things DRY and share functionality between my Rails tasks and my "app", I put a lot of functionality in models. In my models I have "logger.info ..." but this is problematic when I call the model functions from rake tasks because nothing is logged. Is it possible to redirect logger for only rake tasks but have it log normally when the functionality is invoked by my "app" (web requests)?
Another related issue is I don't see ActiveMailer stuff logged when I send emails from rake tasks.
You don't see logging, because a rake task is normally very short-lived. Logger, by default, only writes log to disk every 1000 characters. So your logs are less than 1000 characters and your rake task ends, nothing is written to disk.
The solution is to call
logger.flush
to force a write to disk before your rake task ends, preferably at the end of a model action.

Resources