diff --git a/.rubocop.yml b/.rubocop.yml
index 15ba678d4d37ebee0e28b932cad2377888aa8411..b973f01cda4499d41dd38a85411a53ffbd732e7e 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -18,9 +18,29 @@ Metrics/MethodLength:
   CountComments: false
   Max: 10
 
-Metrics/ModuleLength:
+Metrics/AbcSize:
   Max: 100
 
+Metrics/BlockNesting:
+  Max: 3
+
+Metrics/ClassLength:
+  CountComments: false
+  Max: 200
+
+Metrics/CyclomaticComplexity:
+  Max: 15
+
+Metrics/MethodLength:
+  Max: 55
+
+Metrics/ModuleLength:
+  CountComments: false
+  Max: 200
+
+Metrics/PerceivedComplexity:
+  Max: 10
+
 Metrics/ParameterLists:
   Max: 4
   CountKeywordArgs: true
@@ -37,10 +57,10 @@ Style/Documentation:
   Enabled: false
 
 Style/DoubleNegation:
-  Enabled: false
+  Enabled: true
 
 Style/FrozenStringLiteralComment:
-  Enabled: false
+  Enabled: true
 
 Style/SpaceInsideHashLiteralBraces:
   EnforcedStyle: space
@@ -51,10 +71,18 @@ Style/TrailingCommaInLiteral:
 Style/RegexpLiteral:
   Enabled: false
 
+Style/Lambda:
+  Enabled: false
+
+Rails/HasAndBelongsToMany:
+  Enabled: false
+
 AllCops:
-  TargetRubyVersion: 2.2
+  TargetRubyVersion: 2.3
   Exclude:
   - 'spec/**/*'
   - 'db/**/*'
   - 'app/views/**/*'
   - 'config/**/*'
+  - 'bin/*'
+  - 'Rakefile'
diff --git a/Gemfile b/Gemfile
index 37c7459c86318a803487e0a836f9f8aeb972e70c..d6ef64cf7d10c302e38d978f1b304a0ed5851126 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 source 'https://rubygems.org'
 
 gem 'rails', '5.0.0.1'
diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb
index 28bf0d9d32372c8f4007513ed1d9010c5277189f..69e06921236ae086f1d9142e796aec9dc73ad267 100644
--- a/app/channels/application_cable/channel.rb
+++ b/app/channels/application_cable/channel.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module ApplicationCable
   class Channel < ActionCable::Channel::Base
     protected
diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb
index b94063b105a9809efa96022ff58ecf26c68a8bcf..33f9aa429765136ca1adb6714f96adf7460ce99b 100644
--- a/app/channels/application_cable/connection.rb
+++ b/app/channels/application_cable/connection.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module ApplicationCable
   class Connection < ActionCable::Connection::Base
     identified_by :current_user
diff --git a/app/channels/hashtag_channel.rb b/app/channels/hashtag_channel.rb
index 5be8d94cd327aaf84efe2d3062d831a20cff536e..4470a0e990bb1692c250ec478b3c9c363b4bdc87 100644
--- a/app/channels/hashtag_channel.rb
+++ b/app/channels/hashtag_channel.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class HashtagChannel < ApplicationCable::Channel
   def subscribed
     tag = params[:tag].downcase
