diff --git a/Gemfile b/Gemfile
index 52a2372e2625768f74a266186a1366f29baf03d9..c6e9fd628865eaa9020a23ace522f5cc8d46b480 100644
--- a/Gemfile
+++ b/Gemfile
@@ -87,6 +87,9 @@ group :development do
 
   # JavaScript runtime
   gem 'execjs'
+
+  # local mailbox
+  gem 'mailcatcher'
 end
 
 group :test do
diff --git a/Gemfile.lock b/Gemfile.lock
index b123256c77b81af2ec2fe950f124ebc7dce9b6b7..caba06c98e1d5448a33b9931d3bdd601e03048ae 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -32,8 +32,10 @@ GEM
       erubis (~> 2.7.0)
       rails-dom-testing (~> 1.0, >= 1.0.5)
       rails-html-sanitizer (~> 1.0, >= 1.0.2)
-    active_model_serializers (0.9.5)
-      activemodel (>= 3.2)
+    active_model_serializers (0.10.0)
+      actionpack (>= 4.0)
+      activemodel (>= 4.0)
+      railties (>= 4.0)
     activejob (4.2.6)
       activesupport (= 4.2.6)
       globalid (>= 0.3.0)
@@ -74,10 +76,10 @@ GEM
       debug_inspector (>= 0.0.1)
     brakeman (3.3.0)
     builder (3.2.2)
-    bullet (5.0.0)
+    bullet (5.1.0)
       activesupport (>= 3.0.0)
-      uniform_notifier (~> 1.9.0)
-    byebug (8.2.5)
+      uniform_notifier (~> 1.10.0)
+    byebug (9.0.4)
     choice (0.2.0)
     chronic (0.10.2)
     climate_control (0.0.3)
@@ -94,6 +96,7 @@ GEM
     connection_pool (2.2.0)
     curb (0.8.8)
     cvss (0.99.0)
+    daemons (1.2.3)
     dalli (2.7.6)
     data_mapper (1.2.0)
       dm-aggregates (~> 1.2.0)
@@ -122,7 +125,7 @@ GEM
     debug_inspector (0.0.2)
     descendants_tracker (0.0.4)
       thread_safe (~> 0.3, >= 0.3.1)
-    devise (4.0.2)
+    devise (4.0.3)
       bcrypt (~> 3.0)
       orm_adapter (~> 0.1)
       railties (>= 4.1.0, < 5.1)
@@ -183,15 +186,14 @@ GEM
       multi_json
     equalizer (0.0.11)
     erubis (2.7.0)
-    execjs (2.6.0)
+    eventmachine (1.0.9.1)
+    execjs (2.7.0)
     faraday (0.9.2)
       multipart-post (>= 1.2, < 3)
-    fast_stack (0.2.0)
     fastercsv (1.5.5)
     feature (1.3.0)
     ffi (1.9.10)
-    flamegraph (0.1.0)
-      fast_stack
+    flamegraph (0.9.5)
     flay (2.7.0)
       erubis (~> 2.7.0)
       ruby_parser (~> 3.0)
@@ -227,21 +229,30 @@ GEM
       nokogiri (>= 1.5.9)
     mail (2.6.4)
       mime-types (>= 1.16, < 4)
-    mime-types (3.0)
+    mailcatcher (0.6.4)
+      activesupport (~> 4.0)
+      eventmachine (= 1.0.9.1)
+      mail (~> 2.3)
+      rack (~> 1.5)
+      sinatra (~> 1.2)
+      skinny (~> 0.2.3)
+      sqlite3 (~> 1.3)
+      thin (~> 1.5.0)
+    mime-types (3.1)
       mime-types-data (~> 3.2015)
-    mime-types-data (3.2016.0221)
+    mime-types-data (3.2016.0521)
     mimemagic (0.3.0)
     mina (0.3.8)
       open4 (~> 1.3.4)
       rake
     mini_portile2 (2.0.0)
-    minitest (5.8.4)
+    minitest (5.9.0)
     minitest-reporters (1.1.9)
       ansi
       builder
       minitest (>= 5.0)
       ruby-progressbar
-    multi_json (1.12.0)
+    multi_json (1.12.1)
     multi_xml (0.5.5)
     multipart-post (2.0.0)
     net-http-persistent (2.9.4)
