How to Build a Reddit Clone with Ruby on Rails

In this tutorial you will get a Ruby on Rails Reddit App up and running on your local server, and will push your work into github. If you are casually browsing and are maybe interested in doing a Ruby on Rails tutorial, stop what you are doing RIGHT NOW and give this podcast a listen! It will give you the fuel you need to continue down the web developer path; it definitely fueled me.

Reading and executing tutorials is an amazing way to learn, so roll up your sleeves, take a slug of coffee, and let’s dive in!

This tutorial is loosely transposed from Mackenzie Child’s Youtube Tutorial. I’m transposing this tutorial because Mackenzie flies through the content and I wanted to slow it down a bit. I figured I’d add some value to the Ruby on Rails community and learn a little myself by transposing into blog format.

This is the second tutorial I’ve cloned from Mackenzie’s 12 Web Apps in 12 Weeks Challenge.

This style of website is called a “Link Aggregator” and is similar to Reddit and Hacker News.

The first thing I’m going to do is create a github repository for my work:

Image for post
Image for post
Image for post
Image for post

Next, I’m going to jump into my command line and create the bones of the application:

Which lists the files in the current directory:

Image for post
Image for post

Which “changes directory”.

Then I’ll list the files in Desktop again with:

And then cd (change directory) into my Project folder:

Type ls again and I see my other Rails projects

Image for post
Image for post

I’m right where I want to be, so I’m going to go ahead and create the bones of the application with:

Image for post
Image for post

cd into your new app, and then let’s make sure everything is working correctly:

and then navigate to http://localhost:3000/.

Your page should look like this:

Image for post
Image for post

We need to start the rails server before anything will happen at http://localhost:3000/:

Refresh the page and:

Image for post
Image for post

Great. Everything is working properly. Next I’m going to commit these changes to me github repository for this project:

Check github:

Image for post
Image for post

Everything looks good.

Next I’m going to open up the project file in my text editor:

Image for post
Image for post
Image for post
Image for post

This will get us to 3:20 / 1:08:06 of Mackenzie’s tutorial. In case you get stuck, it’s probably a good idea to check out his video to see what I may have bungled. I’ll continue to pepper in time-stamped video links for you as we go along.

Requirements for our site:

  • Users need to be able to sign-up, sign-in and sign-out
  • Signed-in users will need to be able to submit a link with a title and a URL
  • Users will be able to vote up or down on the link submissions
  • Users will be able to comment on link submissions

We will begin with link submissions

First, we are going to create a new branch in git:

And then we will generate a scaffold for the link submission:

Which gives us the following results in our terminal:

Image for post
Image for post

Migrate the database we created with the scaffold:

And then let’s run the rails server to check out our work:

Navigate to http://localhost:3000/links :

Image for post
Image for post

Great! It’s all working.

I’m going to add a couple of links and make sure everything is working.

Image for post
Image for post
Image for post
Image for post

Excellent. Everything is functioning.

Next we will commit our changes and merge our git branch into the git master branch:

Kill the server: ctrl + c. Then execute each git command individually in your terminal. Write it out rather than copy/paste; you’ll want to commit these commands to memory.

Next, we will create users

This will give us the ability to signup, sign-in and sign-out. We will be using the devise gem to help us add user authentication into our app.

First we are going to create a new branch in our github repository:

“Switched to a new branch ‘add_users’

Next, we will actually add the devise gem to our gemfile. Navigate to the Ruby devise gem page and copy the gemfile:

Open the gem file in your text editor, and add the above line of code into the gemfile. See lines 8 and 9:

Image for post
Image for post

Save the file.

In the command line:

Next, we’ll finish installing devise:

You’ll see the following in your command line:

Image for post
Image for post

Let’s complete setup.

First, add the following to config/environments/development.rb:

Save the file.

Second, add a root to your routes.rb file. I’m going to make the root the links index page:

Before:

After:

Check to see if your routes.rb update worked:

Got to http://localhost:3000/

Image for post
Image for post

Great! It worked.

Third piece of the devise gem install: Ensure you have flash messages in app/views/layouts/application.html.erb.