diff --git a/app/channels/public_channel.rb b/app/channels/public_channel.rb
index 41e21611d7b4652856c4976c33ab204c64cf1205..9ef9e5dd733753ccbda5041fd33b502a690d3631 100644
--- a/app/channels/public_channel.rb
+++ b/app/channels/public_channel.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class PublicChannel < ApplicationCable::Channel
   def subscribed
     stream_from 'timeline:public', lambda { |encoded_message|
diff --git a/app/channels/timeline_channel.rb b/app/channels/timeline_channel.rb
index f2a9636fd71e8d87b3b0d4f8329cdf87f4083005..7b8d63ef59a4682f3712e0fbbb65836d21dbee60 100644
--- a/app/channels/timeline_channel.rb
+++ b/app/channels/timeline_channel.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class TimelineChannel < ApplicationCable::Channel
   def subscribed
     stream_from "timeline:#{current_user.account_id}"
diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb
index 4e423e91f2ae6118692914bb488d733f36bced9e..56ad6365d297dfccce694cbd747482844980ca75 100644
--- a/app/controllers/about_controller.rb
+++ b/app/controllers/about_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class AboutController < ApplicationController
   before_action :set_body_classes
 
diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index b169388451822fb741ef5366c7e3250b52cba6a1..5d2f4eee0fba3ff7357e31f7231cae48554e1a94 100644
--- a/app/controllers/accounts_controller.rb
+++ b/app/controllers/accounts_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class AccountsController < ApplicationController
   layout 'public'
 
@@ -41,10 +43,7 @@ class AccountsController < ApplicationController
   end
 
   def set_link_headers
-    response.headers['Link'] = LinkHeader.new([
-      [webfinger_account_url, [['rel', 'lrdd'], ['type', 'application/xrd+xml']]],
-      [account_url(@account, format: 'atom'), [['rel', 'alternate'], ['type', 'application/atom+xml']]]
-    ])
+    response.headers['Link'] = LinkHeader.new([[webfinger_account_url, [%w(rel lrdd), %w(type application/xrd+xml)]], [account_url(@account, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]]])
   end
 
   def webfinger_account_url
diff --git a/app/controllers/api/salmon_controller.rb b/app/controllers/api/salmon_controller.rb
index c0ba32ff29488d1cc65a3618de79ae8c78ce6748..01862a9000134b214d9bd8f1cf75fecbfe95a987 100644
--- a/app/controllers/api/salmon_controller.rb
+++ b/app/controllers/api/salmon_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Api::SalmonController < ApiController
   before_action :set_account
   respond_to :txt
diff --git a/app/controllers/api/subscriptions_controller.rb b/app/controllers/api/subscriptions_controller.rb
index 058ae8f5eef759bf8726bd36601008e1475989ae..51c4764362ec38ca317d15b250405e83e7b35ad8 100644
--- a/app/controllers/api/subscriptions_controller.rb
+++ b/app/controllers/api/subscriptions_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Api::SubscriptionsController < ApiController
   before_action :set_account
   respond_to :txt
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index 88af41bf88c84c6487a18c2250ec8774fd354b34..2dfab08319dcab4777fe1da9dc21e7bd71c535cf 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Api::V1::AccountsController < ApiController
   before_action -> { doorkeeper_authorize! :read }, except: [:follow, :unfollow, :block, :unblock]
   before_action -> { doorkeeper_authorize! :follow }, only: [:follow, :unfollow, :block, :unblock]
@@ -20,7 +22,7 @@ class Api::V1::AccountsController < ApiController
     @accounts = results.map { |f| accounts[f.target_account_id] }
 
     next_path = following_api_v1_account_url(max_id: results.last.id)    if results.size == DEFAULT_ACCOUNTS_LIMIT
-    prev_path = following_api_v1_account_url(since_id: results.first.id) if results.size > 0
+    prev_path = following_api_v1_account_url(since_id: results.first.id) unless results.empty?
 
     set_pagination_headers(next_path, prev_path)
 
@@ -33,7 +35,7 @@ class Api::V1::AccountsController < ApiController
     @accounts = results.map { |f| accounts[f.account_id] }
 
     next_path = followers_api_v1_account_url(max_id: results.last.id)    if results.size == DEFAULT_ACCOUNTS_LIMIT
-    prev_path = followers_api_v1_account_url(since_id: results.first.id) if results.size > 0
+    prev_path = followers_api_v1_account_url(since_id: results.first.id) unless results.empty?
 
     set_pagination_headers(next_path, prev_path)
 
@@ -56,7 +58,7 @@ class Api::V1::AccountsController < ApiController
     set_maps(@statuses)
 
     next_path = statuses_api_v1_account_url(max_id: @statuses.last.id)    if @statuses.size == DEFAULT_STATUSES_LIMIT
-    prev_path = statuses_api_v1_account_url(since_id: @statuses.first.id) if @statuses.size > 0
+    prev_path = statuses_api_v1_account_url(since_id: @statuses.first.id) unless @statuses.empty?
 
     set_pagination_headers(next_path, prev_path)
   end
diff --git a/app/controllers/api/v1/apps_controller.rb b/app/controllers/api/v1/apps_controller.rb
index a09c29cc6faf570cbafcc0c198951ed8866cc54f..d1db16cf2ae1771ed420b8039ea3e015f8b9e125 100644
--- a/app/controllers/api/v1/apps_controller.rb
+++ b/app/controllers/api/v1/apps_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Api::V1::AppsController < ApiController
   respond_to :json
 
diff --git a/app/controllers/api/v1/follows_controller.rb b/app/controllers/api/v1/follows_controller.rb
index 6a77c4d66b7d5ad03f3f3d2b5b6cdb34bc907361..c22dacbaab794ce78f32dc44488fa9d0e8415be0 100644
--- a/app/controllers/api/v1/follows_controller.rb
+++ b/app/controllers/api/v1/follows_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Api::V1::FollowsController < ApiController
   before_action -> { doorkeeper_authorize! :follow }
   before_action :require_user!
diff --git a/app/controllers/api/v1/media_controller.rb b/app/controllers/api/v1/media_controller.rb
index 6b93e47b47d9155b0e914a220c7539a3f174b268..bb8e8d9eedcb2f66db8c32839659d4f66b43015e 100644
--- a/app/controllers/api/v1/media_controller.rb
+++ b/app/controllers/api/v1/media_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Api::V1::MediaController < ApiController
   before_action -> { doorkeeper_authorize! :write }
   before_action :require_user!
diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb
index f5dbbd013248ec4c715f12e0b135f025b31c7cf4..e1a417129f7d2a76fe4e1ef735d45618f27b73f4 100644
--- a/app/controllers/api/v1/statuses_controller.rb
+++ b/app/controllers/api/v1/statuses_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Api::V1::StatusesController < ApiController
   before_action -> { doorkeeper_authorize! :read }, except: [:create, :destroy, :reblog, :unreblog, :favourite, :unfavourite]
   before_action -> { doorkeeper_authorize! :write }, only:  [:create, :destroy, :reblog, :unreblog, :favourite, :unfavourite]
@@ -10,7 +12,7 @@ class Api::V1::StatusesController < ApiController
   end
 
   def context
-    @context = OpenStruct.new({ ancestors: @status.ancestors, descendants: @status.descendants })
+    @context = OpenStruct.new(ancestors: @status.ancestors, descendants: @status.descendants)
     set_maps([@status] + @context[:ancestors] + @context[:descendants])
   end
 
@@ -20,7 +22,7 @@ class Api::V1::StatusesController < ApiController
     @accounts = results.map { |r| accounts[r.account_id] }
 
     next_path = reblogged_by_api_v1_status_url(max_id: results.last.id)    if results.size == DEFAULT_ACCOUNTS_LIMIT
-    prev_path = reblogged_by_api_v1_status_url(since_id: results.first.id) if results.size > 0
+    prev_path = reblogged_by_api_v1_status_url(since_id: results.first.id) unless results.empty?
 
     set_pagination_headers(next_path, prev_path)
 
@@ -33,7 +35,7 @@ class Api::V1::StatusesController < ApiController
     @accounts = results.map { |f| accounts[f.account_id] }
 
     next_path = favourited_by_api_v1_status_url(max_id: results.last.id)    if results.size == DEFAULT_ACCOUNTS_LIMIT
-    prev_path = favourited_by_api_v1_status_url(since_id: results.first.id) if results.size > 0
+    prev_path = favourited_by_api_v1_status_url(since_id: results.first.id) unless results.empty?
 
     set_pagination_headers(next_path, prev_path)
 
diff --git a/app/controllers/api/v1/timelines_controller.rb b/app/controllers/api/v1/timelines_controller.rb
index 6d7858c7618e41b3cc66527eaab5364e81f24ece..19b76f11d43d9a86feab0c65fc68ea66789eab30 100644
--- a/app/controllers/api/v1/timelines_controller.rb
+++ b/app/controllers/api/v1/timelines_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Api::V1::TimelinesController < ApiController
   before_action -> { doorkeeper_authorize! :read }
   before_action :require_user!, only: [:home, :mentions]
@@ -10,7 +12,7 @@ class Api::V1::TimelinesController < ApiController
     set_maps(@statuses)
 
     next_path = api_v1_home_timeline_url(max_id: @statuses.last.id)    if @statuses.size == DEFAULT_STATUSES_LIMIT
-    prev_path = api_v1_home_timeline_url(since_id: @statuses.first.id) if @statuses.size > 0
+    prev_path = api_v1_home_timeline_url(since_id: @statuses.first.id) unless @statuses.empty?
 
     set_pagination_headers(next_path, prev_path)
 
@@ -23,7 +25,7 @@ class Api::V1::TimelinesController < ApiController
     set_maps(@statuses)
 
     next_path = api_v1_mentions_timeline_url(max_id: @statuses.last.id)    if @statuses.size == DEFAULT_STATUSES_LIMIT
-    prev_path = api_v1_mentions_timeline_url(since_id: @statuses.first.id) if @statuses.size > 0
+    prev_path = api_v1_mentions_timeline_url(since_id: @statuses.first.id) unless @statuses.empty?
 
     set_pagination_headers(next_path, prev_path)
 
@@ -36,7 +38,7 @@ class Api::V1::TimelinesController < ApiController
     set_maps(@statuses)
 
     next_path = api_v1_public_timeline_url(max_id: @statuses.last.id)    if @statuses.size == DEFAULT_STATUSES_LIMIT
-    prev_path = api_v1_public_timeline_url(since_id: @statuses.first.id) if @statuses.size > 0
+    prev_path = api_v1_public_timeline_url(since_id: @statuses.first.id) unless @statuses.empty?
 
     set_pagination_headers(next_path, prev_path)
 
@@ -50,7 +52,7 @@ class Api::V1::TimelinesController < ApiController
     set_maps(@statuses)
 
     next_path = api_v1_hashtag_timeline_url(params[:id], max_id: @statuses.last.id)    if @statuses.size == DEFAULT_STATUSES_LIMIT
-    prev_path = api_v1_hashtag_timeline_url(params[:id], since_id: @statuses.first.id) if @statuses.size > 0
+    prev_path = api_v1_hashtag_timeline_url(params[:id], since_id: @statuses.first.id) unless @statuses.empty?
 
     set_pagination_headers(next_path, prev_path)
 
diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb
index ef453799b373d324bb0e24cbd869f4ae73f68511..aafaf843cbdf077af5ccc737468b0f66150b7943 100644
--- a/app/controllers/api_controller.rb
+++ b/app/controllers/api_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class ApiController < ApplicationController
   DEFAULT_STATUSES_LIMIT = 20
   DEFAULT_ACCOUNTS_LIMIT = 40
@@ -51,8 +53,8 @@ class ApiController < ApplicationController
 
   def set_pagination_headers(next_path = nil, prev_path = nil)
     links = []
-    links << [next_path, [['rel', 'next']]] if next_path
-    links << [prev_path, [['rel', 'prev']]] if prev_path
+    links << [next_path, [%w(rel next)]] if next_path
+    links << [prev_path, [%w(rel prev)]] if prev_path
     response.headers['Link'] = LinkHeader.new(links)
   end
 
@@ -76,7 +78,7 @@ class ApiController < ApplicationController
     render json: {}, status: 200
   end
 
-  def set_maps(statuses)
+  def set_maps(statuses) # rubocop:disable Style/AccessorMethodName
     if current_account.nil?
       @reblogs_map    = {}
       @favourites_map = {}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index e009fb8798fbe2c7bfe50ef200a4f750a4a9da6e..c7a99b22f00f9725766658ff0528e9bb4be3a95a 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class ApplicationController < ActionController::Base
   # Prevent CSRF attacks by raising an exception.
   # For APIs, you may want to use :null_session instead.
diff --git a/app/controllers/auth/confirmations_controller.rb b/app/controllers/auth/confirmations_controller.rb
index b8e9316f10e0f52be5cc0cac2263962d64c28ef1..2fdb281f40e87be38aeeac5e4118b88a24873a0c 100644
--- a/app/controllers/auth/confirmations_controller.rb
+++ b/app/controllers/auth/confirmations_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Auth::ConfirmationsController < Devise::ConfirmationsController
   layout 'auth'
 end
diff --git a/app/controllers/auth/passwords_controller.rb b/app/controllers/auth/passwords_controller.rb
index a2fb7bb134106b52765fbe388e1e69253f7c8752..54ee1c39c0051ae6a36c8df3204939a656499a0c 100644
--- a/app/controllers/auth/passwords_controller.rb
+++ b/app/controllers/auth/passwords_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Auth::PasswordsController < Devise::PasswordsController
   layout 'auth'
 end
diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb
index 7b7f6b52dfc99c5369fd61ceb4c423a6096d0696..f06a1dce19b3e1b6fdf5f1ad478423fec95856e4 100644
--- a/app/controllers/auth/registrations_controller.rb
+++ b/app/controllers/auth/registrations_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Auth::RegistrationsController < Devise::RegistrationsController
   layout 'auth'
 
diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb
index bd41ffd3d8f2c4c23025826ecce348623ab11ea7..c8350f9a1e758deb36bb6bc7f2fae14d959176a5 100644
--- a/app/controllers/auth/sessions_controller.rb
+++ b/app/controllers/auth/sessions_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Auth::SessionsController < Devise::SessionsController
   include Devise::Controllers::Rememberable
 
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index 8ed88d0745a6b0f7463d0cd249fb4ce584c97b16..9710aa84f8e84b00842f719b4e0dc7bdc5e6b0ba 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class HomeController < ApplicationController
   before_action :authenticate_user!
 
diff --git a/app/controllers/media_controller.rb b/app/controllers/media_controller.rb
index edfcdae5309efa7a32175e4e25ff493425751536..9832a91b42ca5c772889d2073fafddb093021731 100644
--- a/app/controllers/media_controller.rb
+++ b/app/controllers/media_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class MediaController < ApplicationController
   before_action :set_media_attachment
 
diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb
index e2d154597b8da3809487a5009cf9f65f93185f38..feaad04f6b6543a63702b5dbc56b4cb868f4707d 100644
--- a/app/controllers/oauth/authorizations_controller.rb
+++ b/app/controllers/oauth/authorizations_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
   skip_before_action :authenticate_resource_owner!
 
diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb
index 8a038f2fe46adabd1f0febb7b73f3f932d117078..7acef5e255ac44a899dc76c7515195d2437ded31 100644
--- a/app/controllers/settings/preferences_controller.rb
+++ b/app/controllers/settings/preferences_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Settings::PreferencesController < ApplicationController
   layout 'auth'
 
diff --git a/app/controllers/settings/profiles_controller.rb b/app/controllers/settings/profiles_controller.rb
index 52b6369a6d7762deadf9723be5d4416f8e943590..bd4fa2c46deb6cf4a09fbe92e826c20aaef70096 100644
--- a/app/controllers/settings/profiles_controller.rb
+++ b/app/controllers/settings/profiles_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Settings::ProfilesController < ApplicationController
   layout 'auth'
 
diff --git a/app/controllers/stream_entries_controller.rb b/app/controllers/stream_entries_controller.rb
index a364fa01c4f96c7227aa7e1dba1feceb31817e9f..caab1237d17c8def9d2a1414915798fa4a86ea15 100644
--- a/app/controllers/stream_entries_controller.rb
+++ b/app/controllers/stream_entries_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class StreamEntriesController < ApplicationController
   layout 'public'
 
@@ -29,9 +31,7 @@ class StreamEntriesController < ApplicationController
   end
 
   def set_link_headers
-    response.headers['Link'] = LinkHeader.new([
-      [account_stream_entry_url(@account, @stream_entry, format: 'atom'), [['rel', 'alternate'], ['type', 'application/atom+xml']]]
-    ])
+    response.headers['Link'] = LinkHeader.new([[account_stream_entry_url(@account, @stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]]])
   end
 
   def set_stream_entry
diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb
index ca5ee2f8343bfdfb420d4d310dff43a5fe4f53a8..a6b359485257978a2ef021d1c093ddedfe6a53dd 100644
--- a/app/controllers/tags_controller.rb
+++ b/app/controllers/tags_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class TagsController < ApplicationController
   layout 'public'
 
diff --git a/app/controllers/xrd_controller.rb b/app/controllers/xrd_controller.rb
index 003ffc18207a36457633da2d3d1289a92a68a2cc..9e0277860775734266cd7601560c837e16f4d0ff 100644
--- a/app/controllers/xrd_controller.rb
+++ b/app/controllers/xrd_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class XrdController < ApplicationController
   before_action :set_default_format_json, only: :webfinger
   before_action :set_default_format_xml, only: :host_meta
@@ -26,11 +28,11 @@ class XrdController < ApplicationController
   private
 
   def set_default_format_xml
-    request.format = 'xml' if request.headers["HTTP_ACCEPT"].nil? && params[:format].nil?
+    request.format = 'xml' if request.headers['HTTP_ACCEPT'].nil? && params[:format].nil?
   end
 
   def set_default_format_json
-    request.format = 'json' if request.headers["HTTP_ACCEPT"].nil? && params[:format].nil?
+    request.format = 'json' if request.headers['HTTP_ACCEPT'].nil? && params[:format].nil?
   end
 
   def username_from_resource
@@ -44,14 +46,14 @@ class XrdController < ApplicationController
 
   def pem_to_magic_key(public_key)
     modulus, exponent = [public_key.n, public_key.e].map do |component|
-      result = ''
+      result = []
 
       until component.zero?
         result << [component % 256].pack('C')
         component >>= 8
       end
 
-      result.reverse!
+      result.reverse.join
     end
 
     (['RSA'] + [modulus, exponent].map { |n| Base64.urlsafe_encode64(n) }).join('.')
diff --git a/app/helpers/about_helper.rb b/app/helpers/about_helper.rb
index 68e69aee147ab5e1e002da1791f688e7e2953236..0f57a7b5e3fa3c4c95f7be374daac3f86271e46e 100644
--- a/app/helpers/about_helper.rb
+++ b/app/helpers/about_helper.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
 module AboutHelper
 end
diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb
index 23eec6c6742410bd9899567575e1c48c28e22813..17c7b4b825abfd716761bf63770200b2fb140507 100644
--- a/app/helpers/accounts_helper.rb
+++ b/app/helpers/accounts_helper.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
 module AccountsHelper
   def pagination_options
     {
-      previous_label: "#{fa_icon('chevron-left')} Prev".html_safe,
-      next_label: "Next #{fa_icon('chevron-right')}".html_safe,
+      previous_label: safe_join([fa_icon('chevron-left'), 'Prev'], ' '),
+      next_label: safe_join(['Next', fa_icon('chevron-right')], ' '),
       inner_window: 1,
-      outer_window: 0
+      outer_window: 0,
     }
   end
 end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 5ed8499aadbc50421acb37a3d6f43f9416e86432..be82ff2fe38a62f88aecf2afefcfc2657c884b8a 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module ApplicationHelper
   def active_nav_class(path)
     current_page?(path) ? 'active' : ''
diff --git a/app/helpers/atom_builder_helper.rb b/app/helpers/atom_builder_helper.rb
index 2eed2da65d65584ff497f79e5ebaabfb8b479d6d..52190adaed77d2ae0799835fe7372ffdc922a238 100644
--- a/app/helpers/atom_builder_helper.rb
+++ b/app/helpers/atom_builder_helper.rb
@@ -1,6 +1,12 @@
+# frozen_string_literal: true
+
 module AtomBuilderHelper
   def stream_updated_at
-    @account.stream_entries.last ? (@account.updated_at > @account.stream_entries.last.created_at ? @account.updated_at : @account.stream_entries.last.created_at) : @account.updated_at
+    if @account.stream_entries.last
+      (@account.updated_at > @account.stream_entries.last.created_at ? @account.updated_at : @account.stream_entries.last.created_at)
+    else
+      @account.updated_at
+    end
   end
 
   def entry(xml, is_root = false, &block)
@@ -98,7 +104,7 @@ module AtomBuilderHelper
   end
 
   def in_reply_to(xml, uri, url)
-    xml['thr'].send('in-reply-to', { ref: uri, href: url, type: 'text/html' })
+    xml['thr'].send('in-reply-to', ref: uri, href: url, type: 'text/html')
   end
 
   def link_mention(xml, account)
diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb
index 86cce4c018d0061c848dcdb7bf6ea638d2f4f2f6..66d7ea9aff5f03c6b9d30f3187ccc3f1142a0fda 100644
--- a/app/helpers/home_helper.rb
+++ b/app/helpers/home_helper.rb
@@ -1,8 +1,10 @@
+# frozen_string_literal: true
+
 module HomeHelper
   def default_props
     {
       token: @token,
-      account: render(file: 'api/v1/accounts/show', locals: { account: current_user.account }, formats: :json)
+      account: render(file: 'api/v1/accounts/show', locals: { account: current_user.account }, formats: :json),
     }
   end
 end
diff --git a/app/helpers/routing_helper.rb b/app/helpers/routing_helper.rb
index 0512a4e0ac88e94a318c888fa61f3bb4cb11fef4..9ae29ec9168ff71206deb497bc1b9998faadf0ed 100644
--- a/app/helpers/routing_helper.rb
+++ b/app/helpers/routing_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module RoutingHelper
   extend ActiveSupport::Concern
   include Rails.application.routes.url_helpers
diff --git a/app/helpers/stream_entries_helper.rb b/app/helpers/stream_entries_helper.rb
index e994155b634ffa7ac5bc08e789d7fb5a8f8cb16e..2ba50edc3f3886c34fe0dc9f27b12c5fd6aec8dd 100644
--- a/app/helpers/stream_entries_helper.rb
+++ b/app/helpers/stream_entries_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module StreamEntriesHelper
   def display_name(account)
     account.display_name.blank? ? account.username : account.display_name
diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb
index 23450bc5c56db13c2b142827940a82e27a743a91..5b2b3ca596684c48ed9ca7181a0290f151e458b7 100644
--- a/app/helpers/tags_helper.rb
+++ b/app/helpers/tags_helper.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
 module TagsHelper
 end
diff --git a/app/helpers/xrd_helper.rb b/app/helpers/xrd_helper.rb
index 6b273e1226aaac9aaee6f0f1665dbc715913c515..2281a0278581493703c5c5f0b4aae9f8766205a3 100644
--- a/app/helpers/xrd_helper.rb
+++ b/app/helpers/xrd_helper.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
 module XrdHelper
 end
diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index 8cf465da835776644578a2aa3a178f99a59639b1..b808d7a0f487b9367748f14ccef44fe486d1f4c3 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'singleton'
 
 class FeedManager
@@ -60,29 +62,29 @@ class FeedManager
   private
 
   def redis
-    $redis
+    Redis.current
   end
 
   def filter_from_home?(status, receiver)
     should_filter = false
 
-    if status.reply? && !status.thread.account.nil?                                     # Filter out if it's a reply
-      should_filter = !receiver.following?(status.thread.account)                       # and I'm not following the person it's a reply to
-      should_filter = should_filter && !(receiver.id == status.thread.account_id)       # and it's not a reply to me
-      should_filter = should_filter && !(status.account_id == status.thread.account_id) # and it's not a self-reply
-    elsif status.reblog?                                                                # Filter out a reblog
-      should_filter = receiver.blocking?(status.reblog.account)                         # if I'm blocking the reblogged person
+    if status.reply? && !status.thread.account.nil?                      # Filter out if it's a reply
+      should_filter   = !receiver.following?(status.thread.account)      # and I'm not following the person it's a reply to
+      should_filter &&= !(receiver.id == status.thread.account_id)       # and it's not a reply to me
+      should_filter &&= !(status.account_id == status.thread.account_id) # and it's not a self-reply
+    elsif status.reblog?                                                 # Filter out a reblog
+      should_filter = receiver.blocking?(status.reblog.account)          # if I'm blocking the reblogged person
     end
 
     should_filter
   end
 
   def filter_from_mentions?(status, receiver)
-    should_filter = receiver.id == status.account_id                             # Filter if I'm mentioning myself
-    should_filter = should_filter || receiver.blocking?(status.account)          # or it's from someone I blocked
+    should_filter   = receiver.id == status.account_id            # Filter if I'm mentioning myself
+    should_filter ||= receiver.blocking?(status.account)          # or it's from someone I blocked
 
-    if status.reply? && !status.thread.account.nil?                              # or it's a reply
-      should_filter = should_filter || receiver.blocking?(status.thread.account) # to a user I blocked
+    if status.reply? && !status.thread.account.nil?               # or it's a reply
+      should_filter ||= receiver.blocking?(status.thread.account) # to a user I blocked
     end
 
     should_filter
@@ -92,9 +94,9 @@ class FeedManager
     should_filter = receiver.blocking?(status.account)
 
     if status.reply? && !status.thread.account.nil?
-      should_filter = should_filter || receiver.blocking?(status.thread.account)
+      should_filter ||= receiver.blocking?(status.thread.account)
     elsif status.reblog?
-      should_filter = should_filter || receiver.blocking?(status.reblog.account)
+      should_filter ||= receiver.blocking?(status.reblog.account)
     end
 
     should_filter
diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb
index 3a6ba97c89c4c59b2e16898acca72effab3864c3..5748680af082d006890c83eab1ae1d470185d9a7 100644
--- a/app/lib/formatter.rb
+++ b/app/lib/formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'singleton'
 
 class Formatter
@@ -17,7 +19,7 @@ class Formatter
     html = link_mentions(html, status.mentions)
     html = link_hashtags(html)
 
-    html.html_safe
+    html.html_safe # rubocop:disable Rails/OutputSafety
   end
 
   def reformat(html)
@@ -30,7 +32,7 @@ class Formatter
     html = encode(account.note)
     html = link_urls(html)
 
-    html.html_safe
+    html.html_safe # rubocop:disable Rails/OutputSafety
   end
 
   private
diff --git a/app/lib/tag_manager.rb b/app/lib/tag_manager.rb
index d2cf35b49ff02caf3878dd7f5259c9dbc581cc3b..fcc4b325925f447b528df825b9a1ff7f4334bf1f 100644
--- a/app/lib/tag_manager.rb
+++ b/app/lib/tag_manager.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'singleton'
 
 class TagManager
@@ -18,7 +20,7 @@ class TagManager
   end
 
   def local_domain?(domain)
-    domain.nil? || domain.gsub(/[\/]/, '').downcase == Rails.configuration.x.local_domain.downcase
+    domain.nil? || domain.gsub(/[\/]/, '').casecmp(Rails.configuration.x.local_domain).zero?
   end
 
   def uri_for(target)
diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb
index 1a3196acd2a5de72621cd619233e1c7c8df042c0..2f7dd6ee5dc32aa90f24723fc24506d7da05027d 100644
--- a/app/mailers/application_mailer.rb
+++ b/app/mailers/application_mailer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class ApplicationMailer < ActionMailer::Base
   default from: (ENV['SMTP_FROM_ADDRESS'] || 'notifications@localhost')
   layout 'mailer'
diff --git a/app/mailers/notification_mailer.rb b/app/mailers/notification_mailer.rb
index 6c81df2699ff50097372755bc829ae9ff38c1f22..2ed5629792b93120e973e9e23ed59db491c74c82 100644
--- a/app/mailers/notification_mailer.rb
+++ b/app/mailers/notification_mailer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class NotificationMailer < ApplicationMailer
   helper StreamEntriesHelper
 
diff --git a/app/models/account.rb b/app/models/account.rb
index 81b724935073641270f677354cc3b0dba277e932..90434f97517b561f766660f4c0dd23991d7b58d1 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Account < ApplicationRecord
   include Targetable
   include PgSearch
@@ -92,11 +94,11 @@ class Account < ApplicationRecord
   end
 
   def favourited?(status)
-    (status.reblog? ? status.reblog : status).favourites.where(account: self).count > 0
+    (status.reblog? ? status.reblog : status).favourites.where(account: self).count.positive?
   end
 
   def reblogged?(status)
-    (status.reblog? ? status.reblog : status).reblogs.where(account: self).count > 0
+    (status.reblog? ? status.reblog : status).reblogs.where(account: self).count.positive?
   end
 
   def keypair
@@ -115,8 +117,8 @@ class Account < ApplicationRecord
   def avatar_remote_url=(url)
     self.avatar = URI.parse(url) unless self[:avatar_remote_url] == url
     self[:avatar_remote_url] = url
-  rescue OpenURI::HTTPError
-    #
+  rescue OpenURI::HTTPError => e
+    Rails.logger.debug "Error fetching remote avatar: #{e}"
   end
 
   def object_type
diff --git a/app/models/application_record.rb b/app/models/application_record.rb
index 10a4cba84df37181f4cf310fd85d8f0aaa5d90ba..71fbba5b32873f53ea6e713ea0219acda01a9286 100644
--- a/app/models/application_record.rb
+++ b/app/models/application_record.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class ApplicationRecord < ActiveRecord::Base
   self.abstract_class = true
 end
diff --git a/app/models/block.rb b/app/models/block.rb
index 418afdbdfa8b7a9db5391a582b75121e0db03030..dc05bce877e28d07d307a0321856a1e4ca490b40 100644
--- a/app/models/block.rb
+++ b/app/models/block.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Block < ApplicationRecord
   belongs_to :account
   belongs_to :target_account, class_name: 'Account'
diff --git a/app/models/concerns/paginable.rb b/app/models/concerns/paginable.rb
index 08f2076212fb10e17c7998b6b2f063b7a9c9cc5c..b3df081c0c336e438d9b6da42a934e06f9df8996 100644
--- a/app/models/concerns/paginable.rb
+++ b/app/models/concerns/paginable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Paginable
   extend ActiveSupport::Concern
 
diff --git a/app/models/concerns/streamable.rb b/app/models/concerns/streamable.rb
index b3354c8193939d1feacb69f70a54dd671f316de8..d9f5dc4d863834b7a8d27218138fe6782b9a54bc 100644
--- a/app/models/concerns/streamable.rb
+++ b/app/models/concerns/streamable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Streamable
   extend ActiveSupport::Concern
 
diff --git a/app/models/concerns/targetable.rb b/app/models/concerns/targetable.rb
index d46590a02e447b54e3e758e34bdcfc1bf9c413fa..4c335a30257680def47cf01ced5e5b8e0679c239 100644
--- a/app/models/concerns/targetable.rb
+++ b/app/models/concerns/targetable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Targetable
   extend ActiveSupport::Concern
 
diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb
index 8f9eb11826fc2429695520d19cdc22f12c68d115..9075b90a0207b9c75a1b3d0c212b43c7218f679b 100644
--- a/app/models/domain_block.rb
+++ b/app/models/domain_block.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class DomainBlock < ApplicationRecord
   validates :domain, presence: true, uniqueness: true
 
diff --git a/app/models/favourite.rb b/app/models/favourite.rb
index 60d853ce2a853e7418a3a92076d0b05d22d0046a..0a4f60ecb4ca04bee9b90ea76c9eb6cbd7922008 100644
--- a/app/models/favourite.rb
+++ b/app/models/favourite.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Favourite < ApplicationRecord
   include Paginable
   include Streamable
diff --git a/app/models/feed.rb b/app/models/feed.rb
index 408403873114b6f214d79df1490f980e35dcdb0b..e7f2ab3a56473aece7b99ebb7cbd1ff712589c48 100644
--- a/app/models/feed.rb
+++ b/app/models/feed.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Feed
   def initialize(type, account)
     @type    = type
@@ -28,6 +30,6 @@ class Feed
   end
 
   def redis
-    $redis
+    Redis.current
   end
 end
diff --git a/app/models/follow.rb b/app/models/follow.rb
index 720812b6d5ce04e710020155dfac462ae1fde03e..c918dabf235f61c6ec822b2bd2340b4af504b9f5 100644
--- a/app/models/follow.rb
+++ b/app/models/follow.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Follow < ApplicationRecord
   include Paginable
   include Streamable
diff --git a/app/models/follow_suggestion.rb b/app/models/follow_suggestion.rb
index ee76d4b6add7d1d5e7286c41f35ea0c327ec1b3f..2daa40dcb99332bf2a9d4e8d13cade97cfb88d0c 100644
--- a/app/models/follow_suggestion.rb
+++ b/app/models/follow_suggestion.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class FollowSuggestion
   class << self
     def get(for_account_id, limit = 10)
diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb
index a740792f209598140ecb0f7aaa3573039f55e140..d3e3d73beb83628dec6c5127ae9fa2777702f03d 100644
--- a/app/models/media_attachment.rb
+++ b/app/models/media_attachment.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class MediaAttachment < ApplicationRecord
   IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif'].freeze
   VIDEO_MIME_TYPES = ['video/webm', 'video/mp4'].freeze
@@ -6,9 +8,9 @@ class MediaAttachment < ApplicationRecord
   belongs_to :status,  inverse_of: :media_attachments
 
   has_attached_file :file,
-    styles: -> (f) { file_styles f },
-    processors: -> (f) { f.video? ? [:transcoder] : [:thumbnail] },
-    convert_options: { all: "-strip" }
+                    styles: -> (f) { file_styles f },
+                    processors: -> (f) { f.video? ? [:transcoder] : [:thumbnail] },
+                    convert_options: { all: '-strip' }
   validates_attachment_content_type :file, content_type: IMAGE_MIME_TYPES + VIDEO_MIME_TYPES
   validates_attachment_size :file, less_than: 4.megabytes
 
@@ -20,8 +22,8 @@ class MediaAttachment < ApplicationRecord
 
   def file_remote_url=(url)
     self.file = URI.parse(url)
-  rescue OpenURI::HTTPError
-    #
+  rescue OpenURI::HTTPError => e
+    Rails.logger.debug "Error fetching remote attachment: #{e}"
   end
 
   def image?
@@ -43,19 +45,19 @@ class MediaAttachment < ApplicationRecord
       if f.instance.image?
         {
           original: '100%',
-          small: '510x680>'
+          small: '510x680>',
         }
       else
         {
           small: {
             convert_options: {
               output: {
-                vf: 'scale=\'min(510\, iw):min(680\, ih)\':force_original_aspect_ratio=decrease'
-              }
+                vf: 'scale=\'min(510\, iw):min(680\, ih)\':force_original_aspect_ratio=decrease',
+              },
             },
             format: 'png',
-            time: 1
-          }
+            time: 1,
+          },
         }
       end
     end