@@ -275,7 +286,7 @@ GEM
       omniauth-oauth (~> 1.1)
     open4 (1.3.4)
     orm_adapter (0.5.0)
-    paper_trail (5.0.1)
+    paper_trail (5.1.0)
       activerecord (>= 3.0, < 6.0)
       activesupport (>= 3.0, < 6.0)
       request_store (~> 1.1)
@@ -287,7 +298,7 @@ GEM
       mimemagic (= 0.3.0)
     paranoia (2.1.5)
       activerecord (~> 4.0)
-    parser (2.3.0.7)
+    parser (2.3.1.0)
       ast (~> 2.2)
     pg (0.18.4)
     phantomjs (2.1.1.0)
@@ -303,7 +314,7 @@ GEM
       activesupport (>= 3.0.0)
     rack (1.6.4)
     rack-cors (0.4.0)
-    rack-mini-profiler (0.9.9.2)
+    rack-mini-profiler (0.10.1)
       rack (>= 1.2.0)
     rack-protection (1.5.3)
       rack
@@ -352,7 +363,7 @@ GEM
     redis (3.3.0)
     redis-namespace (1.5.2)
       redis (~> 3.0, >= 3.0.4)
-    reek (4.0.1)
+    reek (4.0.2)
       codeclimate-engine-rb (~> 0.3.1)
       parser (~> 2.3, >= 2.3.0.6)
       rainbow (~> 2.0)
@@ -362,23 +373,23 @@ GEM
     responders (2.2.0)
       railties (>= 4.2.0, < 5.1)
     rmagick (2.15.4)
-    rubocop (0.39.0)
-      parser (>= 2.3.0.7, < 3.0)
+    rubocop (0.40.0)
+      parser (>= 2.3.1.0, < 3.0)
       powerpack (~> 0.1)
       rainbow (>= 1.99.1, < 3.0)
       ruby-progressbar (~> 1.7)
       unicode-display_width (~> 1.0, >= 1.0.1)
     ruby-graphviz (1.2.2)
-    ruby-progressbar (1.8.0)
+    ruby-progressbar (1.8.1)
     ruby_parser (3.8.2)
       sexp_processor (~> 4.1)
-    rubycritic (2.9.0)
+    rubycritic (2.9.1)
       colorize
       flay (= 2.7.0)
       flog (= 4.3.2)
       launchy (= 2.4.3)
-      parser (= 2.3.0.7)
-      reek (= 4.0.1)
+      parser (= 2.3.1.0)
+      reek (= 4.0.2)
       ruby_parser (~> 3.8)
       virtus (~> 1.0)
     rubyzip (1.2.0)
@@ -406,8 +417,11 @@ GEM
       rack (~> 1.5)
       rack-protection (~> 1.4)
       tilt (>= 1.3, < 3)
-    slim (3.0.6)
-      temple (~> 0.7.3)
+    skinny (0.2.4)
+      eventmachine (~> 1.0.0)
+      thin (>= 1.5, < 1.7)
+    slim (3.0.7)
+      temple (~> 0.7.6)
       tilt (>= 1.3.3, < 2.1)
     spring (1.7.1)
     sprockets (3.6.0)
@@ -423,15 +437,19 @@ GEM
     stringex (1.5.1)
     sys-uname (1.0.2)
       ffi (>= 1.0.0)
-    temple (0.7.6)
+    temple (0.7.7)
     terminal-table (1.5.2)
+    thin (1.5.1)
+      daemons (>= 1.0.9)
+      eventmachine (>= 0.12.6)
+      rack (>= 1.0.0)
     thor (0.19.1)
     thread_safe (0.3.5)
-    tilt (2.0.2)
+    tilt (2.0.4)
     tzinfo (1.2.2)
       thread_safe (~> 0.1)
     unicode-display_width (1.0.5)
-    uniform_notifier (1.9.0)
+    uniform_notifier (1.10.0)
     uuidtools (2.1.5)
     virtus (1.0.5)
       axiom-types (~> 0.1)
@@ -472,6 +490,7 @@ DEPENDENCIES
   gitlab
   immigrant
   libarchive-static
+  mailcatcher
   mimemagic
   mina
   minitest-reporters
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index eec3dc612bb1195e9ab7561d2f3601452f956665..d904c81c1a0f597f8fa851b0364080ca2dd914bd 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -5,10 +5,10 @@ class ApplicationController < ActionController::API
   include PublicActivity::StoreController
 
   # tracking user in papertrail
