diff --git a/.ruby-version b/.ruby-version
index bc4abe86..338a5b5d 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-2.3.8
+2.6.6
diff --git a/Gemfile b/Gemfile
index 7a0ed5e5..70ae8baa 100644
--- a/Gemfile
+++ b/Gemfile
@@ -18,15 +18,15 @@ gem 'sdoc', '~> 0.4.1', group: :doc
 
 gem 'bcrypt', '~> 3.1.7'
 
-gem 'haml'
-gem 'bootstrap-sass', '~> 3.2.0.1'
+gem 'haml', '~> 4.0'
+gem 'bootstrap-sass', '~> 3.4.0'
 gem 'bootswatch-rails'
 gem 'sweetalert-rails'
 gem 'will_paginate'
 gem 'will_paginate-bootstrap'
-gem 'devise'
+gem 'devise', '~> 4.0'
 gem 'devise-i18n'
-gem 'devise-async'
+gem 'devise-async', git: "https://github.com/mhfs/devise-async.git", ref: "devise-4.x" # TODO: bring this to 1.0 after rails5 upgrade
 gem 'bootstrap_form'
 gem 'font-kit-rails'
 gem 'nprogress-rails'
@@ -96,7 +96,7 @@ end
 
 group :development, :test do
   gem 'rake'
-  gem 'thin'
+  gem 'puma'
   gem 'rspec-rails', '~> 3.5'
   gem 'factory_girl_rails', require: false
   gem 'faker'
diff --git a/Gemfile.lock b/Gemfile.lock
index bd684a9e..75f11229 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,3 +1,11 @@
+GIT
+  remote: https://github.com/mhfs/devise-async.git
+  revision: 177f6363a002f7ff28f1d289c8cab7ad8d9cb8c5
+  ref: devise-4.x
+  specs:
+    devise-async (0.10.2)
+      devise (>= 4.0)
+
 GIT
   remote: https://github.com/retrospring/questiongenerator.git
   revision: c5f8362ff769425d42a94b3a611731eadaa5e0ca
@@ -48,15 +56,18 @@ GEM
     airbrussh (1.1.2)
       sshkit (>= 1.6.1, != 1.7.0)
     arel (6.0.4)
-    bcrypt (3.1.11)
+    autoprefixer-rails (9.5.0)
+      execjs
+    bcrypt (3.1.12)
     better_errors (2.1.1)
       coderay (>= 1.0.0)
       erubis (>= 2.6.6)
       rack (>= 0.9.0)
     binding_of_caller (0.7.2)
       debug_inspector (>= 0.0.1)
-    bootstrap-sass (3.2.0.2)
-      sass (~> 3.2)
+    bootstrap-sass (3.4.1)
+      autoprefixer-rails (>= 5.2.1)
+      sassc (>= 2.0.0)
     bootstrap3-datetimepicker-rails (4.7.14)
       momentjs-rails (>= 2.8.1)
     bootstrap_form (2.6.0)
@@ -99,22 +110,18 @@ GEM
     colorize (0.8.1)
     concurrent-ruby (1.0.5)
     connection_pool (2.2.1)
-    crass (1.0.2)
-    daemons (1.2.4)
+    crass (1.0.4)
     database_cleaner (1.5.3)
     debug_inspector (0.0.2)
     delayed_paperclip (3.0.1)
       activejob (>= 4.2)
       paperclip (>= 3.3)
-    devise (3.5.10)
+    devise (4.7.1)
       bcrypt (~> 3.0)
       orm_adapter (~> 0.1)
-      railties (>= 3.2.6, < 5)
+      railties (>= 4.1.0)
       responders
-      thread_safe (~> 0.1)
       warden (~> 1.2.3)
-    devise-async (0.10.2)
-      devise (>= 3.2, < 4.0)
     devise-i18n (1.1.2)
     diff-lcs (1.3)
     docile (1.1.5)
@@ -122,8 +129,7 @@ GEM
       unf (>= 0.0.5, < 1.0.0)
     equalizer (0.0.11)
     erubis (2.7.0)
-    eventmachine (1.2.3)
-    excon (0.55.0)
+    excon (0.73.0)
     execjs (2.7.0)
     factory_girl (4.8.0)
       activesupport (>= 3.0.0)
@@ -301,7 +307,7 @@ GEM
       guard (>= 2.0.0)
     haml (4.0.7)
       tilt
-    hashie (3.5.5)
+    hashie (4.1.0)
     hike (1.2.3)
     http (2.2.1)
       addressable (~> 2.3)
