https://thepracticaldev.s3.amazonaws.com/i/nxqfrbmepu3pwj7fmb1d.gif
Last week, I entered the first ever DEV Contest to build a Realtime App with Pusher. After a very busy day and about 4 hours of coding, I submitted an Instagram clone.
You can check out my entry below to see the live app and Github repo. It'll be nice to also get your ❤️ & 🦄 on my entry post.
In this post, I'll be taking you through how I built the Instagram clone app.
Setting up the application
I built the app using Ruby on Rails. I made use of Devise for user authentication and Carrierwave for image upload.
If you have Ruby and Rails installed and want to follow along, run the following command to generate a new Rails app.
$ rails new instaclone -T --database=postgresql
In your app's root directory, open your Gemfile and add the following and then run bundle install
in your terminal:
# Gemfile
gem 'bootstrap', '~> 4.1.0'
gem 'jquery-rails'
gem 'pusher'
gem 'figaro'
gem 'devise'
gem 'will_paginate', '~> 3.1.0'
gem 'carrierwave'
gem "fog-aws"
Database setup
To get our app up and running, we’ll create a database for it to work with. You can check out this article on how to create a Postgres database and an associated user and password.
Once you have your database details, in your database.yml
file, under the development key, add the following code:
# config/database.yml
...
development:
<<: *default
database: instaclone_development // add this line if it isn't already there
username: database_user // add this line
password: user_password // add this line
...
Ensure that the username and password entered in the code above has access to the instaclone_development
database. After that, run the following code to setup the database:
# setup database
$ rails db:setup
User authentication
With our database set up, we'll set up user authentication with Devise. Devise is a flexible authentication solution for Ruby on Rails. It helps you set up user authentication in seconds. In your terminal, run the following command:
$ rails generate devise:install
The above command will install Devise. At this point, a number of instructions will appear in the console, one of which involves adding some code to your application.html.erb
file. We’ll also add our Pusher script to the file.
Replace the code in your app/views/layouts/application.html.erb
file with the one here
Next, we’ll generate our authentication view pages, like and then user model using Devise. In your terminal, run the following command:
# generate Devise view pages
$ rails generate devise:views
# generate user model
$ rails generate devise user
# generate migration to add extra columns to the user model
$ rails generate migration add_username_to_users username:string:uniq
# generate a likes model
$ rails generate model like like_count:integer post:references
Now that we have generated our migration files, let's make some modifications to some files before running our migrations.
Update the code in your application controller, with the following:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :authenticate_user!
protected
def configure_permitted_parameters
added_attrs = [:username, :email, :password, :password_confirmation, :remember_me]
devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
devise_parameter_sanitizer.permit :account_update, keys: added_attrs
end
end
Also, update the code in your likes migration file with the following
# db/migrate/20180524215616_create_likes.rb
class CreateLikes < ActiveRecord::Migration[5.1]
def change
create_table :likes do |t|
t.integer :like_count, default: 0
t.references :post, foreign_key: true
t.timestamps
end
end
end
Now, we’re ready to run our migration and see our app. In your terminal, run the following:
# run database migrations
$ rails db:migrate
After running migrations, start the development server on your terminal by running rails s. Visit http://localhost:3000 in your browser to see your brand new application:
Pusher account setup
Now that our application is up and running, head over to Pusher and sign up for a free account.
After creating a Pusher account, create a new app by selecting Channels apps on the sidebar and clicking Create Channels app button on the bottom of the sidebar.
Configure your app by providing basic information requested in the form presented. You can also choose the environment you intend to integrate with Pusher, to be provided with some boilerplate setup code. After that, click the App Keys tab to retrieve your keys.
Styling the pages
To style our pages, we'll make use of Bootstrap. We have already added Bootstrap to our app while setting it up, so all we need to do is require it and add our markup and styles.
First we'll generate a controller for our posts; in your terminal, run the following command:
# generate a posts controller
$ rails g controller posts
Update the code in the following files with the code in each link provided below:
- Replace the code in
app/assets/javascripts/application.js
with the code here - Replace the code in
app/views/devise/registrations/new.html.erb
with the code here - Replace the code in
app/views/devise/sessions/new.html.erb
with the code here - Rename your
app/assets/stylesheets/application.css
file toapp/assets/stylesheets/application.scss
and replace the code there with the code here - Add the code here to your
app/controllers/posts_controller.rb
file. - Add the code here to your
config/routes.rb
file.
If we reload our app in the browser, we should be greeted with a lovely sight. Go ahead and create an account.
If you encounter any error related to application.html.erb, in config/boot.rb, change the ExecJS runtime from Duktape to Node.
# config/boot.rb
ENV['EXECJS_RUNTIME'] ='Node'
Realtime posts with Pusher
For users to see our posts realtime, whenever a user adds a post, we save it to the database and notify Pusher by broadcasting the new post and subscribing to it on the frontend of our app.
Let’s initialise our Pusher client. In the config/initializers
folder, create a pusher.rb
file and add the following code:
# config/initializers/pusher.rb
require 'pusher'
Pusher.app_id = ENV["PUSHER_APP_ID"]
Pusher.key = ENV["PUSHER_KEY"]
Pusher.secret = ENV["PUSHER_SECRET"]
Pusher.cluster = ENV["PUSHER_CLUSTER"]
Pusher.logger = Rails.logger
Pusher.encrypted = true
Since we don't want our Pusher keys to be visible to the public, we'll add save them as environmental variables. To do this, we'll make use of Figaro.
Run figaro install
in your terminal. It will generate an application.yml
file. In the application.yml
file add your Pusher keys:
# config/application.yml
PUSHER_APP_ID: '11234'
PUSHER_KEY: '1234567890'
PUSHER_SECRET: '1234556677'
PUSHER_CLUSTER: 'us'
With Pusher now initialised, lets notify Pusher whenever a new post is saved. Add the code below to your post model:
# app/models/post.rb
class Post < ApplicationRecord
belongs_to :user
has_many :likes
after_create :notify_pusher
mount_uploader :image, ImageUploader
validates :caption, presence: true
def serialised
{
id: self.id,
caption: self.caption,
user: self.user.username,
image: self.image_url,
likes: self.likes[0].like_count
}
end
def notify_pusher
Pusher.trigger('post', 'new', self.serialised)
end
end
In the code above, we have a notify_pusher
action that is called after a new post is created. In the notify_pusher
action, we notify pusher of the new post by triggering a new post event and passing in the new post.
Also, we have to notify Pusher whenever there's a new like for an image. Add the following code to the likes model
# app/models/like.rb
class Like < ApplicationRecord
after_save :notify_pusher, on: :create
belongs_to :post
def notify_pusher
Pusher.trigger('post', 'new-like', self.post.serialised)
end
end
As with the user model, we also notify Pusher of a new like by broadcasting a new-like
event.
For us to get the update realtime on the frontend of our app, we have to subscribe to the new post event we broadcasted on the server side. Lets rename our app/assets/javascripts/posts.coffee
file to app/assets/javascripts/posts.coffee.erb
and add the code here to the file.
In the code we added to the file above, we subscribe our Pusher client to the new
and new-like
events for posts and likes respectively. Whenever there's a new event, we update the page with the new post and likes.
Conclusion
There you have it, if you have followed this tutorial to this point, you should have your own fully functional Instagram clone.
Pusher is a very powerful software that can help you implement any realtime feature you can think of.
If you found this post useful, please add a ❤️ & 🦄 both here and in my entry post.
Top comments (1)
The tutorial is constantly driving my motivation . The overall tutorial is well-presented and great for beginners as well. Thanks for making this tutorial. if your looking for real world app. Your should check out some of full-fledge Instagram clone app templates in the market.