Building a Multimedia Content Sharing Website With Rails
Tags: rails, ruby, api, database
Published: 2021-01-24 01:00:39

For a Flatiron School project I wanted to build a website that allowed users to create mixes/playlists and add multimedia content to them. I wanted the site to be social, where users could share their mixes, follow users, comment, and like posts. This post is meant to walk readers through the process of creating this website. Ruby on Rails let's go!

[The website](https://memix.herokuapp.com/) is hosted on Heroku - feel free to check it out and make an account! Also, feel free to check the code out on [github](https://github.com/nicklevenson/me-mix-3). Video walk through can be found [here](https://drive.google.com/file/d/1Wbi01rJem66jXHCgdToq2w5VS2XNPDVQ/view?usp=sharing).

**Phase 1: APIS and Scraping**

Utilizing 4 apis (Spotify, Omdb, Google Books, the MET) and 1 scraper (the Poetry Foundation), I was able to create a search engine for these media types. Learning to use these apis was a great learning experience for using api keys and handling data. For spotify, there was a handy ruby gem called 'rspotify' that made queries easy. Likewise with Omdb, I used a handy gem called 'omdb-api' to help access their open database. I manually fetched data from the MET's open database as well as the google books api. For poetry, I ended up scraping the Poetry Foundation's website. Here's an example of how I configured the Spotify api, as well as the poetry scraper: 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/z6f792koiflnrblog4bd.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/67t7v9tvgy9694w3g79s.png)

If you look close you may see that I transferred the data from each api into an object that has the same attributes. This was to normalize the data across all the apis, so I could create one model called 'Content' that could be any type of media. More on this in the next section. 

**Phase 2: Plotting the DB and related models**

Here is the schema to the app. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vg87kew9g33b6mhemm60.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dz2khgmiqmuh6dzqu734.png)

Once I had figured out how to normalize the media data, I was able to create a model called Content to represent those objects. I made a User model which had many Mixes, and mixes had many Contents. However, Contents could belong to many mixes so I used a joins table called MixContent. Contents could also have Notes that Users added to them inside their Mixes. That meant the Note model was simply a joins table between Mix and Content. I also added other tables which allowed Users to like and comment on Mixes, as well as follow and be followed by other Users. 

**Phase 3: The MVC**

I think one of the most challenging parts of this project was the user interface. I had to make things clear so users could understand how to search for content and add it to their mixes. I ended up making a search bar where you could choose to search for items in every category, or you could filter the categories by type. I searched 'Dev Article' in all and these were the results I got. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/23zbq73wyaq1vie6ezqs.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fvlgzu3tvf642yz9gny8.png)

In the pictures, you can see a space where users can select or create a new mix on a specific piece of content and then add that content to that new or existing mix. I used a datalist element for this feature. Implementing this part was definitely a challenge. Here's what the erb looks like for the datalist: 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/99pss5nwfxmodg62rjsw.png)

Basically, the form builds a new mix for the current user, as well as a new content for the mix. The new content data is being pulled from the api data that was sent from the apis/scraper. The datalist tag gives the user an option of selecting from their existing mixes or writing in a new mix. When the user hits the submit button, the controller persists the new content to a found or created mix for that particular user. 

Here's where a user can filter the results. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/q9wslcjf60v5vu4if72g.png)

Here's what the code looks like in the controller for the search and filter: 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/m28v3598lk5t3z83iglq.png)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6khek5b05sxuwfgek4gw.png)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/sm7x9vul1k6tek78pw5l.png)

What's going on here? Well, the controller is calling a helper method to get an array of results. The @lastresult bit is just checking the last filter the user submits so it will persist on a refresh. Inside the helper, we are checking what the filter is, and then calling from the different apis or Mixes to get results based on that search and filter. We also have some helper methods to check and see if the result is a mix or a content to help out with rendering in the views.  

Users can also search in Mixes themselves. This query will return any mix who's title is similar to the query, as well as mixes who's content matches the query.

There were a lot of other major challenges with the MVC, but these were probably the most important challenges I faced for the app.

**Phase 4: Prepping for Heroku**

Prepping for Heroku involved two major steps. I had to make my database a Postgres db. That part wasn't too difficult with the following code: 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/81315oreb3nfls8hjlf8.png)

The harder part was the storage. I wanted my users to be able to upload photos to their profile if they wanted. Originally I was using active storage for this purpose, but because active storage uses a local disk, this wouldn't work properly on Heroku. I had to configure my storage to use amazon web services. It took a while to figure out but [this article](https://medium.com/@iachieve80/rails-6-0-upload-images-using-active-storage-and-amazon-simple-storage-service-amazon-s3-36861c03dc4a) really helped me out. 

Once I figured all that out, I was pretty much good to go on Heroku!


**Future plans:**

While I did use Bootstrap for styling, I didn't use any javascript elsewhere. There are multiple features that would be great if the page didn't require a refresh. So learning to send ajax requests and have the page update without a refresh would be ideal. I tried using the new rails gem Hotwire, and it actually worked really well. I was able to make changes to the db with no refreshes. However, something about Hotwire was doing something to my ability to use Omniauth for logging in - something to do with the CORS policy. I couldn't figure out a way to get around this so I scratched using Hotwire and stuck with good ol page refreshes (Omniauth was required for this project). Next time Hotwire! 

I would also like to do some more styling and make the site ideal for small screen use. It works on a smartphone, but is not amazing. I could spend weeks adding more style features, but I only had a week to complete the project. 

Adding a notification system for users would be awesome, but I didn't have time to figure that out. 

**Conclusion:** 

This project was extremely challenging and really pushed my limits on how much I could get done in such a small amount of time. However, I learned a plethora of things and I am proud of what I created. I hope the site can attract more users because I genuinely believe in its use case. I love getting a glance into other people's taste in these media categories. I hope you found this article helpful, and would always appreciate constructive feedback on the project. There was a lot to cover and I only scratched the surface of the inner workings of my app. I would be happy to answer any questions readers may have. 

Thank you for reading!