具有友好 ID 的 ActiveAdmin

问题描述 投票:0回答:7

我在 Rails 4 应用程序中使用

friendly_id
slug
。现在我正在使用 active_admin gem

问题:

当我单击来自活动管理员的

Group
资源的显示链接时,它抛出以下异常:

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

我想,我需要重写一些

active_admin
默认功能?

ruby-on-rails ruby ruby-on-rails-4 ruby-on-rails-5 activeadmin
7个回答
30
投票

在某些情况下,当应用程序退出一些资源时,为了保持干燥,有一个很好的解决方案,需要整个应用程序的几行代码 - 只需覆盖 activeadmin 的资源控制器。

创建包含以下内容的

config/initializers/active_admin_monkey_patching.rb
文件:

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

不要忘记重新启动服务器。


21
投票

@AndreyDeineko 的更好方法是重写

ActiveAdmin::ResourceController
find_resource
config/initialisers/active_admin.rb
方法并利用FriendlyId 提供的方法(此时为 5.x):

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

这对我来说看起来比把它放在应用程序控制器中干净得多,因为它与 Active Admin 的配置有关。


6
投票

找到问题的解决方案:

在您的

app/admin/[ResourceName.rb]
中添加:

  # 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

这解决了我的问题。


1
投票

如果您尝试过这里的一些其他答案并得到了

uninitialized constant InheritedResources::Base (NameError)

那么你可能会考虑猴子补丁

FriendlyId
而不是
ActiveAdmin
。创建一个新的初始化文件
config/initializers/friendly_id_monkey_patch.rb
包含以下内容:

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

现在您的所有

FriendlyId
模型将恢复为在 ActiveAdmin 中使用其 ID 以及在其他地方使用其 slug。

另请参阅这个答案,它执行相同的操作,但仅针对一个模型(而不是对所有

FriendlyId
模型进行猴子修补)


0
投票
  class User < ActiveRecord::Base
     extend FriendlyId
  friendly_id :username, :use => [:slugged, :finders]

0
投票

恕我直言,正如大多数答案所暗示的那样,完全覆盖

find_resource
并不是最理想的。最好在前面添加一个模块并调用
super
,在不使用FriendlyId 时保留正常行为。作为参考,您可以检查该方法目前(截至撰写本文时)是如何实现的,它并不像人们想象的那样简单:
https://github.com/activeadmin/activeadmin/blob/b45b1fb05af9a7f6c5e2be94f61cf4a5f60ff3bb/lib/active_admin/resource_controller/data_access.rb#L104
scoped_collection.find(params[:id])



0
投票

如果您看到

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

错误,请将您的

uninitialized constant InheritedResources::Base (NameError)
块放入
class_eval
中的
after_initialize
块内。
config/initializers/active_admin.rb

这是有效的,因为它会在 Rails 初始化之后覆盖 
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

,而不是在其他类尚未加载时覆盖它。

    

© www.soinside.com 2019 - 2024. All rights reserved.