diff --git a/app/models/mention.rb b/app/models/mention.rb
index b39fa2cbbc755082e3529c5f7b0d69e6e2a4eb72..a3c8baf21aa64b623bf3aa841f99c1ffdea7552f 100644
--- a/app/models/mention.rb
+++ b/app/models/mention.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Mention < ApplicationRecord
   belongs_to :account, inverse_of: :mentions
   belongs_to :status
diff --git a/app/models/status.rb b/app/models/status.rb
index 9e27110083d29e1279008f6024438c42e074defd..c6f5c8d6ca6240075a02613393710df5897f19fb 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Status < ApplicationRecord
   include Paginable
   include Streamable
@@ -89,22 +91,17 @@ class Status < ApplicationRecord
 
     def as_public_timeline(account = nil)
       query = joins('LEFT OUTER JOIN accounts ON statuses.account_id = accounts.id').where('accounts.silenced = FALSE')
-
-      unless account.nil?
-        query = filter_timeline(query, account)
-      end
+      query = filter_timeline(query, account) unless account.nil?
 
       query.with_includes.with_counters
     end
 
     def as_tag_timeline(tag, account = nil)
       query = tag.statuses
-        .joins('LEFT OUTER JOIN accounts ON statuses.account_id = accounts.id')
-        .where('accounts.silenced = FALSE')
+                 .joins('LEFT OUTER JOIN accounts ON statuses.account_id = accounts.id')
+                 .where('accounts.silenced = FALSE')
 
