Hello world! It’s time for my first post in over 4 years.
I recently set up a new Rails 7 project with Rspec and looked online for tips, as one does. I’ve set up many Rails projects before, but not yet with Rails 7, and it’s been a while. The top result in Google for “rails 7 with rspec” is currently Adrian Valenzuela’s Setup RSpec on a fresh Rails 7 project. His post was really helpful for me shaking off the rust. So rather than writing another post that’s 80% the same, I’ll just share a few additional tips. Think of this post as a companion piece to Valenzuela’s.
rails.new
Since you’re using Rspec you can add --skip-test
since we don’t need the default MiniTest setup:
rails new your-project -d postgresql --skip-test
Note there is also an option for --skip-system-test
but after doing some side-by-side comparisons, I found that if you run --skip-test
you are also effectively running --skip-system-test
. So if you want system test support – and you probably do – there’s some extra setup you have to do yourself. More on that below.
Valenzuela notes in a comment on his post that his instructions for adding a spec/factories.rb
file are incorrect. But the instructions are still there in the post, so look out for that. You will instead want one file per model in the spec/factories
directory (and when you use a scaffold generator it will put factory files there).
The configuration shown in his post for spec/support/chrome.rb
results in running a headless browser for every system spec, which may be fine for a Javascript heavy site, but could be inefficient for other sites. As explained by Harrison Broadbent in Refactoring from feature specs to system specs:
If we didn’t add this config [see below], RSpec would use
selenium
for everything. There’s nothing wrong with this… it would just be an unnecessary performance slowdown…rack_test
runs a lot faster thanselenium
, but it doesn’t support javascript. By usingrack_test
as the default driver for our system specs, they run much quicker. Then we tell RSpec to useselenium
for tests that require javascript, sinceselenium
emulates a full browser, and we get the best of both worlds — performance by default, and javascript testing when we need it.
So I’ll recommend using the configuration shown in Broadbent’s post:
#spec/rails_helper.rb RSpec.configure do |config| ... config.before(:each, type: :system) do driven_by :rack_test # rack_test by default, for performance end config.before(:each, type: :system, js: true) do driven_by :selenium_chrome_headless # selenium when we need javascript end end
If you ran rails.new
with --skip-test
as I recommended above, you will also need to add the gems shown in Broadbent’s post, since --skip-test
also skips the system tests setup (which consists solely of adding these gems):
#Gemfile group :development, :test do ... gem "capybara" gem "selenium-webdriver" end
Lastly, I recommend Noel Rappin’s post A Quick Guide to Rails System Tests in RSpec as he has a comprehensive overview and also has tips for updates related to Devise and CircleCI.
RubyConf 2018 starts tomorrow, and just like I did with RailsConf, I’m very belatedly going to share some highlights from RubyConf 2017, which was in New Orleans last November. It was my first time attending RubyConf, and what struck me the most was the really strong sense of community. Here’s what one first-time attendee had to say:
…This conference was so incredibly worth it. I learned about sweet gems, cool projects, and job opportunities. But more importantly, I met SO MANY totally epic and amazing individuals that even after only three short days I happily now consider friends. I cannot wait to follow their coding lives and journeys in the years to come. I am confident that so many of them are going to do great and groundbreaking things. Plus, I cannot WAIT for my next RubyConf.
That’s from the post 31 thoughts I had while attending my first #RubyConf as an Opportunity Scholar. RubyConf’s Opportunity Scholar program provides financial support for folks who wouldn’t be able to attend otherwise, and are getting started with Ruby. The Scholars are then each matched with a Guide – experienced people who can help them navigate the conference, and make connections for professional development and job opportunities. I applied to be a Guide for this year’s RubyConf and I was selected – I’m looking forward to it!
RubyConf has three tracks of talks, so it’s not possible to attend them all, but here are the ones that were my favorites, including links to the videos for each of them:
And since the conference was in New Orleans, I now have to show you pictures from some of my time spent outside the conference…
RailsConf 2018 starts in exactly one month, and I’m looking forward to it! This means I should probably get around to saying something about RailsConf 2017. The video above is cued to start at the beginning of a lightning talk I gave. The title was “Why Do Planes Crash? Lessons for Junior and Senior Developers.” Analyses of plane crashes show planes actually crash more often when the senior pilot is in the flying seat, often because junior pilots are reticent to speak up when they see problems, while senior pilots don’t hesitate to do so when the junior pilot is flying. There are some great lessons developers can apply from this for how to do mentoring and pair programming.
The lightning talks were at the end of the 2nd day, and I made a last minute decision that morning to sign up and put a talk together. I’ve given a number of conference talks before, but never to a crowd this big, and never with so little time to prepare. Then when it was time to give the talk, there was a technical issue that prevented me from seeing my notes, so I had to wing it. Under the circumstances I think it still turned out ok. Here are my slides (they’re also embedded below) and some tweets about the talk:
Excited I'm near the top of the list for #railsconf lightning talks! “Why do planes crash? A lesson for developers.” Now I have to prepare 😨 pic.twitter.com/M04Oyp2peL
— Michael Toppa (@mtoppa) April 26, 2017
Great lightning talk by @mtoppa on "Why do Planes Crash" at #RailsConf2017 pic.twitter.com/o0fpRXarxZ
— Braulio Carreno (@bcarreno) April 27, 2017
Something to remember. #railsconf pic.twitter.com/44HfEvHT2r
— Heather Herrington (@EventsDoctor) April 27, 2017
@mtoppa showed us the dangers of mitigated speech at #railsconf. Save lives, don't sugarcoat! And value your junior developer's perspective.
— Adam Bowen (@adamnbowen) April 27, 2017
A thought as I board this plane out of Phoenix. Listen to those less experienced, and if you see something say something #railsconf #lessons pic.twitter.com/hHxqSsAsKY
— Santiago (@San_QG) April 28, 2017
Here are my slides for "Why do planes crash? Lessons for junior and senior developers" Thanks #railsconf! https://t.co/aoeEIZ2Kgy
— Michael Toppa (@mtoppa) April 27, 2017
I work for ActBlue and we provided Opportunity Scholarships for people who normally wouldn’t be able to attend, for financial or other reasons.
We adore our Opportunity Scholars and Guides! Big thanks too to @actblue for funding so many Scholars' travel as well; it's a huge help! 💗💗 pic.twitter.com/xwOuPMYGhb
— RailsConf (@railsconf) April 27, 2017
4 of us from ActBlue attended, and my co-worker Braulio gave an impressive full-length talk explaining how our technical infrastructure supports close to 8,000 active organizations, and handles peak traffic like the 2016 New Hampshire primary night, when our traffic peaked at 300,000 requests per minute and 42 credit card transactions per second.
This is the @ActBlueTech delegation that attended #RailsConf2017 We had a blast! @actblue #railsconf pic.twitter.com/kDHxzui2Dh
— Braulio Carreno (@bcarreno) May 2, 2017
Come to "High Performance Political Revolutions" to see what it looks like to handle complex transactions at scale in Rails #railsconf https://t.co/KzC1bGNKU1
— Michael Toppa (@mtoppa) April 27, 2017
On New Hampshire primary night, @actblue’s Rails app processed 40 credit card transactions/sec for Bernie Sanders #railsconf pic.twitter.com/9OqDtknKPN
— Michael Toppa (@mtoppa) April 27, 2017
"High Performance Political Revolutions" by @bcarreno #railsconf pic.twitter.com/6Z2DMpjWRs
— savannah ❤️🧡💛💚💙💜🖤 (@Savannahdworth) April 27, 2017
Slides for High Performance Political Revolutions (High Volume Track) https://t.co/ZzlwwwBqwZ #RailsConf #RailsConf2017
— Braulio Carreno (@bcarreno) April 27, 2017
Here are some other highlights from the conference…
This is a really impressive, honest talk & unlike any tech conference talk I've ever seen, which is both wonderful and very sad #railsconf https://t.co/fqoq9Ehmcy
— Michael Toppa (@mtoppa) April 27, 2017
Such an amazing keynote by @polotek here at #railsconf. pic.twitter.com/Io9TsqZVoe
— Marlena Compton (@marlenac) April 27, 2017
Video of Marco Roger’s talk mentioned above.
I had such so much fun sharing the story of goldilocks, the rails dev, with you all today, #railsconf! Slides here: https://t.co/0FcnDEycq1
— Vaidehi Joshi (@vaidehijoshi) April 25, 2017
Slides from my #RailsConf talk Learning to Embrace Failure. Now I can focus on enjoying the rest of the conference! https://t.co/p2fxlf9xdp
— Jess Rudder (@JessRudder) April 26, 2017
Here are my slides from my Practical Debugging talk at #railsconf: https://t.co/Cw6GZVEgph. I had a great time sharing it with you all!
— Kevin Deisz (@kddeisz) April 26, 2017
A group of us took in a Diamondback’s game the night the conference ended, and then the next morning a couple of us headed to the Desert Botanical Garden before flying home.
Finishing #railsconf with some baseball! pic.twitter.com/o2NtvxguKj
— Michael Toppa (@mtoppa) April 28, 2017
Staying in Phoenix one more day after #railsconf. The botanical gardens are amazing, and – who would have guessed – full of cactuseses pic.twitter.com/Ejvq4CduBb
— Michael Toppa (@mtoppa) April 28, 2017
Lastly, here are the slides from my lightning talk:
I recently moved from Philadelphia to Boston, and my house is currently overflowing with half-unpacked boxes. Despite all the craziness of moving (or perhaps because of it…), I was a speaker at WordCamp Boston this past weekend, and also gave a lightning talk at the BostonRB Ruby meetup last week.
If you’ve followed our blog so far, you may have noticed we talk about both WordPress and Ruby on Rails. While it’s unusual to see a consultancy that develops in these two very different platforms, supporting both gives us the flexibility to choose the platform that best suits our clients’ needs. For applications that primarily need CMS (content management system) functionality, WordPress is a natural fit, while Rails is best suited for highly customized application development. Well known sites with a focus on content, such as The New York Times, CNN, Mashable and many others use WordPress. Twitter was originally developed on Rails, and sites such as Groupon, Bloomberg, Airbnb, and many others also use Rails.
Many consultancies will shoehorn the development of your web application into the one platform they happen to know, even if it’s not a good fit for your needs (this may not be a conscious decision on their part – if they only know one platform well, they may not have the perspective to know whether another platform might be a better choice). For example, WordPress’ Custom Post Types are great for situations where your data can be well represented in the relational database table structure on which WordPress is built, and using them can speed along the development process. But if they aren’t a good fit, then you will likely encounter poor performance when your traffic increases, or have to do custom database development work, which is a breeze in Rails but is awkward and inefficient to do in WordPress.
We also do extensive work in javascript. The ROI calculators we’ve created for Hobson & Co are written entirely in object-oriented javascript, using jQuery and HighCharts (javascript frameworks such as AngularJS or ember.js would have been overkill for this kind of project). Our latest calculator for Greenway Health is a good example.
Regardless of the platform, we take an Agile approach to our work. On the technical side, this means a relentless focus on quality, using object oriented design and test driven development (TDD). My lightning talk at the BostonRB meetup focused on an aspect of this: following the Law of Demeter in Rails application development. Check out my slides.
My WordCamp Boston talk was about the business side of the Agile development process, with a focus on how to build professional, long term partnerships with your clients. I’ve given this talk a few times now, and it’s been a lot of fun to have the opportunity to refine it and keep improving it (I also gave it at the Philadelphia Emerging Technologies for the Enterprise conference and WordCamp Nashville). The video is above, and you can check out my slides.
Here are some tweets from people at each of my talks:
@mtoppa @bostonrb Great talk! I've made egregious violations of the Law of Demeter before that I'm now eager to try and fix (sans #try 🙂
— Rahul Horé (@TheAllBox) July 15, 2015
@mtoppa on Law of Demeter pic.twitter.com/lyS7RrgWEK
— Boston Ruby Group (@bostonrb) July 14, 2015
Eager to explore the Agile Contracts Primer and revolutionize the way we run our projects. Thanks, @mtoppa! @WordCampBoston…
— WP SuperService (@WPSuperService) July 18, 2015
Good talk by @mtoppa making the argument for agile development with time & materials contracts @wordcampboston #wcbos
— Andy Gagnon (@andygagnon) July 18, 2015
Great takeaway from @mtoppa's session on Agile contracts at @WordCampBoston #wcbos pic.twitter.com/UG3VywnnP7
— Amanda Giles (@AmandaGilesNH) July 18, 2015
agree: Having to give an estimate when you know least about the client places all the risk on you – by @mtoppa #wpbos pic.twitter.com/OtQCvJ9jOu
— Daria Mark (@dariamark) July 18, 2015
Agile consulting @mtoppa agile focuses on agreement about collaboration rather than deliverables and deadlines constant feedback = less risk
— Pat Carroll (@PatC508) July 18, 2015
Loving the agile contracting idea presented by @mtoppa at#wcbos. Turns out I've been doing this all along without knowing it's a framework.
— Daria Mark (@dariamark) July 18, 2015
Armchair WordCampers: Plethora of WP knowledge in @wordcampboston w/ @bobbiec @williampd @mtoppa @scottwyden @professor @michaeldcain #wcbos
— David Bisset (@dimensionmedia) July 18, 2015
Cybersource is a subsidiary of Visa, and is one of the largest providers of online credit card payment services. As any developer who has worked with Cybersource’s Silent Order POST service can tell you, it’s not the easiest service to work with. It provides a great deal of flexibility, but that comes at the cost of you having to write a good deal of your own code in order to use it. Setting up automated testing is also extremely difficult.
Last year I completed a Cybersource project for the University of Pennsylvania, and that project provided the inspiration for 2 Ruby gems, to simplify working with Cybersource: Cybersourcery, and Cybersourcery Testing. There’s also a demo project, so you can see an example of how to use them in a Rails project.
The readme files provide detailed documentation of their features and how to use them. So rather than repeat that information here, let’s take a look at why these gems are necessary in the first place. There’s a lot to cover, so I’ll discuss the testing gem in this post, and Cybersourcery in the next one.
Writing tests that can be repeated and automated provides benefits such as improving the design of your code (if you’re doing test-driven development) and catching regressions early (when changes to your code inadvertently introduce bugs). This can be challenging with 3rd party services, as we don’t want to call those services every time we run our test suite. VCR is a gem that helps with this problem: by recording requests and responses, it allows you to play back those responses in your tests, rather than making real-life calls in every test run.
Unfortunately, Cybersource makes this kind of testing especially difficult. There are 3 different servers involved in processing a transaction through Cybersource, and the key difficulty is that one of them is at a fixed URL that is not easy to swap out in the test environment. Cybersource calls this URL the “Customer Response Page.” It is saved on the Cybersource server as part of the merchant profile, so it cannot be updated dynamically. If you are a developer attempting to test Cybersource transactions, this diagram illustrates the scenario:
+ + + | Developer's | Cybersource | "Customer Response" User's browser | test server | test server | server +------------------+--------------------+-------------------+---------------------+ Request credit card form + | +-----------> Respond with credit card form + | Submit form <-------------+ + | +------------------------------> Process and log transaction; generate "Customer Response" form + | Hidden "Customer <------------------------------+ Response" form is automatically submitted by JS + | +---------------------------------------------------> Process submission; generate response page + | Display <-------------------------------------------------------+ response page
So, what the heck is going on here? The first few steps makes sense, but then when you submit the credit card payment form to Cybersource, things start to seem strange. What happens is that Cybersource sends a seemingly blank page to your browser. But it only appears for a second, as it contains a hidden form, which is immediately and automatically submitted to the “Customer Response Page.” This is the page where users are sent when transactions are complete. You provide the URL for this page when setting up your merchant profile in the Cybersource Business Center. This is a page you create and host yourself – you can use it to show users a “thank you” message, log information about the transaction, etc.
So why doesn’t Cybersource simply redirect to your response page after processing the transaction? Why this peculiar reliance on a hidden form? The reason is that conventional redirects use the GET method, which is meant for idempotent requests. An idempotent request is one that can be safely repeated, which definitely does not apply to a credit card transaction, or logging it. So Cybersource’s forms appropriately use the POST method, which is meant for non-idempotent requests. This is why, if you submit a POST form, and then click “back” in your browser, and try to submit the form again, your browser will warn you, and ask if you really want to submit the form again.
In the case of Cybersource, this is a thorny problem. Trying to do a POST redirect has issues, for these reasons. A redirect isn’t really appropriate anyway: the Cybersource server does some work when it receives the user’s credit card submission (charging the user’s card), and then your response page may also do some work when it receives the hidden form submission (such as logging details of the transaction). These are distinct activities, so – while having two forms may seem odd – it’s a viable solution. Cybersource came up with this before asynchronous requests were a common practice (which is a big part of the reason it’s harder to work with than newer services like Stripe).
The Cybersourcery Testing gem makes it possible to set up automated, repeatable tests in this complex environment. It provides a “translating proxy” server, running on Sinatra, which has middleware to manage the requests and responses between the 3 servers involved in Cybersource transactions. Middleware is especially useful in this situation, as it allows us to modify requests and responses before they reach the application’s code.
In order to explain how the gem works, let’s first take a look at its dependencies:
target_host
URL, which indicates where the proxy server should redirect requests. We also need to provide it with a request_mapping
, which indicates what strings to find in the requests and responses, and what to change them to. It uses a hash format, so that on requests, the keys are translated to the values, and on responses, the values are translated to the keys.The Cybersourcery Testing gem inherits from the Rack::Translating Proxy gem, and implements the methods described above. Specifically:
For the target_host
, we provide the URL of the Cybersource testing site. So if the proxy server is running at http://localhost:5556
, and the target_host
is https://testsecureacceptance.cybersource.com
, requests to http://localhost:5556/some/path
will be redirected to https://testsecureacceptance.cybersource.com/some/path
. The gem also hooks into VCR, allowing us to record transactions that pass through the proxy server, for use in subsequent automated tests.
This is a simplified version of the request_mapping
implementation, using hard-coded values for clarity:
def request_mapping { # local test server Cybersource's "Customer Response Page" URL 'http://localhost:1234/confirm' => 'http://your-site.com/confirm' } end
A Cybersource transaction in this environment looks like this:
target_host
, the proxy server passes the request through to the actual Cybersource test server. If the transaction was previously recorded with VCR, VCR will instead play back the recording of the transaction.request_mapping
will rewrite the URL of the form’s action, causing the form to instead submit to the local test server.The upshot is, the gem handles all this complexity so you don’t have to. By following the setup steps in the readme, you can get a robust test environment setup for Cybersource without breaking a sweat. The Cybersourcery Testing gem offers other features as well, such as reporting of undocumented Cybersource errors. Check out the README to learn more!
I haven’t been blogging for ages – it’s time to fix that. Let’s start with a recap of last night.
The monthly philly.rb meetup at the Comcast Center: how good were the presentations? They were just as good as the view from our room on the 45th floor:
I got a lot out of Nate Olds’ talk, “Refactoring with a View.” A large part of my career has been spent wrestling with big, old, sprawling, messy codebases, so Nate’s real-life walk-through of his strategies for dealing with such challenges was very informative. Check out the February meetup page for more information.
Afterwards, a group of us went to Ladder 15 for beer, where we met up with Maria. She stoically suffered through several minutes of extremely nerdy conversion, before she and I headed to the Boot & Saddle, for a rare evening out without the boys, to see one of Maria’s favorite bands, Cibo Matto. It was a sold out show, and we ended up stuck near the back, but it was still a good time. I tried to take a couple videos, but they didn’t come out. A good introduction to their utterly goofy side is the song Sci Fi Wasabi (I’m Miho Hatori, straight out of purgatory), and their split-screen video for Sugar Water, with one side portraying the visual story in reverse, is quite clever (the ending is in the middle).
I’m presenting at the WordPress ‘Burbs meetup next Monday on Kanban. And on March 1 I’m presenting at WordCamp Lancaster: A11Y? I18N? L10N? UTF8? WTF? Understanding the connections between accessibility, internationalization, localization, and character sets.
I started attending the philly.rb meetups in the early Fall, and I did my first lightning talk last night (before the scheduled main speaker, anyone can come up and give a talk that’s 10 minutes or less). There’s a big debate right now in the Rails community on the “right” way to design applications. As a relative newcomer to Rails, I’ve been trying to find the right balance between leveraging my previous experience and habits from working in other languages and frameworks, vs. the opportunities Rails provides to approach application design in a different way (the “Rails way”).
My talk takes a look at one aspect of that debate – how to apply the Law of Demeter to Rails development. I’ve given many long talks before – this was my first short one. It was actually harder, especially since I delved into theory, but it went well. I was going to write a summary this morning, but @trevmex already did.
Here are my slides (direct link):