diff --git a/app/controllers/administrate/application_controller.rb b/app/controllers/administrate/application_controller.rb
index f07a01575326ea64c8554e5d2e1d5ea0478ef08f..e81454a92f7af3fb04ea986baf1313249bfcfebd 100644
--- a/app/controllers/administrate/application_controller.rb
+++ b/app/controllers/administrate/application_controller.rb
@@ -9,7 +9,7 @@ module Administrate
                                            search_term).run
       resources = apply_collection_includes(resources)
       resources = order.apply(resources)
-      resources = resources.page(params[:page]).per(records_per_page)
+      resources = resources.page(params[:_page]).per(records_per_page)
       page = Administrate::Page::Collection.new(dashboard, order: order)
 
       render locals: {
@@ -105,10 +105,7 @@ module Administrate
     end
 
     def sorting_attribute
-      params.fetch(resource_name, {}).fetch(
-        :order,
-        default_sorting_attribute,
-      )
+      sorting_params.fetch(:order) { default_sorting_attribute }
     end
 
     def default_sorting_attribute
@@ -116,16 +113,17 @@ module Administrate
     end
 
     def sorting_direction
-      params.fetch(resource_name, {}).fetch(
-        :direction,
-        default_sorting_direction,
-      )
+      sorting_params.fetch(:direction) { default_sorting_direction }
     end
 
     def default_sorting_direction
       nil
     end
 
+    def sorting_params
+      Hash.try_convert(request.query_parameters[resource_name]) || {}
+    end
+
     def dashboard
       @dashboard ||= dashboard_class.new
     end
diff --git a/app/helpers/administrate/application_helper.rb b/app/helpers/administrate/application_helper.rb
index 79b9e37eb2d56868242f71baa1ef39843c98ef73..d02ff069d6021d25a8f35bd7950ef4cd80d0f6e5 100644
--- a/app/helpers/administrate/application_helper.rb
+++ b/app/helpers/administrate/application_helper.rb
@@ -70,11 +70,11 @@ module Administrate
       association_params = collection_names.map do |assoc_name|
         { assoc_name => %i[order direction page per_page] }
       end
-      params.permit(:search, :id, :page, :per_page, association_params)
+      params.permit(:search, :id, :_page, :per_page, association_params)
     end
 
     def clear_search_params
-      params.except(:search, :page).permit(
+      params.except(:search, :_page).permit(
         :per_page, resource_name => %i[order direction]
       )
     end
diff --git a/app/views/administrate/application/index.html.erb b/app/views/administrate/application/index.html.erb
index 80a5ae24c8864ac0491f521353902ff1f0dad4f8..5e1796ef8f4c504b95c1d7ecc10ae427a5233c58 100644
--- a/app/views/administrate/application/index.html.erb
+++ b/app/views/administrate/application/index.html.erb
@@ -62,5 +62,5 @@ It renders the `_table` partial to display details about the resources.
     table_title: "page-title"
   ) %>
 
-  <%= paginate resources %>
+  <%= paginate resources, param_name: '_page' %>
 </section>
diff --git a/spec/example_app/app/controllers/admin/pages_controller.rb b/spec/example_app/app/controllers/admin/pages_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..38e505daba00b26d570045b61d9578b27797d8a2
--- /dev/null
+++ b/spec/example_app/app/controllers/admin/pages_controller.rb
@@ -0,0 +1,4 @@
+module Admin
+  class PagesController < Admin::ApplicationController
+  end
+end
diff --git a/spec/example_app/app/dashboards/page_dashboard.rb b/spec/example_app/app/dashboards/page_dashboard.rb
new file mode 100644
index 0000000000000000000000000000000000000000..049fd0113a238b2ff7be672866c2ce1728d2035e
--- /dev/null
+++ b/spec/example_app/app/dashboards/page_dashboard.rb
@@ -0,0 +1,34 @@
+require "administrate/base_dashboard"
+
+class PageDashboard < Administrate::BaseDashboard
+  ATTRIBUTE_TYPES = {
+    product: Field::BelongsTo,
+    id: Field::Number,
+    title: Field::String,
+    body: Field::Text,
+    created_at: Field::DateTime,
+    updated_at: Field::DateTime,
+  }.freeze
+
+  COLLECTION_ATTRIBUTES = %i[
+    id
+    title
+  ].freeze
+
+  SHOW_PAGE_ATTRIBUTES = %i[
+    product
+    id
+    title
+    body
+    created_at
+    updated_at
+  ].freeze
+
+  FORM_ATTRIBUTES = %i[
+    product
+    title
+    body
+  ].freeze
+
+  COLLECTION_FILTERS = {}.freeze
+end
diff --git a/spec/example_app/app/dashboards/product_dashboard.rb b/spec/example_app/app/dashboards/product_dashboard.rb
index bf89c5272be15e40409a655d2f6ad0b5398838f4..9287b65a24ffcfe16048b695de33eb7043243a78 100644
--- a/spec/example_app/app/dashboards/product_dashboard.rb
+++ b/spec/example_app/app/dashboards/product_dashboard.rb
@@ -3,6 +3,7 @@ require "administrate/base_dashboard"
 class ProductDashboard < Administrate::BaseDashboard
   ATTRIBUTES = [
     :name,
+    :pages,
     :price,
     :description,
     :image_url,
@@ -16,6 +17,7 @@ class ProductDashboard < Administrate::BaseDashboard
     description: Field::Text,
     image_url: Field::Url,
     name: Field::String,
+    pages: Field::HasMany,
     price: Field::Number.with_options(prefix: "$", decimals: 2),
     product_meta_tag: Field::HasOne,
     release_year: Field::Select.with_options(
diff --git a/spec/example_app/app/models/page.rb b/spec/example_app/app/models/page.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a4a3058aa9d61e8fecac662767e6c2c1dd01c851
--- /dev/null
+++ b/spec/example_app/app/models/page.rb
@@ -0,0 +1,3 @@
+class Page < ApplicationRecord
+  belongs_to :product
+end
diff --git a/spec/example_app/app/models/product.rb b/spec/example_app/app/models/product.rb
index 35dc9e673cda4f0d1acc8bd506b438d5cedeac8e..3df36e60378c004d761b07805173cd93e8e04acd 100644
--- a/spec/example_app/app/models/product.rb
+++ b/spec/example_app/app/models/product.rb
@@ -8,6 +8,7 @@ class Product < ApplicationRecord
   end
 
   has_many :line_items, dependent: :destroy
+  has_many :pages, dependent: :destroy
   has_one :product_meta_tag, dependent: :destroy
 
   validates :description, presence: true
diff --git a/spec/example_app/app/policies/page_policy.rb b/spec/example_app/app/policies/page_policy.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7d681ef3d27a96604455bfee3b0c428ab0642bfe
--- /dev/null
+++ b/spec/example_app/app/policies/page_policy.rb
@@ -0,0 +1,2 @@
+class PagePolicy < ApplicationPolicy
+end
diff --git a/spec/example_app/config/routes.rb b/spec/example_app/config/routes.rb
index 98123b7953c6bcdae53429a00842a800fcaa98c7..7c08884f650527632da91fdf765051357ad8fda0 100644
--- a/spec/example_app/config/routes.rb
+++ b/spec/example_app/config/routes.rb
@@ -4,6 +4,7 @@ Rails.application.routes.draw do
     resources :line_items
     resources :log_entries
     resources :orders
+    resources :pages
     resources :products
     resources :product_meta_tags, except: [:index]
     resources :payments, only: [:index, :show]
diff --git a/spec/example_app/db/migrate/20200714081950_create_pages.rb b/spec/example_app/db/migrate/20200714081950_create_pages.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7eb89915117b93feec8452ef3c45b5561b601065
--- /dev/null
+++ b/spec/example_app/db/migrate/20200714081950_create_pages.rb
@@ -0,0 +1,11 @@
+class CreatePages < ActiveRecord::Migration[6.0]
+  def change
+    create_table :pages do |t|
+      t.string :title
+      t.text :body
+      t.belongs_to :product, foreign_key: true
+
+      t.timestamps
+    end
+  end
+end
diff --git a/spec/example_app/db/schema.rb b/spec/example_app/db/schema.rb
index 0608b17e424ed73e6925121b83f4ca3422452400..308929609feaceb428493efa7ccb9ff132113f6f 100644
--- a/spec/example_app/db/schema.rb
+++ b/spec/example_app/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2020_03_26_202615) do
+ActiveRecord::Schema.define(version: 2020_07_14_081950) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -77,6 +77,15 @@ ActiveRecord::Schema.define(version: 2020_03_26_202615) do
     t.index ["customer_id"], name: "index_orders_on_customer_id"
   end
 
+  create_table "pages", force: :cascade do |t|
+    t.string "title"
+    t.text "body"
+    t.bigint "product_id"
+    t.datetime "created_at", precision: 6, null: false
+    t.datetime "updated_at", precision: 6, null: false
+    t.index ["product_id"], name: "index_pages_on_product_id"
+  end
+
   create_table "payments", id: :serial, force: :cascade do |t|
     t.integer "order_id"
     t.datetime "created_at", null: false
@@ -111,5 +120,6 @@ ActiveRecord::Schema.define(version: 2020_03_26_202615) do
   add_foreign_key "line_items", "orders"
   add_foreign_key "line_items", "products"
   add_foreign_key "orders", "customers"
+  add_foreign_key "pages", "products"
   add_foreign_key "payments", "orders"
 end
diff --git a/spec/example_app/db/seeds.rb b/spec/example_app/db/seeds.rb
index e7ca242210eea28e1e036cf1429466b9edb64f2b..af2b7f5893ffa1af35aa023ea3e72c4d9aeb51cf 100644
--- a/spec/example_app/db/seeds.rb
+++ b/spec/example_app/db/seeds.rb
@@ -54,6 +54,24 @@ product_attributes.each do |attributes|
   Product.create! attributes.merge(price: 20 + rand(50))
 end
 
+Product.find_each do |p|
+  Page.create!(
+    title: "Something about #{p.name}",
+    body: Faker::Lorem.paragraph,
+    product: p,
+  )
+  Page.create!(
+    title: "The secrets of the game #{p.name}",
+    body: Faker::Lorem.paragraph,
+    product: p,
+  )
+  Page.create!(
+    title: "If you liked #{p.name}, you will love these games",
+    body: Faker::Lorem.paragraph,
+    product: p,
+  )
+end
+
 customers.each do |customer|
   (1..3).to_a.sample.times do
     order = Order.create!(
diff --git a/spec/example_app/spec/features/pagination_spec.rb b/spec/example_app/spec/features/pagination_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e922649d914e62af56952df0c61b900d0dfb4eab
--- /dev/null
+++ b/spec/example_app/spec/features/pagination_spec.rb
@@ -0,0 +1,88 @@
+require "rails_helper"
+
+search_input_selector = ".search__input"
+
+RSpec.feature "Pagination", type: :feature do
+  def expect_to_appear_in_order(*elements)
+    positions = elements.map { |e| page.body.index(e) }
+    expect(positions).to eq(positions.sort)
+  end
+
+  it "paginates records based on a query param" do
+    customers = create_list(:customer, 2)
+
+    visit admin_customers_path(per_page: 1)
+
+    expect(page).not_to have_content(customers.last.name)
+    click_on "Next"
+    expect(page).to have_content(customers.last.name)
+  end
+
+  describe "sorting" do
+    it "allows sorting by columns" do
+      create(:customer, name: "unique name two")
+      create(:customer, name: "unique name one")
+
+      visit admin_customers_path
+      click_on "Name"
+
+      expect_to_appear_in_order("unique name one", "unique name two")
+    end
+
+    it "allows clicking through after sorting", :js do
+      customer = create(:customer)
+      create(:order, customer: customer)
+
+      visit admin_customers_path
+      click_on "Name"
+      find("[data-url]").click
+      expect(page).to have_header("Show #{customer.name}")
+    end
+
+    it "allows reverse sorting" do
+      create(:customer, name: "unique name one")
+      create(:customer, name: "unique name two")
+
+      visit admin_customers_path
+      2.times { click_on "Name" }
+
+      expect_to_appear_in_order("unique name two", "unique name one")
+    end
+
+    it "toggles the order" do
+      create(:customer, name: "unique name one")
+      create(:customer, name: "unique name two")
+
+      visit admin_customers_path
+      3.times { click_on "Name" }
+
+      expect_to_appear_in_order("unique name one", "unique name two")
+    end
+
+    it "preserves search" do
+      query = "bar@baz.com"
+
+      visit admin_customers_path(search: query)
+      click_on "Name"
+
+      expect(find(search_input_selector).value).to eq(query)
+    end
+  end
+
+  context "with resources of type Page" do
+    it "can paginate and sort" do
+      FactoryBot.create(:page, title: "Page 2")
+      FactoryBot.create(:page, title: "Page 4")
+      FactoryBot.create(:page, title: "Page 1")
+      FactoryBot.create(:page, title: "Page 5")
+      FactoryBot.create(:page, title: "Page 3")
+
+      visit admin_pages_path(per_page: 3)
+      click_on "Title"
+      expect_to_appear_in_order("Page 1", "Page 2", "Page 3")
+
+      click_on "Next"
+      expect_to_appear_in_order("Page 4", "Page 5")
+    end
+  end
+end
diff --git a/spec/factories.rb b/spec/factories.rb
index fd87fb2abaaa9f2ca01cb7ae6b616a10b04ba42c..82752358df29ae3efc269dd039689039fe7a0be4 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -69,4 +69,6 @@ FactoryBot.define do
     sequence(:name) { |n| "Country #{n}" }
     sequence(:code) { |n| "C#{n}" }
   end
+
+  factory :page
 end
diff --git a/spec/features/index_page_spec.rb b/spec/features/index_page_spec.rb
index faa8880cfc789cbef42fe58f3ba1df4eb2c1dccc..7bc86fc1ecfbad773c38c16bcccd83f1949d7ae7 100644
--- a/spec/features/index_page_spec.rb
+++ b/spec/features/index_page_spec.rb
@@ -68,72 +68,6 @@ describe "customer index page" do
       expect(page).to have_table_header(custom_label)
     end
   end
-
-  it "paginates records based on a constant" do
-    customers = create_list(:customer, 2)
-
-    visit admin_customers_path(per_page: 1)
-
-    expect(page).not_to have_content(customers.last.name)
-    click_on "Next"
-    expect(page).to have_content(customers.last.name)
-  end
-
-  describe "sorting" do
-    def expect_to_appear_in_order(*elements)
-      positions = elements.map { |e| page.body.index(e) }
-      expect(positions).to eq(positions.sort)
-    end
-
-    it "allows sorting by columns" do
-      create(:customer, name: "unique name two")
-      create(:customer, name: "unique name one")
-
-      visit admin_customers_path
-      click_on "Name"
-
-      expect_to_appear_in_order("unique name one", "unique name two")
-    end
-
-    it "allows clicking through after sorting", :js do
-      customer = create(:customer)
-      create(:order, customer: customer)
-
-      visit admin_customers_path
-      click_on "Name"
-      find("[data-url]").click
-      expect(page).to have_header("Show #{customer.name}")
-    end
-
-    it "allows reverse sorting" do
-      create(:customer, name: "unique name one")
-      create(:customer, name: "unique name two")
-
-      visit admin_customers_path
-      2.times { click_on "Name" }
-
-      expect_to_appear_in_order("unique name two", "unique name one")
-    end
-
-    it "toggles the order" do
-      create(:customer, name: "unique name one")
-      create(:customer, name: "unique name two")
-
-      visit admin_customers_path
-      3.times { click_on "Name" }
-
-      expect_to_appear_in_order("unique name one", "unique name two")
-    end
-
-    it "preserves search" do
-      query = "bar@baz.com"
-
-      visit admin_customers_path(search: query)
-      click_on "Name"
-
-      expect(find(search_input_selector).value).to eq(query)
-    end
-  end
 end
 
 describe "search input" do