@@ -314,7 +320,8 @@ GEM
     http_parser.rb (0.6.0)
     httparty (0.14.0)
       multi_xml (>= 0.5.2)
-    i18n (0.8.1)
+    i18n (0.9.5)
+      concurrent-ruby (~> 1.0)
     i18n-js (3.0.0.rc10)
       i18n (~> 0.6)
     inflecto (0.0.2)
@@ -332,12 +339,21 @@ GEM
     jquery-turbolinks (2.1.0)
       railties (>= 3.1.0)
       turbolinks
-    jquery-ui-rails (5.0.5)
+    jquery-ui-rails (6.0.1)
       railties (>= 3.2.16)
     json (1.8.6)
-    kaminari (0.17.0)
-      actionpack (>= 3.0.0)
-      activesupport (>= 3.0.0)
+    kaminari (1.2.0)
+      activesupport (>= 4.1.0)
+      kaminari-actionview (= 1.2.0)
+      kaminari-activerecord (= 1.2.0)
+      kaminari-core (= 1.2.0)
+    kaminari-actionview (1.2.0)
+      actionview
+      kaminari-core (= 1.2.0)
+    kaminari-activerecord (1.2.0)
+      activerecord
+      kaminari-core (= 1.2.0)
+    kaminari-core (1.2.0)
     kgio (2.11.0)
     launchy (2.4.3)
       addressable (~> 2.3)
@@ -347,7 +363,7 @@ GEM
       rb-fsevent (~> 0.9, >= 0.9.4)
       rb-inotify (~> 0.9, >= 0.9.7)
       ruby_dep (~> 1.2)
-    loofah (2.2.3)
+    loofah (2.5.0)
       crass (~> 1.0.2)
       nokogiri (>= 1.5.9)
     lumberjack (1.0.11)
@@ -374,7 +390,8 @@ GEM
       net-ssh (>= 2.6.5)
     net-ssh (4.1.0)
     newrelic_rpm (4.2.0.334)
-    nokogiri (1.10.1)
+    nio4r (2.5.2)
+    nokogiri (1.10.9)
       mini_portile2 (~> 2.4.0)
     nokogumbo (2.0.1)
       nokogiri (~> 1.8, >= 1.8.4)
@@ -383,8 +400,8 @@ GEM
       shellany (~> 0.0)
     nprogress-rails (0.2.0.2)
     oauth (0.5.1)
-    omniauth (1.6.1)
-      hashie (>= 3.4.6, < 3.6.0)
+    omniauth (1.9.1)
+      hashie (>= 3.4.6)
       rack (>= 1.6.2, < 3)
     omniauth-oauth (1.1.0)
       oauth
@@ -414,8 +431,10 @@ GEM
       method_source (~> 0.8.1)
       slop (~> 3.4)
     public_suffix (2.0.5)
-    rack (1.6.11)
-    rack-pjax (1.0.0)
+    puma (4.3.3)
+      nio4r (~> 2.0)
+    rack (1.6.13)
+    rack-pjax (1.1.0)
       nokogiri (~> 1.5)
       rack (>= 1.1)
     rack-protection (1.5.5)
@@ -438,8 +457,8 @@ GEM
     rails-assets-jquery (2.2.4)
     rails-deprecated_sanitizer (1.0.3)
       activesupport (>= 4.2.0.alpha)
-    rails-dom-testing (1.0.8)
-      activesupport (>= 4.2.0.beta, < 5.0)
+    rails-dom-testing (1.0.9)
+      activesupport (>= 4.2.0, < 5.0)
       nokogiri (~> 1.6)
       rails-deprecated_sanitizer (>= 1.0.1)
     rails-html-sanitizer (1.0.4)
@@ -447,14 +466,14 @@ GEM
     rails-i18n (4.0.9)
       i18n (~> 0.7)
       railties (~> 4.0)
-    rails_admin (1.1.1)
+    rails_admin (1.4.3)
       builder (~> 3.1)
       coffee-rails (~> 4.0)
       font-awesome-rails (>= 3.0, < 5)
-      haml (~> 4.0)
+      haml (>= 4.0, < 6)
       jquery-rails (>= 3.0, < 5)
-      jquery-ui-rails (~> 5.0)
-      kaminari (~> 0.14)
+      jquery-ui-rails (>= 5.0, < 7)
+      kaminari (>= 0.14, < 2.0)
       nested_form (~> 0.3)
       rack-pjax (>= 0.7)
       rails (>= 4.0, < 6)
@@ -466,7 +485,7 @@ GEM
       rake (>= 0.8.7)
       thor (>= 0.18.1, < 2.0)
     raindrops (0.18.0)