-  before_filter :set_paper_trail_whodunnit
+  before_action :set_paper_trail_whodunnit
 
   # check if client application is allowed to consumes the API.
-  before_filter :allow_client_application, if: -> { Feature.active?(:allow_client_application) }
+  before_action :allow_client_application, if: -> { Feature.active?(:allow_client_application) }
 
   # Prevent CSRF attacks by raising an exception.
   # For APIs, you may want to use :null_session instead.
@@ -23,17 +23,9 @@ class ApplicationController < ActionController::API
   protected
 
   def configure_permitted_parameters
-    registration_params = [:name, :email, :avatar, :password, :password_confirmation]
-
-    if params[:action] == 'update'
-      devise_parameter_sanitizer.permit(:account_update) do |user_params|
-        user_params.permit(registration_params << :current_password)
-      end
-    elsif params[:action] == 'create'
-      devise_parameter_sanitizer.permit(:sign_in) do |user_params|
-        user_params.permit(registration_params << :terms_of_service)
-      end
-    end
+    registration_params = [:name, :email, :avatar, :password, :password_confirmation, :current_password, :terms_of_service]
+    devise_parameter_sanitizer.permit :sign_up, keys: registration_params
+    devise_parameter_sanitizer.permit :account_update, keys: registration_params
   end
 
   private
diff --git a/app/controllers/concerns/taggable_controller.rb b/app/controllers/concerns/taggable_controller.rb
index c01fccbad6f5e21c204743177c10e73ee3b62645..bfe6382eb41ec11b898128e5e2b296043ac96fbe 100644
--- a/app/controllers/concerns/taggable_controller.rb
+++ b/app/controllers/concerns/taggable_controller.rb
@@ -10,14 +10,14 @@ module TaggableController
   # POST /v1/learning_objects/1/tagging.json
   def tagging
     @owner.tag(taggable, with: [tag_params[:name]])
-    render json: ActiveModel::ArraySerializer.new(taggable.tags.to_a), status: :created
+    render json: taggable.tags, status: :created
   end
 
   # DELETE /v1/learning_objects/1/untagging
   # DELETE /v1/learning_objects/1/untagging.json
   def untagging
     @owner.untag(taggable, tag_params[:name])
-    render json: ActiveModel::ArraySerializer.new(taggable.tags.to_a), status: :ok
+    render json: taggable.tags, status: :ok
   end
 
   protected
diff --git a/app/controllers/v1/search_controller.rb b/app/controllers/v1/search_controller.rb
index c581c0866d8f36a120e74c290218cd404a4e6e3a..6daa430c5f4723d214784c95cad23e7da6c80918 100644
--- a/app/controllers/v1/search_controller.rb
+++ b/app/controllers/v1/search_controller.rb
@@ -4,30 +4,27 @@ class V1::SearchController < ApplicationController
   # GET v1/search
   # GET v1/search.json
   def index
-    render json: ActiveModel::ArraySerializer.new(SearchService.search(@search, current_user)), status: :ok
-  rescue => e
-    if e.message == 'Invalid search'
-      render json: @search.errors, status: :bad_request
-    else
-      render nothing: true, status: :internal_server_error
-    end
+    render json: SearchService.search(@search, current_user), status: :ok
+  rescue SearchService::InvalidSearchError => e
+    render json: @search.errors, status: :bad_request
   end
 
   # GET v1/search/autocomplete
   # GET v1/search/autocomplete.json
   def autocomplete
-    render json: ActiveModel::ArraySerializer.new(SearchService.autocomplete(@search, current_user)), status: :ok
-  rescue => e
-    if e.message == 'Invalid search'
-      render json: @search.errors, status: :bad_request
-    else
-      render nothing: true, status: :internal_server_error
-    end
+    render json: ArraySerializer.new(SearchService.autocomplete(@search, current_user)), status: :ok
+  rescue SearchService::InvalidSearchError => e
+    render json: @search.errors, status: :bad_request
   end
 
   private
 
   def set_search
-    @search = Search.new(params)
+    @search = Search.new(search_params)
+  end
+
+  # Never trust parameters from the scary internet, only allow the white list through.
+  def search_params
+    params.require(:search).permit(:page, :results_per_page, :order, :query, :search_class)
   end
 end
