administrate icon indicating copy to clipboard operation
administrate copied to clipboard

Kaminari pagination conflict with installed gem

Open dvodvo opened this issue 4 years ago • 16 comments

  • What were you trying to do?

Getting started. After rails generate administrate:install I re-started the server and went straight to http://localhost:3000/admin

  • What did you end up with (logs, or, even better, example apps are great!)?
NoMethodError in Admin::UsersController#index
undefined method `per' for #<User::ActiveRecord_Relation:0x00007fddea0db1f8> 
resources = resources.page(params[:page]).per(records_per_page)

Now the stack trace, which follows, has one line (the second) which is bothersome: administrate (0.14.0) app/controllers/administrate/application_controller.rb:12:in 'index' there is no administrate directory in the app/controllers directory; the classes under Admin::ApplicationController are present in a directory called admin which is consistent with what https://administrate-prototype.herokuapp.com/getting_started the getting started guide indicates. If I change that directory to 'administrate' (out of sheer curiosity) and restart the server, the error becomes:

Routing Error
uninitialized constant Admin

returning the output of rake:routes and, as expected, the top line is /admin/users(.:format)

  • What versions are you running?
    • Rails 6.0.4
    • gem 'administrate', '~> 0.14.0'

Stack trace:

activerecord (6.0.3.4) lib/active_record/relation/delegation.rb:109:in `method_missing'
administrate (0.14.0) app/controllers/administrate/application_controller.rb:12:in `index'
actionpack (6.0.3.4) lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
actionpack (6.0.3.4) lib/abstract_controller/base.rb:195:in `process_action'
actionpack (6.0.3.4) lib/action_controller/metal/rendering.rb:30:in `process_action'
actionpack (6.0.3.4) lib/abstract_controller/callbacks.rb:42:in `block in process_action'
activesupport (6.0.3.4) lib/active_support/callbacks.rb:135:in `run_callbacks'
actionpack (6.0.3.4) lib/abstract_controller/callbacks.rb:41:in `process_action'
actionpack (6.0.3.4) lib/action_controller/metal/rescue.rb:22:in `process_action'
actionpack (6.0.3.4) lib/action_controller/metal/instrumentation.rb:33:in `block in process_action'
activesupport (6.0.3.4) lib/active_support/notifications.rb:180:in `block in instrument'
activesupport (6.0.3.4) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport (6.0.3.4) lib/active_support/notifications.rb:180:in `instrument'
actionpack (6.0.3.4) lib/action_controller/metal/instrumentation.rb:32:in `process_action'
actionpack (6.0.3.4) lib/action_controller/metal/params_wrapper.rb:245:in `process_action'
activerecord (6.0.3.4) lib/active_record/railties/controller_runtime.rb:27:in `process_action'
actionpack (6.0.3.4) lib/abstract_controller/base.rb:136:in `process'
actionview (6.0.3.4) lib/action_view/rendering.rb:39:in `process'
actionpack (6.0.3.4) lib/action_controller/metal.rb:190:in `dispatch'
actionpack (6.0.3.4) lib/action_controller/metal.rb:254:in `dispatch'
actionpack (6.0.3.4) lib/action_dispatch/routing/route_set.rb:50:in `dispatch'
actionpack (6.0.3.4) lib/action_dispatch/routing/route_set.rb:33:in `serve'
actionpack (6.0.3.4) lib/action_dispatch/journey/router.rb:49:in `block in serve'
actionpack (6.0.3.4) lib/action_dispatch/journey/router.rb:32:in `each'
actionpack (6.0.3.4) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (6.0.3.4) lib/action_dispatch/routing/route_set.rb:834:in `call'
warden (1.2.9) lib/warden/manager.rb:36:in `block in call'
warden (1.2.9) lib/warden/manager.rb:34:in `catch'
warden (1.2.9) lib/warden/manager.rb:34:in `call'
rack (2.2.3) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.3) lib/rack/etag.rb:27:in `call'
rack (2.2.3) lib/rack/conditional_get.rb:27:in `call'
rack (2.2.3) lib/rack/head.rb:12:in `call'
actionpack (6.0.3.4) lib/action_dispatch/http/content_security_policy.rb:18:in `call'
rack (2.2.3) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.3) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/cookies.rb:648:in `call'
activerecord (6.0.3.4) lib/active_record/migration.rb:567:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (6.0.3.4) lib/active_support/callbacks.rb:101:in `run_callbacks'
actionpack (6.0.3.4) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/debug_exceptions.rb:32:in `call'
web-console (4.1.0) lib/web_console/middleware.rb:132:in `call_app'
web-console (4.1.0) lib/web_console/middleware.rb:28:in `block in call'
web-console (4.1.0) lib/web_console/middleware.rb:17:in `catch'
web-console (4.1.0) lib/web_console/middleware.rb:17:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
railties (6.0.3.4) lib/rails/rack/logger.rb:37:in `call_app'
railties (6.0.3.4) lib/rails/rack/logger.rb:26:in `block in call'
activesupport (6.0.3.4) lib/active_support/tagged_logging.rb:80:in `block in tagged'
activesupport (6.0.3.4) lib/active_support/tagged_logging.rb:28:in `tagged'
activesupport (6.0.3.4) lib/active_support/tagged_logging.rb:80:in `tagged'
railties (6.0.3.4) lib/rails/rack/logger.rb:26:in `call'
sprockets-rails (3.2.2) lib/sprockets/rails/quiet_assets.rb:13:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/request_id.rb:27:in `call'
rack (2.2.3) lib/rack/method_override.rb:24:in `call'
rack (2.2.3) lib/rack/runtime.rb:22:in `call'
activesupport (6.0.3.4) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/static.rb:126:in `call'
rack (2.2.3) lib/rack/sendfile.rb:110:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/host_authorization.rb:82:in `call'
webpacker (4.3.0) lib/webpacker/dev_server_proxy.rb:23:in `perform_request'
rack-proxy (0.6.5) lib/rack/proxy.rb:57:in `call'
railties (6.0.3.4) lib/rails/engine.rb:527:in `call'
puma (4.3.6) lib/puma/configuration.rb:228:in `call'
puma (4.3.6) lib/puma/server.rb:713:in `handle_request'
puma (4.3.6) lib/puma/server.rb:472:in `process_client'
puma (4.3.6) lib/puma/server.rb:328:in `block in run'
puma (4.3.6) lib/puma/thread_pool.rb:134:in `block in spawn_thread'
Started POST "/__web_console/repl_sessions/fd1d9455a2e7cee208d6f5bb37f68bd9/trace" for ::1 at 2020-12-03 16:24:23 +0100