Mackenzie improvises a bit here, and uses some code that will work with the bootstrap code that we will add later. We’ll follow along with him.

Add the following to app/views/layouts/application.html.erb:

Before:

After:

Next, we’re going kill the server (ctrl +c), and then run:

Image for post
Image for post

Great. Now we can generate a user.

Then, migrate the database:

Image for post
Image for post

Now we can create a user on our web app.

Restart the server

And head to http://localhost:3000/users/sign_up

If your page looks like this, your code is working:

Image for post
Image for post

I’m going to sign up; looks like it worked!

Image for post
Image for post

Next, we are going to get into rails console and take a look at the database:

(Video link here)

Kill the server. Then:

Then:

This will tell us how many users we have on the web app. It should be “1”.

Then:

And you should see the email you just entered in the terminal. I see:

Image for post
Image for post

Control + d will exit the rails console.

FYI, if you like to keep a clean workspace, you can always clear the terminal with:

Now we are going to commit our changes:

then

then

Now we can sign in and out, but we need to update our view files so that we have some accessible links on the home page. We don’t want users to have to know to navigate to http://localhost:3000/sign_up do we?

(video link)

Now, in our app/views/layouts/application.html.erb file, we are going to add a conditional statement to serve different links depending on whether the user is signed in or not:

The whole code block will look like this before:

And this, after:

Don’t forget to save your file.

Start the server:

And head to http://localhost:3000/ to make sure everything is working:

Image for post
Image for post

Yes! Everything is working.

Go ahead and sign out and then sign back in to make sure EVERYTHING is working.

Now, we are going to create an association between the user and the links to make sure that unregistered users can’t navigate to the url for submit link and submit a link. Because as it stands, a non-registered user could do that; they’d just need to know the url path.

(video link)

Head to the user model at app/models/user.rb and add

Before:

After:

And then we will add an association to the link.rb file:

Before:

After:

Then we are going to get back into the rails console to inspect our work.

We are going to ask the rails console what the first link is:

Image for post
Image for post

Then let’s ask the console what user submitted this link:

The console returns => nil

Without this association that we just made between users and links, we would have been shown an error message for the query “@link.user”

Don’t mistake “nil” for an error. This isn’t technically an error, it just means that we haven’t added a user column to our database. Let’s do that now.

Exit the console with control + d.

We are going to run a migration to add users to the links database:

then run:

Output:

Image for post
Image for post

Now we are going to get back into the rails console to confirm our work:

First we do:

And we get a bunch of gobbleygook, and then we do:

And see: => Link(id: integer, title: string, url: string, created_at: datetime, updated_at: datetime, user_id: integer)

The id integer is there! Success.

Exit the console; control + d

Annnnd it’s time for a commit.

then

then

Great.

Next, we are going to update our link controller so that when a user submits a link, their user id gets assigned to that link.

(video link)

We are going to update the new and create methods inside the app/controller/links_controller.rb

New method before:

New method after:

Create method before:

Create method after:

Save the file!

Let’s confirm that this worked. Add a new link, and….

Image for post
Image for post

Huzzah! Let’s get back into the rails console to check our work.

Then:

Image for post
Image for post

Great! user_id: 1 submitted this last link. That was me (you). Now let’s check in on user_id: 1

Image for post
Image for post

Cool. Everything is working.

Now we will add some authentication to our control to make sure users stay within their lanes.

(video link)

First, we will add a before filter to our links_controller.rb:

We’ll add it right there at the top. Before:

After:

To test this, let’s log out and check out the site and see if we can delete a link.

Image for post
Image for post

ERRROROROROROROROR.

After a bit of research I learned that before_filters have been depreciated. Link here. We need to update our before_filter to a before_action.

I also checked Mackenzie’s github repository to see what his code looked like for this project. Sure enough, his has been changed to a before_action instead of a before_filter.

Moving on. Links are still showing even if we aren’t signed in. Let’s change that.

(video link)

Go to app/views/links/index.html.erb. We are going to wrap the ‘Edit’ path in an if block so that a user cannot see the edit path IF they are not signed in.

That block of code will look like this:

Whole page before:

Whole page after:

Alright! Let’s start out server and test out our change:

Got to: http://localhost:3000/ and sign out. Refresh the page.

Image for post
Image for post

Hmmm. It looks like this worked for the third link, but not for the first two. Do you know why?

We told our app to show the Edit and Destroy buttons only if the link.user == current user. But, wecreated the first two links before we added a user column to the database. So, the code we wrote won’t work for those first two links.

Let’s sign in and create a new link just to test out our theory:

Image for post
Image for post

Yay. You can see that we cannot edit or destroy those first two links because we did not create them (technically, no one did, according to the database). We DID create the third link, however, and we are allowed to destroy it.

Let’s get into the console and confirm our theory.

then:

then:

See! You see the user_id for both of these links is set to “nil”.

We can update the database to show that the first user did indeed create these links.

First:

then

then

then

then

then

Ok, restart your server and refresh your page.

Huzzah!

Image for post
Image for post

Next, we will make sure you are signed in before you can submit a new link. Right now, you can submit a new link even if you are signed out. See?

Image for post
Image for post

(video link)

Under: app/views/links/index.html.erb just simply delete the following at the bottom of the page:

Now it’s time for a git commit!

Lovely. Now it’s time to add bootstrap and start styling a bit.

(video link)

Find the bootstrap gem on Google. I found it here. Copy the gem and add to your Gemfile:

Save. Run a bundle install:

Bundle complete! Still some work to do before we can use bootstrap. Head over to the bootstrap sass github page and find the installation directions.

First thing we’ll do here is rename the app/assets/stylesheets/application.css page to app/assets/stylesheets/application.css.scss.

Image for post
Image for post

Import this into your new .css.scss page:

We also need to “//= require bootstrap-sprockets” inside our app/assets/javascripts/application.js page:

Save. Next, delete the scaffold.scss file. It will override your bootstrap stylings and we don’t want that.

Next, let’s head over to app/views/layouts/application.html.erb and start adding some stylings:

(video link)

I hope you don’t mind that we’re just copy/pasting Mackenzie’s stylings. This tutorial is mainly geared towards learning Ruby on Rails, not CSS. So we’re going to cut some corners here. I’m going to head to Mackenzie’s github page for this project, find the application.html.erb layout page, and copy / paste the code.

Before:

After:

Then

And let’s see what we get at http://localhost:3000/

Image for post
Image for post

Nice. Stealing like an artist. Ok, moving on.

Now let’s add some styling to the application.css.scss file. Find the file on the github repo for this project, and copy / paste the content into your own application.css.scss file:

Before:

After:

Refresh your localhost page annddddd:

Image for post
Image for post

Progress. Next, we’ll attack the index.html.erb file.

(video link)

We are going to delete EVERYTHING. And add in the following:

Please forgive me for glossing over this stuff and not explaining the “how” and “why” behind this stuff. I’m learning as I go and my approach (for now) is to repeat, repeat, repeat, repeat, repeat, repeat.

That being said, avoid copy / pasting and write this stuff out yourself. Try to translate the code, and predict what it will do as you write.

Save your code. Refresh your page. Walah!

Image for post
Image for post

Next, let’s tackle the show.html.erb page. Delete everything in there and write:

Click on one of your links and check out your new stylings:

Image for post
Image for post

Cool. Now let’s tackle the style of the forms

(video link)

Before:

After:

Guess what this update does.

Refresh your page, and….

Image for post
Image for post

Next, we are going to update the look of the account page. Navigate to app/views/devise/registrations/edit.html.erb

(video link)

Before:

After:

Looking good!

Image for post
Image for post

Then, navigate to app/views/devise/registrations/new.html.erb and pull the same stunt.

Before:

After:

SAVE!

To update the sign-in page, we need to navigate to app/views/devise/sessions/new.html.erb and update the code:

Before:

After:

If you are using Chrome, use the incognito mode to check out your new Sign in page. Otherwise, sign out and then sign back in to see your changes in action.

Ok, time for a commit! Kill the server, and:

Wonderful. Now we are going to tackle the voting function. FUN!

(video link)

Search for the github page for this gem. I’ve conveniently located it for you here.

We’ll add the following to our gemfile and then run a bundle install.

then