diff --git a/app/models/search.rb b/app/models/search.rb
index 5f9dcf1fae8b7f66ac5edf293154ee82ff82b1a4..4f99e8fe47dd2abbb70513f4b1a1100026a3ffe6 100644
--- a/app/models/search.rb
+++ b/app/models/search.rb
@@ -4,7 +4,7 @@ class Search
 
   validates_presence_of :query, :results_per_page, :order, :search_class
   validates_numericality_of :results_per_page, greater_than: 0
-  validates :search_class, inclusion: { in: %w(LearningObject Collection User) }
+  validates :search_class, inclusion: { in: ::SearchService::SEARCH_CLASSES }
 
   def initialize(params = {})
     super(defaults.merge(params.select { |key, _value| respond_to? key }))
diff --git a/app/services/search_service.rb b/app/services/search_service.rb
index f5fa43b5a613e930ec42e349931e0210e91281f1..d95fe90014fe5fa37998d74c91bad69bae7e3bed 100644
--- a/app/services/search_service.rb
+++ b/app/services/search_service.rb
@@ -1,4 +1,8 @@
 module SearchService
+  SEARCH_CLASSES = %w(LearningObject Collection User)
+
+  class InvalidSearchError < StandardError; end;
+
   def self.search(search, user)
     model = instance(search, user)
     model.search.results
@@ -9,8 +13,10 @@ module SearchService
     model.autocomplete
   end
 
+  private
+
   def self.instance(search, user)
-    raise 'Invalid search' unless search.valid?
+    raise InvalidSearchError unless search.valid?
     "SearchService::#{search.search_class}".constantize.new(search, user)
   end
 end
diff --git a/config/environments/development.rb b/config/environments/development.rb
index eb3772c3a0867beabd00a672cf5c425b64731fa7..987efaf25f29e895293756ea1e7bc3c1703b2bad 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -51,5 +51,9 @@ Rails.application.configure do
   # Raises error for missing translations
   # config.action_view.raise_on_missing_translations = true
 
+  #config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
+  # Lets define mailcatcher configs
+  config.action_mailer.delivery_method = :smtp
+  config.action_mailer.smtp_settings = { address: 'localhost', port: 1025 }
   config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
 end
diff --git a/config/routes.rb b/config/routes.rb
index 4289be952c2bbcdb6672d0af66e5c606415250c7..4b045a9eb95bb5f4d2c8d84a188b34fb7ff89cd8 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -71,8 +71,11 @@ Rails.application.routes.draw do
     end
 
     # search routes
-    get :search, to: 'search#index'
-    get 'search/autocomplete', to: 'search#autocomplete'
+    resources :search, only: :index do
+      collection do
+        get :autocomplete
+      end
+    end
 
     resources :collections, concerns: [:followable, :sociable, :reviewable, :taggable, :versionable, :deletable, :highlights]
     resources :learning_objects, concerns: [:sociable, :reviewable, :taggable, :versionable, :deletable, :highlights] do
diff --git a/test/controllers/v1/search_controller_test.rb b/test/controllers/v1/search_controller_test.rb
index 75df1fa21f283932509d387eac8c6c8fe5d2bf93..8814eb8d694252176483d08b76c88840403a2480 100644
--- a/test/controllers/v1/search_controller_test.rb
+++ b/test/controllers/v1/search_controller_test.rb
@@ -9,23 +9,20 @@ class V1::SearchControllerTest < ActionController::TestCase
     auth_application
   end
 
-  test 'should get index and return :ok' do
-    get :index, search_class: 'LearningObject'
-    assert_response :ok
+  test 'should search return :ok' do
+    SearchService::SEARCH_CLASSES.each do |search_class|
+      get :index, search: {search_class: search_class}
+      assert_response :ok
+    end
   end
 
-  test 'should get index and return :bad_request' do
-    get :index
+  test 'should search with invalid class and return :bad_request' do
+    get :index, search: {search_class: 'invalid'}
     assert_response :bad_request
   end
 
-  test 'should get autocomplete and return :ok' do
-    get :autocomplete, search_class: 'LearningObject'
-    assert_response :ok
-  end
-
-  test 'should get autocomplete and return :bad_request' do
-    get :autocomplete
+  test 'should autocomplete with invalid class and return :bad_request' do
+    get :autocomplete, search: {search_class: 'invalid'}
     assert_response :bad_request
   end