Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
14c624f
Create draft PR for #99
IzzySmillie Jan 10, 2023
34bc4b4
Add kaminari gem
IzzySmillie Jan 10, 2023
3ae3bc0
Add pagination to projects index
IzzySmillie Jan 10, 2023
d9f6bd8
Fix projects var
IzzySmillie Jan 10, 2023
ddd88dc
wip: pagination working with json render
IzzySmillie Jan 10, 2023
6d19686
Fix rendering of index for paginated_projects
IzzySmillie Jan 10, 2023
10bf337
wip setting up pagination link header
IzzySmillie Jan 11, 2023
fed886d
current and total not needed as links
IzzySmillie Jan 11, 2023
b74e65a
wip: refactoring pagination_header
IzzySmillie Jan 11, 2023
f16a491
more refactoring
IzzySmillie Jan 11, 2023
0d05666
Merge branch 'main' into issues/99-Add_pagination_functionality_to_th…
IzzySmillie Jan 11, 2023
697fdc9
Update default_per_page
IzzySmillie Jan 11, 2023
3a6700f
More refactoring and splitting out
IzzySmillie Jan 11, 2023
d90f6ba
Add pagination response header tests
IzzySmillie Jan 11, 2023
c483f11
Small change to CORS
loiswells97 Jan 17, 2023
5d93112
Order projects by updated_at before paginating
loiswells97 Jan 19, 2023
be2a402
Merge branch 'main' into issues/99-Add_pagination_functionality_to_th…
IzzySmillie Jan 26, 2023
2d3d62a
Gemlock
IzzySmillie Jan 26, 2023
1aac492
Merge main
IzzySmillie Jan 26, 2023
c61a7f4
Gemfile from main
IzzySmillie Jan 26, 2023
b5bac2e
Gemlock fix
IzzySmillie Jan 26, 2023
780eff2
Merge branch 'main' into issues/99-Add_pagination_functionality_to_th…
IzzySmillie Jan 30, 2023
80e17c9
Merge branch 'main' into issues/99-Add_pagination_functionality_to_th…
IzzySmillie Jan 30, 2023
efc032b
Merge branch 'main' into issues/99-Add_pagination_functionality_to_th…
IzzySmillie Jan 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ gem 'cancancan', '~> 3.3'
gem 'faraday'
gem 'importmap-rails'
gem 'jbuilder'
gem 'kaminari'
gem 'pg', '~> 1.1'
gem 'puma', '~> 5.6'
gem 'rack-cors'
Expand Down
13 changes: 13 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@ GEM
activesupport (>= 5.0.0)
jmespath (1.6.2)
json (2.6.2)
kaminari (1.2.2)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.2)
kaminari-activerecord (= 1.2.2)
kaminari-core (= 1.2.2)
kaminari-actionview (1.2.2)
actionview
kaminari-core (= 1.2.2)
kaminari-activerecord (1.2.2)
activerecord
kaminari-core (= 1.2.2)
kaminari-core (1.2.2)
loofah (2.19.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
Expand Down Expand Up @@ -282,6 +294,7 @@ DEPENDENCIES
faraday
importmap-rails
jbuilder
kaminari
pg (~> 1.1)
pry-byebug
puma (~> 5.6)
Expand Down
48 changes: 46 additions & 2 deletions app/controllers/api/projects_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ class ProjectsController < ApiController
before_action :require_oauth_user, only: %i[create update index destroy]
before_action :load_project, only: %i[show update destroy]
before_action :load_projects, only: %i[index]
after_action :pagination_link_header, only: [:index]
load_and_authorize_resource
skip_load_resource only: :create

def index
render :index, formats: [:json]
@paginated_projects = @projects.page(params[:page])
render index: @paginated_projects, formats: [:json]
end

def show
Expand Down Expand Up @@ -51,7 +53,7 @@ def load_project
end

def load_projects
@projects = Project.where(user_id: current_user)
@projects = Project.where(user_id: current_user).order(updated_at: :desc)
end

def project_params
Expand All @@ -65,5 +67,47 @@ def project_params
}
)
end

def pagination_link_header
pagination_links = []
pagination_links << page_links(first_page, 'first')
pagination_links << page_links(last_page, 'last')
pagination_links << page_links(next_page, 'next')
pagination_links << page_links(prev_page, 'prev')

pagination_links.compact_blank!
headers['Link'] = pagination_links.join(', ')
end

def page_links(to_page, rel_type)
return if to_page.nil?

page_info = "page=#{to_page}"
"<#{request.base_url}/api/projects?#{page_info}>; rel=\"#{rel_type}\""
end

def page
params.key?(:page) ? params[:page].to_i : 1
end

def total_pages
@projects.page(1).total_pages
end

def first_page
@projects.page(page).first_page? ? nil : 1
end

def last_page
@projects.page(page).last_page? ? nil : total_pages
end

def next_page
@projects.page(page).next_page
end

def prev_page
@projects.page(page).prev_page
end
end
end
2 changes: 1 addition & 1 deletion app/views/api/projects/index.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# frozen_string_literal: true

json.array! @projects, :identifier, :project_type, :name, :user_id, :updated_at
json.array! @paginated_projects, :identifier, :project_type, :name, :user_id, :updated_at
2 changes: 1 addition & 1 deletion config/initializers/cors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins origins_array
resource '*', headers: :any, methods: %i[get post patch put delete]
resource '*', headers: :any, methods: %i[get post patch put delete], expose: ['Link']
end
end
5 changes: 5 additions & 0 deletions config/initializers/kaminari_config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

Kaminari.configure do |config|
config.default_per_page = 8
end
39 changes: 39 additions & 0 deletions spec/request/projects/index_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require 'rails_helper'

RSpec.describe 'Project index requests', type: :request do
include PaginationLinksMock

let(:user_id) { 'e0675b6c-dc48-4cd6-8c04-0f7ac05af51a' }
let(:project_keys) { %w[identifier project_type name user_id updated_at] }

Expand Down Expand Up @@ -41,6 +43,43 @@
end
end

context 'when the projects index has pagination' do
before do
create_list(:project, 10, user_id:)
mock_oauth_user(user_id)
end

it 'returns the default number of projects on the first page' do
get '/api/projects'
returned = JSON.parse(response.body)
expect(returned.length).to eq(8)
end

it 'returns the next set of projects on the next page' do
get '/api/projects?page=2'
returned = JSON.parse(response.body)
expect(returned.length).to eq(4)
end

it 'has the correct response headers for the first page' do
last_link = page_links(2, 'last')
next_link = page_links(2, 'next')
expected_link_header = [last_link, next_link].join(', ')

get '/api/projects'
expect(response.headers['Link']).to eq expected_link_header
end

it 'has the correct response headers for the next page' do
first_link = page_links(1, 'first')
prev_link = page_links(1, 'prev')
expected_link_header = [first_link, prev_link].join(', ')

get '/api/projects?page=2'
expect(response.headers['Link']).to eq expected_link_header
end
end

context 'when no user' do
it 'returns unauthorized' do
get '/api/projects'
Expand Down
8 changes: 8 additions & 0 deletions spec/support/pagination_links_mock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

module PaginationLinksMock
def page_links(to_page, rel_type)
page_info = "page=#{to_page}"
"<http://www.example.com/api/projects?#{page_info}>; rel=\"#{rel_type}\""
end
end