12

I am using friendly_id in my rails 4 application with slug. Now I am using active_admin gem.

Problem:

When I click on show link from active admin for Group resource, It is throwing the following exception:

ActiveRecord::RecordNotFound at /admin/groups/username20-s-group-1

I guess, I need to override some of the active_admin default functions?

Andrey Deineko
  • 51,333
  • 10
  • 112
  • 145
przbadu
  • 5,769
  • 5
  • 42
  • 67

6 Answers6

30

There are cases, when application has quit a few resources, hence in order to keep it DRY there is a nice solution requiring few lines of code for whole application - simply override activeadmin's resource controller.

Create config/initializers/active_admin_monkey_patching.rb file with the following content:

ActiveAdmin::ResourceController.class_eval do
  def find_resource
    finder = resource_class.is_a?(FriendlyId) ? :slug : :id
    scoped_collection.find_by(finder => params[:id])
  end
end

Do not forget to restart the server.

Dorian
  • 7,749
  • 4
  • 38
  • 57
Andrey Deineko
  • 51,333
  • 10
  • 112
  • 145
21

A better approach to @AndreyDeineko's is to override ActiveAdmin::ResourceController's find_resource method in config/initialisers/active_admin.rb and leverage the methods provided by FriendlyId (5.x at this point):

In config/initialisers/active_admin.rb:

ActiveAdmin.setup do |config|
  # == Friendly Id addon
  ActiveAdmin::ResourceController.class_eval do
    def find_resource
      if resource_class.is_a?(FriendlyId)
        scoped_collection.friendly.find(params[:id])
      else
        scoped_collection.find(params[:id])
      end
    end
  end
  # initial config
end

This looks much cleaner to me, than putting it in the application controller, as it is related to the configuration of Active Admin.

Dorian
  • 7,749
  • 4
  • 38
  • 57
Quentin
  • 1,854
  • 1
  • 19
  • 19
  • 1
    Getting problem with starting Puma: `=> Booting Puma => Rails 7.0.4 application starting in development => Run 'bin/rails server --help' for more startup options Exiting [...]/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activeadmin-2.13.1/lib/active_admin/base_controller/authorization.rb:3:in '': uninitialized constant InheritedResources::Base (NameError) class BaseController < ::InheritedResources::Base ^^^^^^ Did you mean? Base64` any ideas? – Jens Schmidt Sep 29 '22 at 19:36
  • 1
    @JensSchmidt Happy to see I'm not the only one. I may be a bit late to this party, but I believe I've found a workaround to that particular issue: https://stackoverflow.com/a/74916805/2288659 – Silvio Mayolo Dec 26 '22 at 01:53
6

Found solution for the problem:

In your app/admin/[ResourceName.rb] add:

  # app/admin/group.rb

  # find record with slug(friendly_id)
  controller do
    def find_resource
      begin
        scoped_collection.where(slug: params[:id]).first!
      rescue ActiveRecord::RecordNotFound
        scoped_collection.find(params[:id])
      end
    end
  end

This solved my problem.

przbadu
  • 5,769
  • 5
  • 42
  • 67
1

If you've tried some of the other answers here and gotten

uninitialized constant InheritedResources::Base (NameError)

Then you might consider monkey patching FriendlyId rather than ActiveAdmin. Create a new initializer file config/initializers/friendly_id_monkey_patch.rb containing this:

module FriendlyIdModelMonkeyPatch

  def to_param
    if caller.to_s.include? 'active_admin'
      id&.to_s
    else
      super
    end
  end

end

module FriendlyId::Model
  prepend FriendlyIdModelMonkeyPatch
end

Now all of your FriendlyId models will revert to using their ID in ActiveAdmin and their slug everywhere else.

See also this answer, which does the same thing but for only one model (rather than monkey patching for all FriendlyId models)

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
0
  class User < ActiveRecord::Base
     extend FriendlyId
  friendly_id :username, :use => [:slugged, :finders]
obi1kinobi
  • 41
  • 1
  • 2
  • 8
0

IMHO, it's suboptimal to completely override the find_resource as most of the answers suggest. Better to prepend a module and call super preserving normal behaviour when FriendlyId is not in use. For reference you can check how this method is currently (as of writing) implemented, it is not simply scoped_collection.find(params[:id]) as one might think: https://github.com/activeadmin/activeadmin/blob/b45b1fb05af9a7f6c5e2be94f61cf4a5f60ff3bb/lib/active_admin/resource_controller/data_access.rb#L104

module ActiveAdminFriendlyIdScoping
  def find_resource
    if resource_class.is_a? FriendlyId
      scoped_collection.friendly.find params[:id]
      # Or potentially even
      # scoped_collection.friendly.send method_for_find, params[:id]
      # Or you could do something like this
      # raise "Using FriendlyId, find method configuration ignored" if method_for_find != :find
    else
      super
    end
  end
end

ActiveAdmin.setup do |config|
  #...
  Rails.application.config.to_prepare do
    ActiveAdmin::ResourceController.prepend(ActiveAdminFriendlyIdScoping)
  end
end
Timo
  • 3,335
  • 30
  • 25