Cool. Now we just need to follow the installation instructions on the github page. Let’s create a table to store the votes in:

then

Next, we need to add a line to our app/models/link.rb file:

Before:

After:

Now let’s jump into the rails console to add our first link like and make sure this is all working:

Then

then

then

then

then

Your output should look something like this:

Image for post
Image for post

Great. It’s working.

Now we need to get this data inside of our views so that we can see the votes in our HTML!

(video link)

First, we’ll go into our routes file and add some routes.

Before:

After:

Then, inside of our links controller (app/controllers/links_controllers.rb), we need to create an upvote and downvote method.

First the upvote method:

Then the downvote method:

NOTE: Mackenzie wrote his app three years ago, so some of the code is no out-of-date. We need to use “redirect_back fallback_location: root_path” instead of “redirect_to :back” as specified in the video.

Save. Now we will add the ability to upvote or downvote inside of our views.

Before:

After:

Make sure all of your files have been saved before you refresh and test your code.

Refresh and test!

Image for post
Image for post

Niiiiiiiiiiiice. Go ahead and give those links some votes to make sure everything is working correctly.

Niiiiiice. Now, we are going to add the votes to the show page as well.

In app/views/links/show.html.erb, we will add some code.

Before:

After:

Great. Save. Refresh. Test.

Image for post
Image for post

Niiiiiice. Let’s git it on! Lol.

ONE MORE FEATURE! Let’s add the ability to comment on a link.

(video link)

I imagine there is a gem out there that does this, but we’re going to scaffold this ourselves instead.

Image for post
Image for post

Niiice. Ok, next:

And refresh your server to make sure everything is running ok.

It’s not. I jumped the gun and pulled the trigger before the tutorial had typed out everything. BUT IT’S OK. We can fix this.

Go into app/assets/stylesheets/scaffolds.scss and delete all the code. Save. Refresh. And walah! Back to normal.

For the comment function, we are going to use a gem called “simple form”. I’ve placed the link right →here← for your convenience.

By now you’re a gem pro. We just need to copy paste this into our gemfile:

Save, bundle install.

Then head over to our models and update the comment.rb file to:

Also, we need to update the link.rb file to:

Save those files.

Next, we will add a resource to our routes.rb file.

Before:

After:

Now we need to update the create method in our comments controller.

(video link)

The whole comments_controller.rb file will look like this:

Next, we need to add a form to our show page.

(video link)

Under app/views/links/show.html.erb, at the bottom of the file, add:

Now we need to create the partial that we are rendering.

(video link)

We need to save a new file “_comment.html.erb” under app/views/comments.

For this file to work, we need to add a new gem. Ruby no longer recognizes the div_for command, but we can make it work if we add the following gem to our gemfile:

then

then

And refresh your page. http://localhost:3000/links/1

Haha! It worked. HUZZZZZZAAAAAAHHHHHH.

Now, let’s commit to git

Nice.

Ok, one last thing. We’re going to add a username so the it says “Submitted about 8 hours… oops… typo! Need to fix that. It should read 8 hours ago by davideallen7@gmail.com

Image for post
Image for post

We just need to go into the links/index.html.erb file and update the <h2> class heading to:

Back to the username.

then

then we’ll add an input into our form field to accept a username upon sign-up.

Head over to app/views/devise/registration/edit.html.erb, and add:

And then get into the application controller and update to:

Then update the <h2> code block in your index.html.erb file from:

to:

Check your work:

Image for post
Image for post

Sweet success.

Image for post
Image for post

Even sweeter success. Wonderful. Now we need to do the same thing to the show.html.erb page.

Update this:

To this:

And then we need to update the comment page, _comment.html.erb.

Update this:

To this:

And now we need to make sure that when a new user signs up, the form asks for the name. Just copy / paste this code into the new.html.erb file and save:

Finally, commit and push your changes! We’re almost done.

Wowza. That was something else, wasn’t it. We’re finished.

Hope you enjoyed the fun. Let me know if you have any questions!

Repository for this project is located here.

Written by

Documentation and tutorials on Python, Programming, and Data Analysis. FPL Addict. Occasionally writing about biohacking, PMing, and food.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store