我在 Rails 4 应用程序中使用
friendly_id
和 slug
。现在我正在使用 active_admin gem。
问题:
当我单击来自活动管理员的
Group
资源的显示链接时,它抛出以下异常:
ActiveRecord::RecordNotFound at /admin/groups/username20-s-group-1
我想,我需要重写一些
active_admin
默认功能?
在某些情况下,当应用程序退出一些资源时,为了保持干燥,有一个很好的解决方案,需要整个应用程序的几行代码 - 只需覆盖 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
不要忘记重新启动服务器。
@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 的配置有关。
找到问题的解决方案:
在您的
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
这解决了我的问题。
如果您尝试过这里的一些其他答案并得到了
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
模型进行猴子修补)
class User < ActiveRecord::Base
extend FriendlyId
friendly_id :username, :use => [:slugged, :finders]
恕我直言,正如大多数答案所暗示的那样,完全覆盖
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])
如果您看到
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
,而不是在其他类尚未加载时覆盖它。