Making My First Rails App

Edward Heaver
3 min readMar 14, 2020

As part of my ongoing project work with Flatiron, I had to design a Rails app that utilized ActiveRecord validations to manage models. I also had to implement Omniauth sign in via a 3rd party like Facebook, or Google. From my Sinatra project, I had gained a strong understanding of the Google OAuth2.0 flow. So, it felt extremely logical to use this again for the Rails project. There were some caveats to this that I didn’t know entering the project, but I overcame these and now have a strong understanding of troubleshooting these issues.

The idea for my app was a social media site driven by books. I wanted to focus on creating an endpoint for a 3rd party API (Google Books) to generate objects that would be stored in the database for users to interact with. My core focus for this project was to get a default user flow down before adding features. I felt that in my Sinatra project, I had tried to do too much in too little time, leading to a product that wasn’t fully tested. This time round felt much cleaner, and Rails helped a tremendous amount in constructing routes and handling resources. The default flow would be for a user to find books via a search form, adding these books to their library, and other users commenting on what is in the library. Part of the criteria for the project was to have 2 Has_many Through relationships, creating a bi-directional domain for the object to interact in. Initially, I only want the user to have 1 library. Which will be made from a model scope ActiveRecord method finding books by the User ID. In future, I will look to have multiple libraries for each user so that users could sort their books, and share books that matched a specific topic. I will look to host this project when I have more features implemented and a more cohesive admin view.

Creating the end point was very simple. I used this Medium article as a template, but added some other functionality to improve the return.

def self.search_books(query_string, author="", title="")url = "https://www.googleapis.com/books/v1/volumes?q=#{query_string.to_s}&maxResults=20&key=#{ENV["API_KEY"]}"response = HTTParty.get(url)results = response.parsed_responseresultsend

The endpoint being restricted to a number of elements means that I can better understand what the returns look like and drive users to submit stronger queries. I also append my API_KEY (using dotenv and the gitignore to protect my key) to make sure I can log what requests are made. I also added in arguments for the author and title. This will be part of a future feature, where users can do an advanced search by multiple criteria. Google’s Books API has great documentation, so implementing new features will be very simple in future.

To handle user accounts, I chose Devise. Mainly due to the ease of use with Omniauth. Implementing Devise was incredibly simple, with several great guides online. What wasn’t so simple was using Omniauth. My experience with Google’s OAuth2.0 flow was helpful here, but there were several caveats that caused issues with poor documentation around the web. The 2 problems I encountered, specifically with Google as an Omniauth provider, where:

  1. CSRF detected
  2. Invalid credentials with Google.

Both of these could be solved with adjustments to the provider initializer in devise.rb / Omniauth.rb and additions of methods to the model to circumvent CSRF tokens. One issue I had to troubleshoot was a database rollback caused by signing in via the provider. In the end, what solved it was removing the validations from the model. I implemented these after working out how best to handle these and adjusted the method that created the users from the authorised provider.

There are multiple security concerns raised by implementing the fixes to these problems. But, for the purposes of this project, I was willing to accept these and keep moving forward.

Finally, implementing access policy was also very simple. Using a migration to add the field to the users table was all that was required here. In future, I would like a separate policies table, with access to a view so that admins can make other admins. I could also incorporate other controls here to make security in the program much stronger.

Overall, the project was successful. I feel that operating on building a core user flow is much more important than building out the feature list straight away. Without building a good foundation first, you’re never going to have a strong end product.

--

--

Edward Heaver

Backend Engineer with a passion for clean code and fun features