dvodvo avatar Dec 03 '20 15:12 dvodvo

Worry not: app/controllers/administrate/application_controller.rb is not expected to be in your application. Instead it's provided by Administrate. It's ok that you don't see it.

The error about per suggests that the problem is with pagination. Is your app using a pagination gem? Administrate uses Kaminari, and this is known to cause incompatibilities with others.

pablobm avatar Dec 03 '20 16:12 pablobm

Yes, I do not use Kaminari, but will_paginate

dvodvo avatar Dec 03 '20 16:12 dvodvo

OK. I'm afraid this is a known bug that we need to look into, and see how we can incorporate pagination in a way that doesn't interfere with other people's gem choices. I did some surface research some time ago and it didn't look simple. We may need to try again.

Of course, ideas, feedback, and contributions are welcome on this front.

pablobm avatar Dec 03 '20 16:12 pablobm

Announce the colours on the getting started page for starters ( ;-) ). At present, this means adopting Kaminari to be able to run Administrate; this is not necessarily a big hurdle, but needs to be stated (if the adminsitration functions are required, odds are the application may be big enough (il calsses and records) that pagination is de facto.

The only thing that comes to mind is seperating out the views from the search/split logic, allowing dev to edit a directory of partials that respond to the pagination method with what the gem offers. possibly a sub-directory named that of the installed gem?

Cheers!

dvodvo avatar Dec 03 '20 16:12 dvodvo

Let's leave this open. It's actually a bug, and we should address it at some point. Your suggestion does have merit. I'll bear it in mind when I try again.

pablobm avatar Dec 03 '20 16:12 pablobm

OK. I have updated the title to better reflect the issue, for readers's sake.

dvodvo avatar Dec 03 '20 17:12 dvodvo

I'd add to this. I am in the middle of trying to solve this same bug. We use Pagy and we implemented Administrate. AFTER being somewhat committed, and gotten some data in our system.. only now do we realize that we can't paginate. Had we known from the get-go that Kaminari to the exclusion of others was a hard requirement, we'd likely have gone a different way.

wflanagan avatar Feb 22 '21 18:02 wflanagan

We use pagy in our main app and Administrate still works fine with Kaminari for the admin dashboards. I can't remember if something was configured somewhere for this to work. Using Administrate 0.14.0.

NB: we have separate application controllers for the main app (ApplicationController < ActionController::Base) and the admin dashboard (Admin::ApplicationController < Administrate::ApplicationController). Pagy is only loaded in the former using include Pagy::Backend.

sedubois avatar Feb 23 '21 08:02 sedubois

It would be nice to be able to configure the pagination by overriding the Administrate::ApplicationController. I use Kaminari but with a custom page_method_name method.

Ex:

module Administrate
  class ApplicationController < ActionController::Base
    protect_from_forgery with: :exception

    def index
      authorize_resource(resource_class)
      search_term = params[:search].to_s.strip
      resources = filter_resources(scoped_resource, search_term: search_term)
      resources = apply_collection_includes(resources)
      resources = order.apply(resources)
-      resources = resources.page(params[:_page]).per(records_per_page)
+      resources = paginate_resources(resources, params[:_page], record_per_page)
      page = Administrate::Page::Collection.new(dashboard, order: order)

      render locals: {
        resources: resources,
        search_term: search_term,
        page: page,
        show_search_bar: show_search_bar?,
      }
    end
    
    # ...
    
+    protected
+    
+    def paginate_resources(resources, record_page, record_per_page)
+      resources.page(record_page).per(record_per_page)
+    end

    private
    
    # ...
  end
end
class Admin::ApplicationController < Administrate::ApplicationController
  def paginate_resource(scope)
    # Custom pagination.
  end
end

masterT avatar Mar 30 '22 18:03 masterT

@masterT - That looks like a worthy PR. We have had similar ones in the past (eg: https://github.com/thoughtbot/administrate/pull/2096). Would you want to contribute one?

pablobm avatar Apr 14 '22 14:04 pablobm

Sure, you can assign me, I'll draft a PR. 😊

masterT avatar Apr 14 '22 18:04 masterT

@masterT - Your proposal has been implemented at https://github.com/thoughtbot/administrate/pull/2216

pablobm avatar Jul 21 '22 09:07 pablobm

Awesome! 🙌🏻

masterT avatar Jul 21 '22 10:07 masterT

Hi any good idea for has_many pagination?

jubilee2 avatar Jan 20 '23 05:01 jubilee2

@jubilee2 - What do you want to do? Would overriding https://github.com/thoughtbot/administrate/blob/main/lib/administrate/field/has_many.rb#L59 help?

pablobm avatar Jan 26 '23 14:01 pablobm

finally i found this solution maybe you can add into document https://github.com/jubilee2/pushvendor/blob/books/config/initializers/will_paginate.rb

jubilee2 avatar Jan 26 '23 14:01 jubilee2