How to stop VCR from overwriting erb in the cassettes - ruby-on-rails

We've recently started using VCR to stub requests in our cucumber tests. We're using cucumber tables to describe different kinds of requests, and storing them as variables with gherkin. Our cassette files have all been reworked to include erb, so that we can substitute in the values for the request we want to test.
The problem is that whenever there is a new request, VCR records the new requests and also overwrites (removes) all the erb from the cassette, replacing it with the request as interpolated for that example. Every time we run requests where a value has changed (say, the value of the timestamp we receive from the API we're talking to), all the erb needs to be copied back in to the cassette file. This is frustrating, since tests are run all the time.
Does anyone know why VCR strips the erb out when recording new responses? Any idea of a workaround? Is there any way to save back a template before it's interpolated?

Automatically merging your manual changes to the cassette with a newly recorded cassette is a difficult problem that, in my opinion, is best left to tools that are specifically designed to handle the history of text documents and manage merging them (i.e. your source control system). ERB makes it even more difficult: while you may just be using ERB to interpolate variables, any valid ruby can be used. There may be loops, conditionals and more in the ERB. There's no way for VCR to automatically merge this stuff.
A couple suggestions:
Use your cassettes in a more granular fashion so that they do not get overridden frequently. I tend to use a casette for each HTTP request or logical group of HTTP requests.
Use the :once record mode (the recent default) to prevent existing cassettes from being overriden.
Take a look at the sensitive data filtering feature of VCR. This is far less flexible than ERB (i.e. you can't use loops, conditionals, or any arbitrary ruby code), but for simple variable intepolation, it works really, really well. Rather than using ERB, it uses a placeholder string--you might use a string like <PASSWORD> to take the place of a password, for example. VCR automatically takes care of inserting the placeholder text when it records the cassette, and replacing it with the correct real value on playback.
If that doesn't meet your needs, the before_record and before_playback hooks should give you all the power you need to do automatic interpolation (or even ERB snippet insertion) when a cassette is recorded. It's basically how the filtering works--see here.
I'm certainly open to ideas for how to improve VCR if these things don't meet your needs.

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.

Restrictions on user-submitted code

I have a Ruby on Rails application, and one of its functions is to present JSON data to the user in table form. Before this step, I intend to add a way for users to tweak the JSON data by means of uploading their own Ruby code files that handle this.
This has its dangers. I definitely don't want any form of access (reading or writing) to the databases, nor do I want it to be able to call anything in another file. How can I limit the file in this way?
Essentially all I need is for the main code to call the function in the user-submitted file with the JSON as the parameter, and returning JSON back. All logic during this manipulation of the JSON must happen in and only in the user file.
I've looked around for ways to do this with no luck. I've seen this question:
Restricting access to user submitted code in Rails
The issue here is that I'd prefer an approach that doesn't require a gem. Also sandboxing seems rather complicated for the approach I want, which is a blanket restriction, and not specific things.
I intend to raise the $SAFE level to 4 before calling the user-supplied code/method. That doesn't seem to prevent calling other methods in the application though.

print and debugging functions in rails?

In php one can print_r() anywhere in the view, controller, or model. Is there anything like that in rails? I tried to_yaml and inspect. They don't seem to print things out from the model. Is it only allowed to be used in view? If not any example in model or controller?
This doesn't really exist because it's the lest effective way of debugging.
Being able to dump output to the browser depends on where you are. It's trivially easy in views, slightly cumbersome in controllers, and too difficult to be worth-while from models.
Fortunately, there are much better tools than simply dumping things into the browser.
You can use pry to stop mid-request, open a REPL environment and interactively query or modify the state of your running application.
If you simply want to trace the flow of execution through output, use the logger:
Rails.logger.info(my_object.inspect)
Normally you'll identify problems in your model, controller or integration tests long before it becomes an issue. In that context you can use puts to output whatever you want when instrumenting bits of code and it will show up in your test output:
puts object.inspect
Within the Rails operational environment you can use Rails.logger:
Rails.logger.debug(object.inspect)
This will show up in log/development.org where you can see what's going on. It's best to leave this at debug level so it doesn't clutter up your production logs if left in by accident.
Short answer is, you can't. At least not in one line. And not only because this is a violation of MVC, there are also practical reasons that prevent this.
There is no reliable way to output a bunch of data in an arbitrary format and keep it valid. Outputting it in JSON views may easily result in invalid data. So if your debug data can only be handled by a browser, that output should only be specified in views for browsers. Even if none other exist, separate concerns.
There is a substitute, of course. Rails 4.2.0 ships an app template with web_console. All you need to start using it is add a call to console in your views somewhere, like the app's general layout file. If that's actually ERB, add this line below:
<%= console %>
And wherever it appears, you have a REPL in the context of the currently rendered view, where you can easily inspect objects and even perform actions that change your data.
There is also a variety of methods to output data into the server's console or log file. They've been listed in other answers. I'll add a little to the solution involving logger.
Rails Panel. It's a Chrome extension that adds another tab to Chrome Dev Tools (that show up behind F12) named "Rails". For it to work, you need to add a meta_request gem to your app (make sure it's in group development!). Once working, it will show loads of data about how the page was processed:
Time spent fetching data, rendering it
Parameters for the given request
Executed DB queries, duration and lines they've been triggered by
View files involved
Log entries emitted on this request and what triggered that
Errors encountered
This one and some other debugging things are discussed in this Railscast.

How to test Recurly in Ruby, possibly using VCR

I have a rails application that uses Recurly for its transactions. I am trying to write automated tests for some of the helper functions that I have written.
A super simple example of a function...
def status_for_display
transaction.status.capitalize
end
In order to test these functions, I need to have a Recurly::Account object as well as associated Recurly::Transaction objects.
I have tried going the route of using Recurly::Account.create & Recurly::Transaction.create but I cannot seem to get the transactions to match up with the account.
I am also wondering if it doesn't just make better sense to use the VCR gem to make this happen. In which case, how would I go about doing that? I've never really managed to get VCR setup properly.
VCR is, by in large, plug and play. Once you have it configured and enabled, it'll intercept all HTTP requests and try to play back the data from a cassette. The problem with VCR, though, is that it is request data specific. In order for it to work right, you need to ensure that your tests are always sending the exact same request params to Recurly. You can work around this by having it skip certain things, but it's generally a pain.
The other option is to just use something like Webmock directly and house your own "known responses" for your Recurly calls, but then it's up to you to ensure that you responses stay in sync with the API.
In the end, I'd probably recommend going the VCR route but structuring your tests such that you have known good and bad test scenarios so you can get the real benefits of the cassettes.

Some questions on Unobtrusive JavaScript

I am using Ruby on Rails and I heard of “Unobtrusive JavaScript” (UJS). After (but even before) my previous question, I ask myself:
Are there common-used patterns, rules, practices or techniques in order to respond pragmatically to JavaScript and HTML AJAX requests? If there are, what are those? For example, what responses should be returned? What kind of data? Is there a standard?
Practically speaking, how should my controller respond_to (à la Rails) depend on the request format? That is, how should my application respond with format.js, format.html or format.whatever in controllers when using the Rails framework?
About the previous matters, what is the solution of the Rails community and / or of the “general” public? What do you use?
Ajax
I don't know any patterns, but we take a "per feature" stance -
You'll have different use cases for different features. In the most part, you can handle these using the remote: true option (which just uses the ajax handler in UJS), which will allow you to either capture the response with .on("ajax:success" in your asset JS, or by using a .js.erb file in the backend
The bottom line is we do what will produce the least amount of code. We always look at it from the perspective of future development - in the future, will you get confused with what we're doing, or will it be the logical way?
I suppose we could probably find a more structured way of handling this, but with the varying amounts of data coming back, we prefer to handle each feature in its own way
--
Code
I would personally put code efficiency & focus functionality first
Instead of trying to make a pattern to fit all cases, I'd look at what you're trying to achieve, and creating code to get it to work. If you can refactor after that, great! Otherwise, I'd invest my energy into getting functionality working

Resources