diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 3e7257e2..8154a821 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -8,7 +8,14 @@ class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
- @users = User.all
+ (@filterrific = initialize_filterrific(
+ User.all,
+ params[:filterrific],
+ select_options: {
+ sorted_by: User.options_for_sorted_by
+ }
+ )) || return
+ @users = @filterrific.find.page(params[:page])
end
# GET /users/new
diff --git a/app/models/user.rb b/app/models/user.rb
index 0db95239..0482c600 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -10,10 +10,58 @@ class User < ApplicationRecord
validates :email, presence: true, uniqueness: { case_sensitive: false }
+ filterrific(
+ default_filter_params: { sorted_by: 'email_desc' },
+ available_filters: %i[
+ sorted_by
+ search_query
+ ]
+ )
+
scope :admins, -> {
where(is_admin: true)
}
+ scope :search_query, ->(query) {
+ return nil if query.blank?
+
+ # condition query, parse into individual keywords
+ terms = query.downcase.split(/\s+/)
+ # replace "*" with "%" for wildcard searches,
+ # append '%', remove duplicate '%'s
+ terms = terms.map do |e|
+ ('%' + e.gsub('*', '%') + '%').gsub(/%+/, '%')
+ end
+ # configure number of OR conditions for provision
+ # of interpolation arguments. Adjust this if you
+ # change the number of OR conditions.
+ num_or_conditions = 1
+ where(
+ terms.map do
+ or_clauses = [
+ 'LOWER(users.email) LIKE ?'
+ ].join(' OR ')
+ "(#{or_clauses})"
+ end.join(' AND '),
+ *terms.map { |e| [e] * num_or_conditions }.flatten
+ )
+ }
+
+ scope :sorted_by, ->(sort_option) {
+ # extract the sort direction from the param value.
+ direction = /desc$/.match?(sort_option) ? 'desc' : 'asc'
+ case sort_option.to_s
+ when /^email_/
+ order(Arel.sql("LOWER(users.email) #{direction}"))
+ when /^years_experience_/
+ order(Arel.sql("users.years_experience #{direction}"))
+ when /^admin_/
+ order(Arel.sql("users.is_admin #{direction}"))
+ else
+ raise(ArgumentError, "Invalid sort option: #{sort_option.inspect}")
+ end
+ }
+
def admin?
is_admin
end
@@ -22,6 +70,17 @@ def sha_email
sha = Digest::SHA1.new
sha.hexdigest email
end
+
+ def self.options_for_sorted_by
+ [
+ ['Email (a-z)', 'email_asc'],
+ ['Email (z-a)', 'email_desc'],
+ ['Years Experience (lowest first)', 'years_experience_asc'],
+ ['Years Experience (highest first)', 'years_experience_desc'],
+ ['Admin? (false first)', 'admin_asc'],
+ ['Admin? (true first)', 'admin_desc']
+ ]
+ end
end
# == Schema Information
diff --git a/app/views/users/_list.html.erb b/app/views/users/_list.html.erb
new file mode 100644
index 00000000..2cfeb071
--- /dev/null
+++ b/app/views/users/_list.html.erb
@@ -0,0 +1,45 @@
+<% if users.load.empty? %>
+ No users at this time!
+<% else %>
+
+
+
+
+ <%= page_entries_info users, model: 'user', class: 'align-middle' %>
+
+
+ <%= link_to "Reset filters", reset_filterrific_url, class: 'btn btn-secondary align-middle' %>
+
+
+ <%= render_filterrific_spinner %>
+
+
+
+
+ <%= filterrific_sorting_link(@filterrific, :email) %>
+ <%= filterrific_sorting_link(@filterrific, :years_experience) %>
+ <%= filterrific_sorting_link(@filterrific, :admin) %>
+
+
+
+
+
+ <% @users.each do |user| %>
+
+ <%= user.email %>
+ <%= user.years_experience %>
+ <%= user.is_admin %>
+ <% if user.admin? %>
+ <%= link_to 'Demote', user_demote_path(user), method: :put %>
+ <% else %>
+ <%= link_to 'Promote', user_promote_path(user), method: :put %>
+ <% end %>
+ <%= link_to 'Edit', edit_user_path(user) %>
+ <%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %>
+
+ <% end %>
+
+
+
+ <%= will_paginate users, renderer: WillPaginate::ActionView::BootstrapLinkRenderer %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb
index 1178ae26..03647ff0 100644
--- a/app/views/users/index.html.erb
+++ b/app/views/users/index.html.erb
@@ -1,31 +1,31 @@
<% if can? :manage, User %>
-Users
-
-
-
- Email
- Years experience
- Is admin
-
-
-
-
-
- <% @users.each do |user| %>
-
- <%= user.email %>
- <%= user.years_experience %>
- <%= user.is_admin %>
- <% if user.admin? %>
- <%= link_to 'Demote', user_demote_path(user), method: :put %>
- <% else %>
- <%= link_to 'Promote', user_promote_path(user), method: :put %>
- <% end %>
- <%= link_to 'Edit', edit_user_path(user) %>
- <%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %>
-
+ Users
+ <%= link_to 'New User', new_user_path %>
+
+
+ <%= form_for_filterrific @filterrific do |f| %>
+
+
+
+ Search
+ <%= f.text_field(
+ :search_query,
+ class: 'filterrific-periodically-observed'
+ ) %>
+
+
+
+
+ Sorted by
+ <%= f.select(:sorted_by, @filterrific.select_options[:sorted_by],
+ {},
+ { class: 'form-control' }
+ ) %>
+
+
+
<% end %>
-
-
-<% end %>
\ No newline at end of file
+
+<% end %>
+
+<%= render 'list', users: @users %>
\ No newline at end of file
diff --git a/app/views/users/index.js.erb b/app/views/users/index.js.erb
new file mode 100644
index 00000000..2c85890e
--- /dev/null
+++ b/app/views/users/index.js.erb
@@ -0,0 +1,7 @@
+<% js = escape_javascript(
+ render(
+ partial: 'users/list',
+ locals: { users: @users }
+ )
+) %>
+$("#filterrific_results").html("<%= js %>");
\ No newline at end of file
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index 0ec8d600..c56185f5 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -4,7 +4,7 @@
RSpec.describe UsersController, type: :controller do
context 'admin' do
- let(:current_user) { build_stubbed(:admin) }
+ let(:current_user) { create(:admin) }
before do
sign_in current_user
allow(request.env['warden']).to receive(:authenticate!).and_return(current_user)
@@ -13,15 +13,7 @@
describe 'GET #index' do
before do
- @users = [build_stubbed(:user), build_stubbed(:user)]
- allow_any_instance_of(User).to receive(:admin?).and_return(true)
- allow(User).to receive(:all).and_return(@users)
- allow(User).to receive(:where).and_return(@users)
- end
-
- it 'calls all' do
- expect(User).to receive(:all)
- get :index
+ @users = [create(:user), create(:user), current_user]
end
it 'returns a success response' do
@@ -31,7 +23,7 @@
it 'assigns users to @users' do
get :index
- expect(assigns(:users)).to eq(@users)
+ expect(assigns(:users).size).to eq(3)
end
it 'renders the index template' do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 6b1c7046..e6cde374 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -27,6 +27,36 @@
end
end
end
+
+ describe 'search_query' do
+ it 'gets all users with query' do
+ user1 = create(:user, email: 'unicorns@gmail.com')
+ user2 = create(:user, email: 'oh_no@test.com')
+ user3 = create(:user, email: 'bye@test.com')
+ aggregate_failures do
+ expect(User.search_query('unicorns').length).to eq 1
+ expect(User.search_query('unicorns')).to include user1
+ expect(User.search_query('unicorns')).not_to include user2
+ expect(User.search_query('unicorns')).not_to include user3
+ end
+ end
+ end
+
+ describe 'sorted_by' do
+ it 'gets all users sorted' do
+ user1 = create(:user, email: 'Alphabets@test.com', is_admin: true, years_experience: 3)
+ user2 = create(:user, email: 'Zebra@test.com', is_admin: false, years_experience: 4)
+ user3 = create(:user, email: 'Cows@test.com', is_admin: false, years_experience: 5)
+ aggregate_failures do
+ expect(User.sorted_by('email_asc').first).to eq user1
+ expect(User.sorted_by('email_desc').first).to eq user2
+ expect(User.sorted_by('years_experience_asc').first).to eq user1
+ expect(User.sorted_by('years_experience_desc').first).to eq user3
+ expect(User.sorted_by('admin_desc').first).to eq user1
+ expect { User.sorted_by('oh_no') }.to raise_error(ArgumentError, 'Invalid sort option: "oh_no"')
+ end
+ end
+ end
end
context 'methods' do