Skip to content

Commit a0372b0

Browse files
committed
Add search functionality to users
There used to be a search functionality in the users index page that was using Mazer's datatable stylesheet (PR#52), but it was then removed in PR#86 as we discussed doing it our way instead. This commit enables searching Users by using a similar logic to what Dmitry did for searching Topics.
1 parent e73dd4c commit a0372b0

File tree

4 files changed

+100
-2
lines changed

4 files changed

+100
-2
lines changed

app/controllers/users_controller.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ class UsersController < ApplicationController
33
before_action :set_user, only: %i[ edit update destroy ]
44

55
def index
6-
@users = User.all
6+
@users = User.all.search_with_params(user_search_params)
77
end
88

99
def new
@@ -52,4 +52,9 @@ def set_user
5252
def user_params
5353
params.expect(user: [ :email, :password, :is_admin ])
5454
end
55+
56+
def user_search_params
57+
return {} unless params[:search].present?
58+
params.expect(search: [ :email, :is_admin, :order ])
59+
end
5560
end

app/models/user.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ class User < ApplicationRecord
2424
validates :email, presence: true, uniqueness: true, format: URI::MailTo::EMAIL_REGEXP
2525
validates :password_digest, presence: true
2626

27+
scope :search_with_params, ->(params) do
28+
self
29+
.then { |scope| params[:email].present? ? scope.where("email ILIKE ?", "%#{params[:email]}%") : scope }
30+
.then { |scope| params[:is_admin].present? ? scope.where(is_admin: params[:is_admin]) : scope }
31+
.then { |scope| scope.order(created_at: params[:order]&.to_sym || :desc) }
32+
end
33+
2734
def topics
2835
Topic.where(provider_id: providers.pluck(:id))
2936
end

app/views/users/index.html.erb

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,42 @@
11
<div class="page-heading">
22
<section class="section">
3+
<div class="card">
4+
<div class="card-header d-flex justify-content-between align-items-center">
5+
<h2 class="card-title">Search</h2>
6+
</div>
7+
<div class="card-content">
8+
<div class="card-body">
9+
<%= form_for :search, url: users_path, method: :get, data: { controller: "search", search_target: "search", turbo_frame: "user-list", turbo_action: "advance" } do |f| %>
10+
<div class="form-body">
11+
<div class="row">
12+
<div class="col-md-6 col-12">
13+
<div class="form-group">
14+
<%= f.label :email %>
15+
<%= f.text_field :email, value: params.dig(:search, :email), class: "form-control", data: { action: "input->search#submit" } %>
16+
</div>
17+
</div>
18+
<div class="col-md-6 col-12">
19+
<div class="form-group">
20+
<%= f.label "Role" %>
21+
<%= f.select :is_admin, options_for_select([["Admin", "true"], ["Contributor", "false"]], params.dig(:search, :is_admin)), { prompt: "Select user role" }, class: "form-select", data: { action: "change->search#submit" } %>
22+
</div>
23+
</div>
24+
<div class="col-md-6 col-12">
25+
<div class="form-group">
26+
<%= f.label :order %>
27+
<%= f.select :order, options_for_select([["By most recently added", :desc], ["By least recently added", :asc]], params.dig(:search, :order)), {}, class: "form-select", data: { action: "change->search#submit" } %>
28+
</div>
29+
</div>
30+
<div class="col-12 d-flex justify-content-end">
31+
<%= link_to "Clear", users_path, class: "btn btn-light-secondary me-1 mb-1" %>
32+
</div>
33+
</div>
34+
</div>
35+
<% end %>
36+
</div>
37+
</div>
38+
</div>
39+
340
<div class="card">
441
<div class="card-header d-flex justify-content-between align-items-center">
542
<h2>User List</h2>
@@ -20,7 +57,7 @@
2057
<% @users.each do |user| %>
2158
<tr>
2259
<td><%= user.email %></td>
23-
<td><%= user.is_admin %></td>
60+
<td><%= user.is_admin ? "✅" : "✖️" %></td>
2461
<td class="text-end">
2562
<%= link_to edit_user_path(user), class: "btn btn-secondary btn-sm pr-2" do %>
2663
<i class="bi bi-pencil"></i> Edit

spec/system/user_search_spec.rb

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
require "rails_helper"
2+
3+
RSpec.describe "User search", type: :system do
4+
let(:admin) { create(:user, :admin, email: "[email protected]", created_at: 3.days.ago) }
5+
let!(:martin) { create(:user, email: "[email protected]", created_at: 2.days.ago) }
6+
let!(:rosemary) { create(:user, email: "[email protected]", created_at: 1.day.ago) }
7+
8+
before do
9+
login_as(admin)
10+
click_link("Users")
11+
end
12+
13+
it "shows by default the users from most to least recently added" do
14+
expect(page).to have_text(/#{rosemary.email}.+#{martin.email}.+#{admin.email}/m)
15+
end
16+
17+
context "searching by email" do
18+
it "only displays users matching the search" do
19+
fill_in "search[email]", with: "mar"
20+
21+
expect(page).to have_text(rosemary.email)
22+
expect(page).to have_text(martin.email)
23+
expect(page).not_to have_text(admin.email)
24+
end
25+
end
26+
27+
context "searching by role" do
28+
it "only displays users matching the search" do
29+
select "Admin", from: "search_is_admin"
30+
31+
expect(page).to have_text(admin.email)
32+
expect(page).not_to have_text(rosemary.email)
33+
expect(page).not_to have_text(martin.email)
34+
35+
select "Contributor", from: "search_is_admin"
36+
37+
expect(page).to have_text(rosemary.email)
38+
expect(page).to have_text(martin.email)
39+
expect(page).not_to have_text(admin.email)
40+
end
41+
end
42+
43+
context "sorting" do
44+
it "displays users in the selected order" do
45+
select "By least recently added", from: "search_order"
46+
expect(page).to have_text(/#{admin.email}.+#{martin.email}.+#{rosemary.email}/m)
47+
end
48+
end
49+
end

0 commit comments

Comments
 (0)