-    rake (12.0.0)
+    rake (13.0.1)
     rb-fsevent (0.9.8)
     rb-inotify (0.9.8)
       ffi (>= 0.5.0)
@@ -478,7 +497,7 @@ GEM
     rdoc (4.3.0)
     redcarpet (3.4.0)
     redis (3.3.3)
-    remotipart (1.3.1)
+    remotipart (1.4.4)
     responders (2.4.1)
       actionpack (>= 4.2.0, < 6.0)
       railties (>= 4.2.0, < 6.0)
@@ -513,6 +532,9 @@ GEM
       sass (~> 3.2.2)
       sprockets (~> 2.8, < 3.0)
       sprockets-rails (~> 2.0)
+    sassc (2.0.1)
+      ffi (~> 1.9)
+      rake
     sdoc (0.4.2)
       json (~> 1.7, >= 1.7.7)
       rdoc (~> 4.0)
@@ -553,10 +575,6 @@ GEM
       net-ssh (>= 2.8.0)
     sweetalert-rails (1.1.3)
       railties (>= 3.1.0)
-    thin (1.7.0)
-      daemons (~> 1.0, >= 1.0.9)
-      eventmachine (~> 1.0, >= 1.0.4)
-      rack (>= 1, < 3)
     thor (0.19.4)
     thread_safe (0.3.6)
     tilt (1.4.1)
@@ -617,7 +635,7 @@ PLATFORMS
 DEPENDENCIES
   bcrypt (~> 3.1.7)
   better_errors
-  bootstrap-sass (~> 3.2.0.1)
+  bootstrap-sass (~> 3.4.0)
   bootstrap3-datetimepicker-rails (~> 4.7.14)
   bootstrap_form
   bootswatch-rails
@@ -630,8 +648,8 @@ DEPENDENCIES
   colorize
   database_cleaner
   delayed_paperclip
-  devise
-  devise-async
+  devise (~> 4.0)
+  devise-async!
   devise-i18n
   factory_girl_rails
   fake_email_validator
@@ -642,7 +660,7 @@ DEPENDENCIES
   font-kit-rails
   foreman
   guard-brakeman
-  haml
+  haml (~> 4.0)
   httparty
   i18n-js (= 3.0.0.rc10)
   jbuilder (~> 2.2.4)
@@ -660,6 +678,7 @@ DEPENDENCIES
   pg
   pghero
   poltergeist
+  puma
   questiongenerator!
   rails (~> 4.2.11, >= 4.2.11.1)
   rails-assets-growl
@@ -682,7 +701,6 @@ DEPENDENCIES
   sinatra
   spring (~> 1.3.5)
   sweetalert-rails
-  thin
   tiny-color-rails
   tumblr_client
   turbolinks (~> 2.5.3)
diff --git a/app/assets/javascripts/answerbox/comment/smile.coffee b/app/assets/javascripts/answerbox/comment/smile.coffee
index 6b25dfa6..a85da543 100644
--- a/app/assets/javascripts/answerbox/comment/smile.coffee
+++ b/app/assets/javascripts/answerbox/comment/smile.coffee
@@ -31,11 +31,13 @@ $(document).on "click", "button[name=ab-smile-comment]", ->
       showNotification translate('frontend.error.message'), false
     complete: (jqxhr, status) ->
       btn.button "reset"
-      if success
-        switch action
-          when 'smile'
-            btn[0].dataset.action = 'unsmile'
-            btn.html "<i class=\"fa fa-frown-o\"></i> <span id=\"ab-comment-smile-count-#{cid}\">#{count}</span>"
-          when 'unsmile'
-            btn[0].dataset.action = 'smile'
-            btn.html "<i class=\"fa fa-smile-o\"></i> <span id=\"ab-comment-smile-count-#{cid}\">#{count}</span>"
+      window.setTimeout ->
+        if success
+          switch action
+            when 'smile'
+              btn[0].dataset.action = 'unsmile'
+              btn.html "<i class=\"fa fa-frown-o\"></i> <span id=\"ab-comment-smile-count-#{cid}\">#{count}</span>"
+            when 'unsmile'
+              btn[0].dataset.action = 'smile'
+              btn.html "<i class=\"fa fa-smile-o\"></i> <span id=\"ab-comment-smile-count-#{cid}\">#{count}</span>"
+      , 20
diff --git a/app/assets/javascripts/answerbox/smile.coffee b/app/assets/javascripts/answerbox/smile.coffee
index ed26ec5f..8a9b9769 100644
--- a/app/assets/javascripts/answerbox/smile.coffee
+++ b/app/assets/javascripts/answerbox/smile.coffee
@@ -31,11 +31,13 @@ $(document).on "click", "button[name=ab-smile]", ->
       showNotification translate('frontend.error.message'), false
     complete: (jqxhr, status) ->
       btn.button "reset"
