我最近在一个项目中开始使用ActiveAdmin,几乎所有东西都运行良好但是在将它与friendly_id gem结合使用时遇到了问题。我正在为我的表单[我相信]抛出ActiveRecord :: ReadOnlyRecord,因为friendly_id属性的ID是只读的:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"Rc5PmUYZt3BiLvfPQr8iCPPXlbfgjoe/n+NhCwXazNs=",
"space"=>{"name"=>"The Kosmonaut",
"address"=>"8 Sichovykh Striltsiv 24",
"email"=>"info@somedomain.com"},
"commit"=>"Update Space",
"id"=>"the-kosmonaut"} <--- culprit
我猜最后一行是罪魁祸首,因为它是一个只读属性,它不是我的形式,而是在PATH中
http://localhost:5000/manage/spaces/the-kosmonaut/edit
如何通过尝试更新ID来解决此问题?
ActiveAdmin中的表单如下所示:
form do |f|
f.inputs "Details" do
f.input :name
f.input :address
f.input :email
f.input :phone
f.input :website
end
f.inputs "Content" do
f.input :description
f.input :blurb
end
f.buttons
end
更新:这不起作用,所以它不是friendly_id?
我尝试使用@ watson的建议本应该有效,但仍然有同样的错误; - (
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"Rc5PmUYZt3BiLvfPQr8iCPPXlbfgjoe/n+NhCwXazNs=",
"space"=>{"name"=>"The Kosmonaut 23"},
"commit"=>"Update Space",
"id"=>"6933"}
http://localhost:5000/manage/spaces/6933/edit
当我用record.readonly检查控制台中的记录时?它返回false
UPDATE UPDATE:删除scope_to可以解决问题。
scope_to :current_user, :unless => proc{ current_user.admin? }
唯一的问题是我需要使用scope_to来防止用户看到他们不拥有的记录。我的猜测是(因为我假设scope_to通常与has_many一起使用)我的HABTM关联会导致一些奇怪吗?即用户&lt; - HABTM - &gt;空间?
答案 0 :(得分:28)
如果您只想在前端使用友好ID,而在Active Admin中不关心它们,则可以为您的Active Admin控制器恢复friendly_id gem的效果。
我不确切知道friendly_id如何覆盖to_param
方法,但如果它以正常方式执行,则在所有Active Admin控制器中重新覆盖它应该修复它,例如:
ActiveAdmin.register Foobar do
before_filter do
Foobar.class_eval do
def to_param
id.to_s
end
end
end
end
更好的是,您可以在基本Active Admin控制器ActiveAdmin::ResourceController
中创建一个前置过滤器,以便它自动继承到所有Active Admin控制器中。
首先将过滤器添加到config/initializers/active_admin.rb
设置:
ActiveAdmin.setup do |config|
# ...
config.before_filter :revert_friendly_id
end
开放ActiveAdmin::ResourceController
并添加revert_friendly_id
方法,例如将以下内容添加到config/initializers/active_admin.rb
的末尾:
ActiveAdmin::ResourceController.class_eval do
protected
def revert_friendly_id
model_name = self.class.name.match(/::(.*)Controller$/)[1].singularize
# Will throw a NameError if the class does not exist
Module.const_get model_name
eval(model_name).class_eval do
def to_param
id.to_s
end
end
rescue NameError
end
end
更新:我刚刚更新了最后一个代码示例来处理没有相关模型的控制器(例如Active Admin Dashboard控制器)
更新2:我刚尝试将上述hack与friendly_id gem一起使用,它似乎工作正常:)
更新3:清除代码以使用在过滤器添加到基本控制器之前添加Active Admin的标准方式
答案 1 :(得分:16)
您可以根据http://activeadmin.info/docs/2-resource-customization.html#customizing_resource_retrieval自定义资源检索。请注意,您要使用find_resource
方法而不是resource
,否则您将无法创建新记录。
在ActiveAdmin资源类中写:
controller do
def find_resource
scoped_collection.where(slug: params[:id]).first!
end
end
您还可以通过在active_admin.rb
初始值设定项中修改ResourceController来覆盖所有资源的行为。
ActiveAdmin::ResourceController.class_eval do
def find_resource
if scoped_collection.is_a? FriendlyId
scoped_collection.where(slug: params[:id]).first!
else
scoped_collection.where(id: params[:id]).first!
end
end
end
希望有所帮助!
附注:通过管理界面创建新记录时,请确保不在表单中包含slug字段,否则FriendlyId将不会生成slug。 (我相信仅适用于5+版本)
答案 2 :(得分:4)
这种方法适合我。在app / admin / model_name.rb中添加此代码
ActiveAdmin.register model_name do
controller do
defaults finder: :find_by_slug
end
end
答案 3 :(得分:2)
要添加到Denny's solution,更友好的解决方案是使用friendly_id的查找器。
controller do
def find_resource
scoped_collection.friendly.find_by_friendly_id(params[:id])
end
end
答案 4 :(得分:1)
以下是基于@Thomas解决方案的解决方案
ActiveAdmin.setup do |config|
# ...
config.before_filter :revert_friendly_id, :if => -> { !devise_controller? && resource_controller? }
end
# override #to_param method defined in model in order to make AA generate
# routes like /admin/page/:id/edit
ActiveAdmin::BaseController.class_eval do
protected
def resource_controller?
self.class.superclass.name == "ActiveAdmin::ResourceController"
end
def revert_friendly_id
model_name = self.class.name.match(/::(.*)Controller$/)[1].singularize
# Will throw a NameError if the class does not exist
Module.const_get model_name
eval(model_name).class_eval do
def to_param
id.to_s
end
end
rescue NameError
end
end