Skip to content

Commit

Permalink
Merge pull request #1672 from tvdeyen/page-api-pagination
Browse files Browse the repository at this point in the history
Page api pagination
  • Loading branch information
tvdeyen authored Nov 15, 2019
2 parents 8013c37 + ac18eca commit 71ee31a
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ spec/dummy/public/assets
.ruby-gemset
.ruby-version
.env
.rspec
1 change: 0 additions & 1 deletion .rspec

This file was deleted.

1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ group :development, :test do
gem 'localeapp', '~> 3.0', require: false
gem 'dotenv', '~> 2.2'
gem 'github_fast_changelog', require: false
gem 'active_record_query_trace', require: false
end
end
62 changes: 61 additions & 1 deletion app/controllers/alchemy/api/pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,24 @@ def index
else
@pages = Page.accessible_by(current_ability, :index)
end
@pages = @pages.includes(*page_includes)
if params[:page_layout].present?
Alchemy::Deprecation.warn <<~WARN
Passing page_layout parameter to Alchemy::Api::PagesController#index is deprecated.
Please pass a Ransack search query instead:
q: {
page_layout_eq: '#{params[:page_layout]}'
}
WARN
@pages = @pages.where(page_layout: params[:page_layout])
end
render json: @pages, adapter: :json, root: 'pages'
@pages = @pages.ransack(params[:q]).result

if params[:page]
@pages = @pages.page(params[:page]).per(params[:per_page])
end

render json: @pages, adapter: :json, root: 'pages', meta: meta_data
end

# Returns all pages as nested json object for tree views
Expand Down Expand Up @@ -54,5 +68,51 @@ def load_page
) ||
raise(ActiveRecord::RecordNotFound)
end

def meta_data
{
total_count: total_count_value,
per_page: per_page_value,
page: page_value
}
end

def total_count_value
params[:page] ? @pages.total_count : @pages.size
end

def per_page_value
if params[:page]
(params[:per_page] || Kaminari.config.default_per_page).to_i
else
@pages.size
end
end

def page_value
params[:page] ? params[:page].to_i : nil
end

def page_includes
[
:tags,
{
elements: [
{
nested_elements: [
{
contents: :essence
},
:tags
]
},
{
contents: :essence
},
:tags
]
}
]
end
end
end
2 changes: 1 addition & 1 deletion app/models/alchemy/content.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Content < BaseRecord
# Concerns
include Alchemy::Content::Factory

belongs_to :essence, polymorphic: true, dependent: :destroy
belongs_to :essence, polymorphic: true, dependent: :destroy, inverse_of: :content
belongs_to :element, touch: true, inverse_of: :contents
has_one :page, through: :element

Expand Down
2 changes: 1 addition & 1 deletion app/models/alchemy/element.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class Element < BaseRecord

# Content positions are scoped by their essence_type, so positions can be the same for different contents.
# In order to get contents in creation order we also order them by id.
has_many :contents, -> { order(:position, :id) }, dependent: :destroy
has_many :contents, -> { order(:position, :id) }, dependent: :destroy, inverse_of: :element

has_many :all_nested_elements,
-> { order(:position) },
Expand Down
4 changes: 0 additions & 4 deletions app/serializers/alchemy/page_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,5 @@ class PageSerializer < ActiveModel::Serializer
:status

has_many :elements

def elements
object.elements.published
end
end
end
2 changes: 1 addition & 1 deletion lib/alchemy/essence.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def acts_as_essence(options = {})
stampable stamper_class_name: Alchemy.user_class_name
validate :validate_ingredient, on: :update, if: -> { validations.any? }
has_one :content, as: :essence, class_name: "Alchemy::Content"
has_one :content, as: :essence, class_name: "Alchemy::Content", inverse_of: :essence
has_one :element, through: :content, class_name: "Alchemy::Element"
has_one :page, through: :element, class_name: "Alchemy::Page"
Expand Down
60 changes: 40 additions & 20 deletions spec/controllers/alchemy/api/pages_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ module Alchemy

describe '#index' do
let!(:page) { create(:alchemy_page, :public) }
let(:result) { JSON.parse(response.body) }

it "returns all public pages as json objects" do
it 'returns JSON' do
get :index, params: {format: :json}

expect(response.status).to eq(200)
expect(response.media_type).to eq('application/json')
expect(result).to have_key('pages')
end

result = JSON.parse(response.body)
it "returns all public pages" do
get :index, params: {format: :json}

expect(result).to have_key('pages')
expect(result['pages'].size).to eq(2)
end

Expand All @@ -27,12 +30,6 @@ module Alchemy
it "returns only page with this page layout" do
get :index, params: {page_layout: 'news', format: :json}

expect(response.status).to eq(200)
expect(response.media_type).to eq('application/json')

result = JSON.parse(response.body)

expect(result).to have_key('pages')
expect(result['pages'].size).to eq(1)
end
end
Expand All @@ -41,12 +38,6 @@ module Alchemy
it "returns all pages" do
get :index, params: {page_layout: '', format: :json}

expect(response.status).to eq(200)
expect(response.media_type).to eq('application/json')

result = JSON.parse(response.body)

expect(result).to have_key('pages')
expect(result['pages'].size).to eq(2)
end
end
Expand All @@ -59,13 +50,42 @@ module Alchemy
it "returns all pages" do
get :index, params: {format: :json}

expect(response.status).to eq(200)
expect(response.media_type).to eq('application/json')
expect(result['pages'].size).to eq(Alchemy::Page.count)
end
end

result = JSON.parse(response.body)
it 'includes meta data' do
get :index, params: { format: :json }

expect(result).to have_key('pages')
expect(result['pages'].size).to eq(Alchemy::Page.count)
expect(result['pages'].size).to eq(2)
expect(result['meta']['page']).to be_nil
expect(result['meta']['per_page']).to eq(2)
expect(result['meta']['total_count']).to eq(2)
end

context 'with page param given' do
let!(:page1) { create(:alchemy_page) }
let!(:page2) { create(:alchemy_page) }

before do
expect(Kaminari.config).to receive(:default_per_page).at_least(:once) { 1 }
end

it 'returns paginated result' do
get :index, params: { page: 2, format: :json }

expect(result['pages'].size).to eq(1)
expect(result['meta']['page']).to eq(2)
expect(result['meta']['per_page']).to eq(1)
expect(result['meta']['total_count']).to eq(2)
end
end

context 'with ransack query param given' do
it 'returns filtered result' do
get :index, params: { q: { name_eq: page.name }, format: :json }

expect(result['pages'].size).to eq(1)
end
end
end
Expand Down
10 changes: 10 additions & 0 deletions spec/dummy/config/initializers/active_record_query_trace.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
if Rails.env.development?
require 'active_record_query_trace'
ActiveRecordQueryTrace.enabled = true
ActiveRecordQueryTrace.level = :custom
ActiveRecordQueryTrace.backtrace_cleaner = ->(trace) do
trace.reject do |line|
line =~ /\b(active_record_query_trace|active_support|active_record|rack-mini-profiler)\b/
end
end
end

0 comments on commit 71ee31a

Please sign in to comment.