All The World’s a Stage…until you have CORS issues.
During our Module 4 project at Turing School, a colleague and I were tasked with setting up the staging environment for the brownfield Rails project we were working on. No big deal, right? The app was already in production on Heroku, so surely pushing it up to staging would be easy. Little did we know we were in for a wild ride of frustration, victory, more frustration, and finally, success. What follows is a catalog of some of the issues we encountered.
Our brownfield project consisted of two Rails apps, Enroll and Apply. Apply would perform user authentication and authorization, and then Enroll would communicate with Apply to retrieve this user information for its own authentication purposes. This communication required session information to be stored in the browser and shared between the two apps which were running separately.
We were able to successfully push Apply to Heroku staging using their free cloud hosting, but when it came time to push Enroll, we discovered that it was not communicating with Apply. Our attempted debugging involved resetting environment variables in Heroku, creating staging environment variables in Enroll, removing problematic gems, and other attempted fixes. Nothing worked. We were incredibly discouraged. We even pulled in some instructors who were stymied for hours until one of them came upon this crucial bit of information on Heroku’s website:
We were trying to communicate between *.herokuapp.com apps, but it turns out the session information was not being passed between them. Our instructor solved the problem by setting us up with a paid Heroku domain for both Enroll and Apply, and the problem was solved. Lesson: Read docs carefully! You never know what will end up being a roadblock. Understand your hosting service, and make sure you follow their rules.
Our problems were far from over. If you’ve ever tried to communicate between two apps, you might have run into issues with Cross Origin Resource Sharing (CORS).
“The CORS mechanism works by adding HTTP headers to cross-domain HTTP requests and responses. These headers indicate the origin of the request and the server must indicate via headers in the response whether it will serve resources to this origin. This exchange of headers is what makes CORS a secure mechanism.” -ConstantContact
While the mechanism is intended to enhance security, it can cause frustrating bugs when making AJAX requests with jQuery. This occurs because AJAX initiates a client-side communication rather than a server-side communication. This, coupled with the fact that you have two separate apps trying to communicate with the CORS mechanism, can cause the receiving app to block the communication. So how do we get around this in our Rails apps? While you could add several lines of code to your API controller, the rack-cors gem makes it easy. Just insert the following into your gemfile:
gem 'rack-cors', :require => 'rack/cors'
Then make a new file called cors.rb and place it in your config/initializers folder. This file should contain the following:
Rails.application.config.middleware.insert_before 0, “Rack::Cors” do
origins ‘localhost:3000’, ‘https://your-app-name.herokuapp.com/'
methods: %i(get post put patch delete options head)
Note that you can allow any number of origins and specific resource paths with the gem. This gives you a higher degree of security. If you’re going to be playing around in development, it makes sense to add to allowed origins your localhost port along with the final production domain of the application which is initiating the AJAX call.
You probably won’t be out of the woods yet if you’re using AJAX. You might run into CSRF issues. But that’s another issue for another day. Happy coding!