-      unless account.nil?
-        query = filter_timeline(query, account)
-      end
+      query = filter_timeline(query, account) unless account.nil?
 
       query.with_includes.with_counters
     end
diff --git a/app/models/stream_entry.rb b/app/models/stream_entry.rb
index f8272be17cfb2eaf628bc504d5626f37038818a1..f6c8f461b306339667f71717ac277643b8643d0d 100644
--- a/app/models/stream_entry.rb
+++ b/app/models/stream_entry.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class StreamEntry < ApplicationRecord
   include Paginable
 
@@ -15,7 +17,11 @@ class StreamEntry < ApplicationRecord
   scope :with_includes, -> { includes(:account, status: STATUS_INCLUDES, favourite: [:account, :stream_entry, status: STATUS_INCLUDES], follow: [:target_account, :stream_entry]) }
 
   def object_type
-    orphaned? ? :activity : (targeted? ? :activity : activity.object_type)
+    if orphaned?
+      :activity
+    else
+      targeted? ? :activity : activity.object_type
+    end
   end
 
   def verb
diff --git a/app/models/tag.rb b/app/models/tag.rb
index ac89c9bff36ab8478d3d8878e428de6f6953202a..e5b0511ae7ee0d3c2e859230d6e0e07d9ea79b6a 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class Tag < ApplicationRecord
   has_and_belongs_to_many :statuses
 
