Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Page api pagination #1672

Merged
merged 7 commits into from
Nov 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 .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