Building a Wishlist App using Rails + jQuery
Part I: Building a Wishlist App using Ruby on Rails
Since building my wishlist app using Ruby on Rails, I have extended my app by adding dynamic features through jQuery and a JSON API.
In this project, I’ve added three new features:
- Users can navigate to the next Product without refreshing the page
- Users can view all products associated with a chosen wishlist
- Users can create a new wishlist and review the new wishlist information once it is successfully created
You can see a demo video of my app here:
Adding jQuery to Gemfile and asset pipeline
Starting with Rails 5.1, jQuery is not included by default. In order to use jQuery, we must first add it to the Gemfile and install it:
gem 'jquery-rails'
bundle install
Next, update the JS manifest file with jQuery paths:
//= require jquery3
//= require jquery_ujs
//= require_tree .
When we include the manifest file in our layout with javascript_include_tag
, and the application layout file is a great place to include this tag:
<%= javascript_include_tag 'application' %>
The rails asset pipeline will then look for all of the files listed in the Asset Path — including jQuery and all .js
files in the assets/javascript
folder.
Creating a Rails API
In order to build the three features above, I needed to create a Rails backend API (Application Programming Interface) that will interact with a jQuery frontend. My rails API will provide access to the data stored in my database in JSON (JavaScript Object Notation) format, which looks a lot like a Ruby hash:
{
"id": 74,
"name": "2019 World Traveler",
"price": 26,
"url": "https://riflepaperco.com/shop/desk/calendars/2019-world-traveler/",
"category": {
"id": 11,
"name": "Calendars",
"link": "https://riflepaperco.com/shop/desk/calendars/"},
"wishlist": null
}
My app’s jQuery frontend is able to fetch /get JSON data from the API, use the JSON data in my JS code (e.g. display a product on button click), and ultimately render data to the HTML DOM without refreshing the page.
But how exactly can we create a Rails API?
Adding ActiveModel::Serializer to Gemfile and asset pipeline
ActiveModel::Serializer(AMS)
provides a way of creating custom JSON by representing each resource as a class that inherits fromActiveModel::Serializer
— Hendra Uzia
In another word, AMS provides a convention-based approach to convert our Ruby models into JSON objects, including model associations! In order to use AMS, we must first add it to our Gemfile and install it:
gem 'active_model_serializers'
bundle install
Next, generate serializers for each data model using rails generator commands:
rails g serializer product
This will create a serializer in app/serializers/product_serializer.rb with a single attribute: id
:
class ProductSerializer < ActiveModel::Serializer attributes :idend
You can add more attributes and model associations to the file, but pay attention to only include data that you want to expose/share with your end client (in this case, the jQuery frontend):
class ProductSerializer < ActiveModel::Serializer attributes :id, :name, :price, :url, :image_link belongs_to :category belongs_to :wishlistend
This mirrors the Product
model associations:
class Product < ActiveRecord::Base belongs_to :wishlist belongs_to :categoryend
Now we are ready to build our new features!
Feature 1: Navigate to the next product on product page
User Story: As a user, I need to be able to see the next product, so that I can decide what to buy!
In order to fulfill the user story above, we need to:
- Attach an event listener to the “Next Product” button
- On button click, the app should somehow get the data for the next product and update the page with this information (without refreshing the page)
How can we get data from rails API? By using AJAX (Asynchronous JavaScript And XML), of course!
AJAX use a browser built-in XMLHttpRequest object to request data from a web server and JavaScript to use the data or display data in HTML DOM — W3School
Here’s the actual code snippet showing how I implemented this feature in Product
show
view, note that I’m using a jQuery GET $.get()
request to fetch data asynchronously from the server:
Feature 2: View all products associated with a chosen wishlist
User Story: As a user, I need to be able to see all products associated with a wishlist, so that I can review my shopping list!
In order to fulfill the user story above, we need to:
- Attach an event listener to the “Show Products” button
- On button click, the app should get data for all products associated with the chosen wishlist, and update the page with this information (without refreshing the page)
You guessed it — we will use the handy AJAX request again! Here’s the actual code snippet showing how I implemented this feature in Wishlist
show
view, note that I’m using a GET request again:
Feature 3: Create a new wishlist
User Story: As a user, I need to be able to create a new wishlist and see it on screen right after, so that I can check my wishlist information is correct!
In order to fulfill the user story above, we need to:
- Attach an event listener to the “Create Wishlist” button
- On button click, the app should get all form input values and create a new
Wishlist
object. This new object should be persisted to our database. - If the object is created successfully, update the page with information for the new
wishlist
(without refreshing the page)
Here’s the actual code snippet showing how I implemented this feature in Wishlist
new
view, note that I’m attaching an event listener to form submission to setupCreateWishlist
:
To stay organized, I’ve extracted my JS code into a separate file in assets/javascript
, which the asset pipeline will use the JS manifest we configure in Rails to automatically concatenate all files listed into one JS file in production.
As you may remember from your CRUD operations, to create a new resource, you need to send a POST request. We will use the jQuery POST $.post()
method to send an asynchronous request to submit the data to the server. If this is successful, we will get the response back in JSON format.
We will pass our serialized form input value (i.e. values
) as argument to createWishlist()
, the AJAX function that sends a HTTP POST request. If the request succeeds, we will receive response data in JSON format from our Rails API and create a new Wishlist
object with Javascript class declaration: class Wishlist
.
JavaScript classes, introduced in ECMAScript 2015 (ES6), are primarily syntactical sugar over JavaScript’s existing prototype-based inheritance. — MDN
The constructor
method initialize an instance, it is called automatically to initialize objects and keep data encapsulated, thereby keeping the JSON data private and inaccessible to the outside world. TheWishlist
class has a prototype method, updateHTML()
which will render data onto the page:
Voila! And we have implemented three new features using a jQuery frontend in our app. In this project, I’ve learned about Rails asset pipeline process, building and using an API, and using AJAX calls to GET and POST data to my server!
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. Contributions are always welcomed! And thank you for taking the time to read through this blog.