diff --git a/app/models/user.rb b/app/models/user.rb
index de3521989784dfe4a77ec26f516f81e0fc5058eb..4a330d8eac2733e90f93b0146a3bd2a4376646b9 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class User < ApplicationRecord
   devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable
 
diff --git a/app/services/base_service.rb b/app/services/base_service.rb
index 10c55810915ac1813089c6bbd29271212b6b7181..6653255f2a38f0ff90f587bc45d2eea7cb556331 100644
--- a/app/services/base_service.rb
+++ b/app/services/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class BaseService
   include ActionView::Helpers::TextHelper
   include ActionView::Helpers::SanitizeHelper
diff --git a/app/services/block_domain_service.rb b/app/services/block_domain_service.rb
index 93987af29b7c4ff0a26540cc6fcfdf6f45ef157f..a8fafe412195c4f4bcaed3ad364ef31e4768337d 100644
--- a/app/services/block_domain_service.rb
+++ b/app/services/block_domain_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class BlockDomainService < BaseService
   def call(domain)
     DomainBlock.find_or_create_by!(domain: domain)
diff --git a/app/services/block_service.rb b/app/services/block_service.rb
index 6c841d25b4252da2aeeb003b0fd1a41cd47e5dad..388a592e0925c56cd6bf6ccad2b8bad14a9a099d 100644
--- a/app/services/block_service.rb
+++ b/app/services/block_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class BlockService < BaseService
   def call(account, target_account)
     return if account.id == target_account.id
