ActiveAdmin with friendly id
Asked Answered
S

7

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?

Subbase answered 20/11, 2014 at 6:9 Comment(0)
C
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.

Cantonment answered 20/11, 2014 at 7:27 Comment(2)
I think it has to be added in config/intializers/active_admin.rb . Worked for me when I added it there. Friendly_id - 5.1Commorant
Shouldn't matter which initializer it gets added in.Symphonious
I
22

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.

Iormina answered 20/11, 2015 at 11:49 Comment(2)
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 '<module:ActiveAdmin>': uninitialized constant InheritedResources::Base (NameError) class BaseController < ::InheritedResources::Base ^^^^^^ Did you mean? Base64 any ideas?Mashe
@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://mcmap.net/q/888095/-activeadmin-with-friendly-idLai
S
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.

Subbase answered 20/11, 2014 at 7:2 Comment(0)
L
2

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)

Lai answered 26/12, 2022 at 1:52 Comment(0)
E
1

Really late to the party here, but we were struggling recently with this in a Rails 7.0 app and I wanted to share our fix.

If you see the uninitialized constant InheritedResources::Base (NameError) error, put your class_eval block inside an after_initialize block in config/initializers/active_admin.rb.

Rails.application.configure do
  config.after_initialize do
    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
  end
end

This works because it will overwrite #find_resource after Rails has initialized instead of in the middle of it while other classes have not loaded yet.

Elamite answered 4/10, 2023 at 17:54 Comment(0)
S
0
  class User < ActiveRecord::Base
     extend FriendlyId
  friendly_id :username, :use => [:slugged, :finders]
Swan answered 6/2, 2017 at 3:26 Comment(0)
D
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
Disconnection answered 22/8, 2022 at 5:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.