Building a Wishlist App using Ruby on Rails
A part of building software is learning to “scratch your own itch” — identifying a problem with an existing website, or a feature that you wish it had. I was browsing through Rifle Paper’s online store and noted that there was no easy way to sort products!
In their online shop, products are organized by categories and you can only view products for each category. I was trying to find some “fillers” to add to my cart to meet the free shipping requirements (order over $50), but there was no easy way to find products under a certain price point (e.g. $7). Within each category, you can “sort” the products. However, there were no options for sorting (e.g. by name, price or size).
So, of course, I decided to build a wishlist app! My app will have the following features:
- Provide user login with Authentification and Authorization
- User can view all products on one page
- User can sort products by name and price
- User can create, read, update and delete (CRUD) a wish list
- User can add product(s) to a wishlist
The app follows the Model–view–controller (MVC) architectural pattern.
To start, I need to define the necessary models/ Ruby classes. Models are the blueprint for individual objects to be created, and each model has a corresponding database table:
- product: stores product information such as name, price, category, image link etc
- category: stores category information such as name, image link etc
- wishlist: stores wishlist information such as name, budget, user notes etc
- user: stores user login information such as name, email, password etc
Validation rules and model association are defined in each model file, here’s the code for my Product model class:
In my product model, I defined two scope methods: free_shipping
and sort_by_price
. Scope methods are named class method for retrieving and querying objects, with a corresponding route.
Once the database is created using ActiveRecord, it was time to populate our database with actual data! I wanted my app to have the most updated, live product data from Rifle Paper’s website. As the company does not provide a developer API, I decided to build a web scraper to solve this problem.
I had learned to build a web scraper for my Ruby CLI gem project, and Nokogiri is still my default library for parsing HTML. Thankfully, rifle paper’s website is well structured with semantic HTML.
Following the single responsibility principle, I defined four methods within my scraper: get_page, get_categories, get_products, get_all_products
:
Ruby make it easy for developers to populate their database using rake: rake is a Ruby gem and the command line utility of Rails. Typically, you will add the initial data to populate your database in db/seeds.rb
file. In this app, the database will be seeded with records created by my scraper.
As with any Ruby app, users will interact with your app through its views (HTML templates mixed with Ruby tags). But first, I need to define the available routes and controller actions.
The router processes URL request and ‘routes’ the request data to the corresponding controller actions. In my router, I defined all the possible URLs including logical nested routes (e.g. users/1/wishlists
to see all of user1
’s wishlists
):
For example, users expect a website’s sign-up page to have a URL that looks something like this: ...com/signup
.
User signup actually calls for the creation of a new user
in our app. When the Rails app receives this request, it is translated to GET ‘/signup’
in your router, which needs to be matched to a controller action. The controller then creates a new instance of the User
model:
def new @user = User.newenddef create @user = User.new(user_params) if @user.save session[:user_id] = @user.id redirect_to '/' else render 'new' endend
Lastly, I created my user authentification and authorization using Bcrypt and OmniAuth gems. Bcrypt is used to securely hash user password to be stored in our database, and OmniAuth is a library for user authentification. I’ve also added omniauth-facebook
strategy, which allows authenticate user sign-up with their Facebook account using the OAuth 2 Graph API.
Overall, this was a challenging project! I learned a lot about building CRUD apps in Rails, went down the rabbit hole of user authentification with OmniAuth configurations, and managing complex associations for multiple data models!
I invite you to check out my Github repo here, clone or fork it and poke around! If you spot a bug, please file an issue and let me know. Contributes are always welcomed! And thank you for taking the time to read through this blog.