@@ -20,6 +22,6 @@ class BlockService < BaseService
   end
 
   def redis
-    $redis
+    Redis.current
   end
 end
diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb
index 43e36c1380b20dd33a593ed974ed45fd9098392f..70cf06e02b29c9a74abad785fb39dc92a2fc4c1b 100644
--- a/app/services/fan_out_on_write_service.rb
+++ b/app/services/fan_out_on_write_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class FanOutOnWriteService < BaseService
   # Push a status into home and mentions feeds
   # @param [Status] status
diff --git a/app/services/favourite_service.rb b/app/services/favourite_service.rb
index ab7f8aea12431f7d0f642d7c3d3ac076b5e61e52..9c6f12478b32b4ddf555af5848c44034fb480e5c 100644
--- a/app/services/favourite_service.rb
+++ b/app/services/favourite_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class FavouriteService < BaseService
   # Favourite a status and notify remote user
   # @param [Account] account
diff --git a/app/services/fetch_atom_service.rb b/app/services/fetch_atom_service.rb
index 5f00bf8010ef9121edc13338fd3e25a97de022a1..98ee1db845effd311c6eff73aeafbfadf2f9abb4 100644
--- a/app/services/fetch_atom_service.rb
+++ b/app/services/fetch_atom_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class FetchAtomService < BaseService
   def call(url)
     response = http_client.head(url)
@@ -9,15 +11,9 @@ class FetchAtomService < BaseService
     Rails.logger.debug "Remote status GET request returned code #{response.code}"
 
     return nil if response.code != 200
-
-    if response.mime_type == 'application/atom+xml'
-      return [url, fetch(url)]
-    elsif !response['Link'].blank?
-      return process_headers(url, response)
-    else
-      return process_html(fetch(url))
-    end
-
+    return [url, fetch(url)] if response.mime_type == 'application/atom+xml'
+    return process_headers(url, response) unless response['Link'].blank?
+    process_html(fetch(url))
   rescue OpenSSL::SSL::SSLError => e
     Rails.logger.debug "SSL error: #{e}"
   end
@@ -31,17 +27,17 @@ class FetchAtomService < BaseService
     alternate_link = page.xpath('//link[@rel="alternate"]').find { |link| link['type'] == 'application/atom+xml' }
 
     return nil if alternate_link.nil?
-    return [alternate_link['href'], fetch(alternate_link['href'])]
+    [alternate_link['href'], fetch(alternate_link['href'])]
   end
 
   def process_headers(url, response)
     Rails.logger.debug 'Processing link header'
 
     link_header    = LinkHeader.parse(response['Link'].is_a?(Array) ? response['Link'].first : response['Link'])
-    alternate_link = link_header.find_link(['rel', 'alternate'], ['type', 'application/atom+xml'])
+    alternate_link = link_header.find_link(%w(rel alternate), %w(type application/atom+xml))
 
     return process_html(fetch(url)) if alternate_link.nil?
-    return [alternate_link.href, fetch(alternate_link.href)]
+    [alternate_link.href, fetch(alternate_link.href)]
   end
 
   def fetch(url)
diff --git a/app/services/fetch_remote_account_service.rb b/app/services/fetch_remote_account_service.rb
index 7cbc9f6ec5b8e81077e9f35e3d6ce2e99abb564b..3c3694a6505d17ce8127e3450843219303d33489 100644
--- a/app/services/fetch_remote_account_service.rb
+++ b/app/services/fetch_remote_account_service.rb
@@ -1,9 +1,11 @@
+# frozen_string_literal: true
+
 class FetchRemoteAccountService < BaseService
   def call(url)
     atom_url, body = FetchAtomService.new.call(url)
 
     return nil if atom_url.nil?
-    return process_atom(atom_url, body)
+    process_atom(atom_url, body)
   end
 
   private
@@ -25,7 +27,7 @@ class FetchRemoteAccountService < BaseService
     Rails.logger.debug "Unparseable URL given: #{url}"
     nil
   rescue Nokogiri::XML::XPath::SyntaxError
-    Rails.logger.debug "Invalid XML or missing namespace"
+    Rails.logger.debug 'Invalid XML or missing namespace'
     nil
   end
 end
diff --git a/app/services/fetch_remote_status_service.rb b/app/services/fetch_remote_status_service.rb
index e4537d61f97d058f43634063084c1409c3838d69..7063231e43e3d160c918c1258a160ed368a8f68d 100644
--- a/app/services/fetch_remote_status_service.rb
+++ b/app/services/fetch_remote_status_service.rb
@@ -1,9 +1,11 @@
+# frozen_string_literal: true
+
 class FetchRemoteStatusService < BaseService
   def call(url)
     atom_url, body = FetchAtomService.new.call(url)
 
     return nil if atom_url.nil?
-    return process_atom(atom_url, body)
+    process_atom(atom_url, body)
   end
 
   private
@@ -20,7 +22,7 @@ class FetchRemoteStatusService < BaseService
 
     statuses = ProcessFeedService.new.call(body, account)
 
-    return statuses.first
+    statuses.first
   end
 
   def extract_author(url, xml)
@@ -34,7 +36,7 @@ class FetchRemoteStatusService < BaseService
 
     return FollowRemoteAccountService.new.call("#{username}@#{domain}")
   rescue Nokogiri::XML::XPath::SyntaxError
