ruby on rails - ActiveRecord:: ReadOnlyRecord cuando se usa ActiveAdmin y Friendly_id
ruby-on-rails ruby-on-rails-3 (5)
Aquí está mi solución basada en la solución @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
Comencé a usar ActiveAdmin recientemente en un proyecto y casi todo funciona bien, pero tengo un problema cuando lo uso en combinación con la gema friendly_id. Obtengo ActiveRecord :: ReadOnlyRecord para mis formularios [creo] debido al atributo friendly_id cuyo ID es de solo lectura:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"Rc5PmUYZt3BiLvfPQr8iCPPXlbfgjoe/n+NhCwXazNs=",
"space"=>{"name"=>"The Kosmonaut",
"address"=>"8 Sichovykh Striltsiv 24",
"email"=>"[email protected]"},
"commit"=>"Update Space",
"id"=>"the-kosmonaut"} <--- culprit
Supongo que la última línea es la culpable ya que es un atributo de solo lectura, no está en mi forma sino en el PATH
http://localhost:5000/manage/spaces/the-kosmonaut/edit
¿Cómo puedo solucionar esto al intentar actualizar la ID?
El formulario de ActiveAdmin se ve así:
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
ACTUALIZACIÓN: ¿Esto tampoco funciona así que no es el friendly_id?
Intenté usar la sugerencia de @ watson, que debería haber funcionado, pero aún así tuve el mismo error ;-(
{"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
Cuando reviso el registro en la consola con record.readonly? devuelve falso
ACTUALIZACIÓN ACTUALIZACIÓN: eliminando el alcance_para solucionar el problema.
scope_to :current_user, :unless => proc{ current_user.admin? }
El único problema es que necesito alcance_para evitar que los usuarios vean registros que no son de su propiedad. ¿Mi suposición es (como supongo que scope_to normalmente funciona con has_many) que mi asociación HABTM causa alguna rareza? Es decir, Usuarios <- HABTM -> ¿Espacios?
Este método funciona para mí. agrega este código en app / admin / model_name.rb
ActiveAdmin.register model_name do
controller do
defaults finder: :find_by_slug
end
end
Para agregar a la solución de Denny , una solución más "amigable" sería utilizar los buscadores de friendly_id.
controller do
def find_resource
scoped_collection.friendly.find_by_friendly_id(params[:id])
end
end
Puede personalizar la recuperación de recursos de acuerdo con http://activeadmin.info/docs/2-resource-customization.html#customizing_resource_retrieval . Tenga en cuenta que desea utilizar el método find_resource
lugar del resource
, o no podrá crear nuevos registros.
(Consulte https://github.com/gregbell/active_admin/blob/master/lib/active_admin/resource_controller/data_access.rb para obtener más detalles)
En su clase de recurso ActiveAdmin escriba:
controller do
def find_resource
scoped_collection.where(slug: params[:id]).first!
end
end
También puede sobrescribir el comportamiento de todos los recursos modificando el ResourceController en el inicializador active_admin.rb
.
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
¡Espero que ayude!
Nota al margen: al crear nuevos registros a través de la interfaz de administración, asegúrese de no incluir el campo de slug en el formulario, o FriendlyId no generará los slugs. (Creo que eso es solo para la versión 5+)
Si solo quieres IDs amigables en el extremo delantero y no te importan dentro de Active Admin, puedes revertir los efectos de la gema friendly_id para tus controladores Active Admin.
No sé exactamente cómo friendly_id reemplaza el método to_param
, pero si lo está haciendo de la manera normal, volver a reemplazarlo dentro de todos los controladores de administración activa debería solucionarlo, por ejemplo:
ActiveAdmin.register Foobar do
before_filter do
Foobar.class_eval do
def to_param
id.to_s
end
end
end
end
Aún mejor, podría crear un filtro anterior en el controlador Active Admin ActiveAdmin::ResourceController
para que se herede automáticamente en todos sus controladores Active Admin.
Primero agregue el filtro a la config/initializers/active_admin.rb
:
ActiveAdmin.setup do |config|
# ...
config.before_filter :revert_friendly_id
end
ActiveAdmin::ResourceController
y agregue un método revert_friendly_id
, por ejemplo, agregando lo siguiente al final de 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
Actualización: acabo de actualizar el último ejemplo de código para manejar controladores sin modelo relacionado (por ejemplo, el controlador Active Admin Dashboard)
Actualización 2: Acabo de intentar usar el truco anterior junto con la gema friendly_id y parece que funciona bien :)
Actualización 3: limpié el código para usar la forma estándar de agregar Active Admin antes de los filtros al controlador base