-      if success
-        switch action
-          when 'smile'
-            btn[0].dataset.action = 'unsmile'
-            btn.html "<i class=\"fa fa-frown-o\"></i> <span id=\"ab-smile-count-#{aid}\">#{count}</span>"
-          when 'unsmile'
-            btn[0].dataset.action = 'smile'
-            btn.html "<i class=\"fa fa-smile-o\"></i> <span id=\"ab-smile-count-#{aid}\">#{count}</span>"
+      window.setTimeout ->
+        if success
+          switch action
+            when 'smile'
+              btn[0].dataset.action = 'unsmile'
+              btn.html "<i class=\"fa fa-frown-o\"></i> <span id=\"ab-smile-count-#{aid}\">#{count}</span>"
+            when 'unsmile'
+              btn[0].dataset.action = 'smile'
+              btn.html "<i class=\"fa fa-smile-o\"></i> <span id=\"ab-smile-count-#{aid}\">#{count}</span>"
+      , 20
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 13d96e03..ef5ee974 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -55,8 +55,8 @@ class ApplicationController < ActionController::Base
   protected
 
   def configure_permitted_parameters
-    devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:screen_name, :email, :password, :password_confirmation, :remember_me) }
-    devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:login, :screen_name, :email, :password, :remember_me) }
-    devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:screen_name, :email, :password, :password_confirmation, :current_password) }
+    devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit(:screen_name, :email, :password, :password_confirmation, :remember_me) }
+    devise_parameter_sanitizer.permit(:sign_in) { |u| u.permit(:login, :screen_name, :email, :password, :remember_me) }
+    devise_parameter_sanitizer.permit(:account_update) { |u| u.permit(:screen_name, :email, :password, :password_confirmation, :current_password) }
   end
 end
diff --git a/app/controllers/discover_controller.rb b/app/controllers/discover_controller.rb
index 5d1490a5..daeb7536 100644
--- a/app/controllers/discover_controller.rb
+++ b/app/controllers/discover_controller.rb
@@ -2,6 +2,10 @@ class DiscoverController < ApplicationController
   before_filter :authenticate_user!
 
   def index
+    unless APP_CONFIG.dig(:features, :discover, :enabled) || current_user.mod?
+      return redirect_to root_path
+    end
+
     top_x = 10  # only display the top X items
 
     @popular_answers = Answer.where("created_at > ?", Time.now.ago(1.week)).order(:smile_count).reverse_order.limit(top_x)
diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml
index 0c07ee32..fc88d814 100644
--- a/app/views/layouts/_header.html.haml
+++ b/app/views/layouts/_header.html.haml
@@ -22,7 +22,7 @@
         %ul.nav.navbar-nav
           = nav_entry t('views.navigation.timeline'), root_path
           = nav_entry t('views.navigation.inbox'), "/inbox", badge: inbox_count
-          - if APP_CONFIG.dig(:features, :discover, :enabled)
+          - if APP_CONFIG.dig(:features, :discover, :enabled) || current_user.mod?
             = nav_entry t('views.navigation.discover'), discover_path
         %ul.nav.navbar-nav.navbar-right
           - unless @user.nil?
diff --git a/config/initializers/devise_async.rb b/config/initializers/devise_async.rb
index 5e432598..05a1852c 100644
--- a/config/initializers/devise_async.rb
+++ b/config/initializers/devise_async.rb
@@ -1 +1 @@
-Devise::Async.backend = :sidekiq
\ No newline at end of file
+Devise::Async.backend = :sidekiq
diff --git a/config/routes.rb b/config/routes.rb
index e266e01c..8176f058 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -104,7 +104,7 @@ Rails.application.routes.draw do
     match '/unsubscribe', to: 'subscription#unsubscribe', via: :post, as: :unsubscribe_answer
   end
 
-  match '/discover', to: 'discover#index', via: :get, as: :discover if APP_CONFIG.dig(:features, :discover, :enabled)
+  match '/discover', to: 'discover#index', via: :get, as: :discover
   match '/public', to: 'public#index', via: :get, as: :public_timeline if APP_CONFIG.dig(:features, :public, :enabled)
   match '/group/:group_name', to: 'group#index', via: :get, as: :group_timeline