-    Rails.logger.debug "Invalid XML or missing namespace"
+    Rails.logger.debug 'Invalid XML or missing namespace'
     nil
   end
 end
diff --git a/app/services/follow_remote_account_service.rb b/app/services/follow_remote_account_service.rb
index b309425a83a13113f1cc202e4234e556b97a02e5..37339d8ed751cd68d5017991fbecf59784855bd6 100644
--- a/app/services/follow_remote_account_service.rb
+++ b/app/services/follow_remote_account_service.rb
@@ -1,7 +1,9 @@
+# frozen_string_literal: true
+
 class FollowRemoteAccountService < BaseService
   include OStatus2::MagicKey
 
-  DFRN_NS = 'http://purl.org/macgirvin/dfrn/1.0'.freeze
+  DFRN_NS = 'http://purl.org/macgirvin/dfrn/1.0'
 
   # Find or create a local account for a remote user.
   # When creating, look up the user's webfinger and fetch all
@@ -49,7 +51,7 @@ class FollowRemoteAccountService < BaseService
     get_profile(xml, account)
     account.save!
 
-    return account
+    account
   end
 
   private
diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb
index 2a9dc82c38caaad61fb31353beb9ef82e3eba57b..3b97840cb5085a47c470f799f0005707d7162d2e 100644
--- a/app/services/follow_service.rb
+++ b/app/services/follow_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class FollowService < BaseService
   # Follow a remote user, notify remote user about the follow
   # @param [Account] source_account From which to follow
@@ -35,7 +37,7 @@ class FollowService < BaseService
   end
 
   def redis
-    $redis
+    Redis.current
   end
 
   def follow_remote_account_service
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index b23808a7c1b1a5d6f79522048a89cd161c3a0638..cf824ff99262cb5f5daf5c2dd4f65cff07c85640 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class PostStatusService < BaseService
   # Post a text status update, fetch and notify remote users mentioned
   # @param [Account] account Account from which to post
diff --git a/app/services/precompute_feed_service.rb b/app/services/precompute_feed_service.rb
index 3094c50fdb6375db2804c3722db45b22931152f4..54d11b631d8756f1346a2bf359b39c29dac64326 100644
--- a/app/services/precompute_feed_service.rb
+++ b/app/services/precompute_feed_service.rb
@@ -1,10 +1,10 @@
+# frozen_string_literal: true
+
 class PrecomputeFeedService < BaseService
   # Fill up a user's home/mentions feed from DB and return a subset
   # @param [Symbol] type :home or :mentions
   # @param [Account] account
   def call(type, account)
-    instant_return = []
-
     Status.send("as_#{type}_timeline", account).limit(FeedManager::MAX_ITEMS).each do |status|
       next if FeedManager.instance.filter?(type, status, account)
       redis.zadd(FeedManager.instance.key(type, account.id), status.id, status.reblog? ? status.reblog_of_id : status.id)
@@ -14,6 +14,6 @@ class PrecomputeFeedService < BaseService
   private
 
   def redis
-    $redis
+    Redis.current
   end
 end
diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb
index b671c809dcf92fcced72d9f321329860f77bd6c4..561feb0325bab74b107283990afaaf0441157264 100644
--- a/app/services/process_feed_service.rb
+++ b/app/services/process_feed_service.rb
@@ -1,6 +1,8 @@
+# frozen_string_literal: true
+
 class ProcessFeedService < BaseService
-  ACTIVITY_NS = 'http://activitystrea.ms/spec/1.0/'.freeze
-  THREAD_NS   = 'http://purl.org/syndication/thread/1.0'.freeze
+  ACTIVITY_NS = 'http://activitystrea.ms/spec/1.0/'
+  THREAD_NS   = 'http://purl.org/syndication/thread/1.0'
 
   def call(body, account)
     xml = Nokogiri::XML(body)
@@ -89,13 +91,13 @@ class ProcessFeedService < BaseService
         account = @account
       end
 
-      status = Status.create!({
+      status = Status.create!(
         uri: id(entry),
         url: url(entry),
         account: account,
         text: content(entry),
-        created_at: published(entry),
-      })
+        created_at: published(entry)
+      )
 
       if thread?(entry)
         Rails.logger.debug "Trying to attach #{status.id} (#{id(entry)}) to #{thread(entry).first}"
diff --git a/app/services/process_hashtags_service.rb b/app/services/process_hashtags_service.rb
index df30f73ae86d5896f0c026e2a21f079105ca79b0..3bf3471ec4cf3bbb5add17e6553ce8f63ffa830e 100644
--- a/app/services/process_hashtags_service.rb
+++ b/app/services/process_hashtags_service.rb
@@ -1,8 +1,8 @@
+# frozen_string_literal: true
+
 class ProcessHashtagsService < BaseService
   def call(status, tags = [])
-    if status.local?
-      tags = status.text.scan(Tag::HASHTAG_RE).map(&:first)
-    end
+    tags = status.text.scan(Tag::HASHTAG_RE).map(&:first) if status.local?
 
     tags.map(&:downcase).uniq.each do |tag|
       status.tags << Tag.where(name: tag).first_or_initialize(name: tag)
diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb
index be78ebb58b408ef0c7b2228499ffefca3ac0c569..ecd3c2b2c4b575f0e4278eff0c1edf6ac51cfcf5 100644
--- a/app/services/process_interaction_service.rb
+++ b/app/services/process_interaction_service.rb
@@ -1,5 +1,7 @@
+# frozen_string_literal: true
+
 class ProcessInteractionService < BaseService
-  ACTIVITY_NS = 'http://activitystrea.ms/spec/1.0/'.freeze
+  ACTIVITY_NS = 'http://activitystrea.ms/spec/1.0/'
 
   # Record locally the remote interaction with our user
   # @param [String] envelope Salmon envelope
@@ -76,9 +78,7 @@ class ProcessInteractionService < BaseService
 
     return if status.nil?
 
-    if account.id == status.account_id
-      remove_status_service.call(status)
-    end
+    remove_status_service.call(status) if account.id == status.account_id
   end
 
   def favourite!(xml, from_account)
diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb
index 8baa03d070aee72fbb524e7c23d35d8a23db1e05..fd5a02ffedb01b887c068b1a7302a411980cf505 100644
--- a/app/services/process_mentions_service.rb
+++ b/app/services/process_mentions_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class ProcessMentionsService < BaseService
   # Scan status for mentions and fetch remote mentioned users, create
   # local mention pointers, send Salmon notifications to mentioned
diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb
index 627d4e0e81c5fac4cb2fcb6da08fd6b5e46276d0..884d911a4bb19a3c83cac4656b7e79c6221ac51f 100644
--- a/app/services/reblog_service.rb
+++ b/app/services/reblog_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class ReblogService < BaseService
   # Reblog a status and notify its remote author
   # @param [Account] account Account to reblog from
diff --git a/app/services/remove_status_service.rb b/app/services/remove_status_service.rb
index 66fa1be18fba350008f7b1685c7bbfb1a9a5789c..689abc97bb4f32747d4b6432e9c06519475872e2 100644
--- a/app/services/remove_status_service.rb
+++ b/app/services/remove_status_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class RemoveStatusService < BaseService
   def call(status)
     remove_from_self(status) if status.account.local?
@@ -62,6 +64,6 @@ class RemoveStatusService < BaseService
   end
 
   def redis
-    $redis
+    Redis.current
   end
 end
diff --git a/app/services/search_service.rb b/app/services/search_service.rb
index 9e8ee6220bc5c7fd28265b052255f7b42e296a7b..c4cffda13fb188a87561394b8b940835ff1440ac 100644
--- a/app/services/search_service.rb
+++ b/app/services/search_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class SearchService < BaseService
   def call(query, limit, resolve = false)
     return if query.blank?
@@ -5,10 +7,10 @@ class SearchService < BaseService
     username, domain = query.split('@')
 
     results = if domain.nil?
-      Account.search_for(username)
-    else
-      Account.search_for("#{username} #{domain}")
-    end
+                Account.search_for(username)
+              else
+                Account.search_for("#{username} #{domain}")
+              end
 
     results = results.limit(limit).with_counters
 
diff --git a/app/services/send_interaction_service.rb b/app/services/send_interaction_service.rb
index a425dcc8e2d4a0f16cce1155dd4c2cbd906c5c01..05a1e77e39d7c598d3481f2b3f40b8faccc074b0 100644
--- a/app/services/send_interaction_service.rb
+++ b/app/services/send_interaction_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class SendInteractionService < BaseService
   # Send an Atom representation of an interaction to a remote Salmon endpoint
   # @param [StreamEntry] stream_entry
diff --git a/app/services/subscribe_service.rb b/app/services/subscribe_service.rb
index 427a5e198600b892bfff898ed37b49e1f935a2cf..820b208e9936424ac616025bf10d2359745f8be3 100644
--- a/app/services/subscribe_service.rb
+++ b/app/services/subscribe_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class SubscribeService < BaseService
   def call(account)
     account.secret = SecureRandom.hex
diff --git a/app/services/unblock_service.rb b/app/services/unblock_service.rb
index d241614232cfe0ed04cdbd39b377486936bb9547..3658dcd715fda5ad7345131a6bb47d5b8313b23f 100644
--- a/app/services/unblock_service.rb
+++ b/app/services/unblock_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class UnblockService < BaseService
   def call(account, target_account)
     account.unblock!(target_account) if account.blocking?(target_account)
diff --git a/app/services/unfavourite_service.rb b/app/services/unfavourite_service.rb
index 2491c194f1e615c5fe67f0d72702f7ced757ba09..de6e84e7d460ed12d74f53627b0585a7288476ce 100644
--- a/app/services/unfavourite_service.rb
+++ b/app/services/unfavourite_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class UnfavouriteService < BaseService
   def call(account, status)
     favourite = Favourite.find_by!(account: account, status: status)
diff --git a/app/services/unfollow_service.rb b/app/services/unfollow_service.rb
index d22451a74e374da3b9891bdfb0c77654101fe4d0..b3386a99c16bfc63c69cecf96b874e8028eeb7a7 100644
--- a/app/services/unfollow_service.rb
+++ b/app/services/unfollow_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class UnfollowService < BaseService
   # Unfollow and notify the remote user
   # @param [Account] source_account Where to unfollow from
@@ -21,6 +23,6 @@ class UnfollowService < BaseService
   end
 
   def redis
-    $redis
+    Redis.current
   end
 end
diff --git a/app/services/update_remote_profile_service.rb b/app/services/update_remote_profile_service.rb
index 14f8cc868602d77bbb2722200d7b74e5a10f9bfc..2909ae12aa1fa7dad4b440b12356e4dd5d9f1bdd 100644
--- a/app/services/update_remote_profile_service.rb
+++ b/app/services/update_remote_profile_service.rb
@@ -1,14 +1,16 @@
+# frozen_string_literal: true
+
 class UpdateRemoteProfileService < BaseService
   POCO_NS = 'http://portablecontacts.net/spec/1.0'
 
   def call(author_xml, account)
     return if author_xml.nil?
 
-    if author_xml.at_xpath('./poco:displayName', poco: POCO_NS).nil?
-      account.display_name = account.username
-    else
-      account.display_name = author_xml.at_xpath('./poco:displayName', poco: POCO_NS).content
-    end
+    account.display_name = if author_xml.at_xpath('./poco:displayName', poco: POCO_NS).nil?
+                             account.username
+                           else
+                             author_xml.at_xpath('./poco:displayName', poco: POCO_NS).content
+                           end
 
     unless author_xml.at_xpath('./poco:note').nil?
       account.note = author_xml.at_xpath('./poco:note', poco: POCO_NS).content
diff --git a/app/workers/distribution_worker.rb b/app/workers/distribution_worker.rb
index a69b3952327a6298538e508374e1303573c0e97f..09374bee293e1be91c8bed56158cde1c77f6a86c 100644
--- a/app/workers/distribution_worker.rb
+++ b/app/workers/distribution_worker.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class DistributionWorker
   include Sidekiq::Worker
 
diff --git a/app/workers/hub_ping_worker.rb b/app/workers/hub_ping_worker.rb
index 57d716c97faed9d60f1fdbb3c20aaff91036e0a4..d9a9ff4277b9c3a27dc50fe2e24611660735de72 100644
--- a/app/workers/hub_ping_worker.rb
+++ b/app/workers/hub_ping_worker.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class HubPingWorker
   include Sidekiq::Worker
   include RoutingHelper
diff --git a/app/workers/notification_worker.rb b/app/workers/notification_worker.rb
index 473a9232bb4dfd3acd50fcc2ee799b2eb76071ec..386e94111f54343168b948641f8848b5667099da 100644
--- a/app/workers/notification_worker.rb
+++ b/app/workers/notification_worker.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class NotificationWorker
   include Sidekiq::Worker
 
diff --git a/app/workers/processing_worker.rb b/app/workers/processing_worker.rb
index 87ebbc5eaa8d9487878c1c93a7e976a2347b281d..3b11a4c5ea52cd3bf2115cba512765a54339aae8 100644
--- a/app/workers/processing_worker.rb
+++ b/app/workers/processing_worker.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class ProcessingWorker
   include Sidekiq::Worker
 
diff --git a/app/workers/regeneration_worker.rb b/app/workers/regeneration_worker.rb
index f0ed01d7112e60d9e6b2ef8684372aa954ec657f..3aece0ba28a63061bc5440f514111aaf74a6e8af 100644
--- a/app/workers/regeneration_worker.rb
+++ b/app/workers/regeneration_worker.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class RegenerationWorker
   include Sidekiq::Worker
 
diff --git a/app/workers/thread_resolve_worker.rb b/app/workers/thread_resolve_worker.rb
index c59fb093aa379ed66c9d987b59619a9e3543b0d0..70016198965678de20d3a4ad1bd80231718dc2b7 100644
--- a/app/workers/thread_resolve_worker.rb
+++ b/app/workers/thread_resolve_worker.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class ThreadResolveWorker
   include Sidekiq::Worker
 
diff --git a/config.ru b/config.ru
index bd83b25412305f93fdb0a892aded30e5178899ba..3476455ef3e2f3058557a315f1729d635012d2b9 100644
--- a/config.ru
+++ b/config.ru
@@ -1,3 +1,4 @@
+# frozen_string_literal: true
 # This file is used by Rack-based servers to start the application.
 
 require ::File.expand_path('../config/environment', __FILE__)
diff --git a/config/initializers/redis.rb b/config/initializers/redis.rb
index 4fe33811f200c877fe0b7c2036311a7975962653..3825710b87a7d18f4fe039c66fc4c47e2160e295 100644
--- a/config/initializers/redis.rb
+++ b/config/initializers/redis.rb
@@ -1,5 +1,7 @@
-$redis = Redis.new({
+# frozen_string_literal: true
+
+Redis.current = Redis.new(
   host: ENV.fetch('REDIS_HOST') { 'localhost' },
   port: ENV.fetch('REDIS_PORT') { 6379 },
   driver: :hiredis
-})
+)
diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake
index 94da0904c9326b8e9e402386d9e855936a0fef52..58bafff662ccb7e5a67675b67c950b074e09feb6 100644
--- a/lib/tasks/mastodon.rake
+++ b/lib/tasks/mastodon.rake
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 namespace :mastodon do
   namespace :media do
     desc 'Removes media attachments that have not been assigned to any status for longer than a day'
@@ -28,7 +30,7 @@ namespace :mastodon do
     task refresh: :environment do
       Account.expiring(1.day.from_now).find_each do |a|
         Rails.logger.debug "PuSH re-subscribing to #{a.acct}"
-        SubscribeService.new.(a)
+        SubscribeService.new.call(a)
       end
     end
   end
@@ -36,7 +38,7 @@ namespace :mastodon do
   namespace :feeds do
     desc 'Clears all timelines so that they would be regenerated on next hit'
     task clear: :environment do
-      $redis.keys('feed:*').each { |key| $redis.del(key) }
+      Redis.current.keys('feed:*').each { |key| Redis.current.del(key) }
     end
   end