ActiveRecord:: ReadOnlyRecord при использовании ActiveAdmin и Friendly_id
Я начал использовать ActiveAdmin недавно в проекте, и почти все работает отлично, но у меня проблема при использовании его в сочетании с жемчужиной friendly_id. Я получаю ActiveRecord:: ReadOnlyRecord, брошенный для моих форм [я верю] из-за атрибута friendly_id, чей идентификатор только для чтения:
{"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
Я предполагаю, что последняя строка является виновником, поскольку она является атрибутом readonly, она не в моей форме, а скорее в PATH
http://localhost:5000/manage/spaces/the-kosmonaut/edit
Как я могу исправить это из попытки обновления идентификатора?
Форма из 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
UPDATE: Это не работает, так что это не 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 вызывает какую-то странность? Т.е. пользователи < - HABTM → Пробелы?
Ответы
Ответ 1
Если вы хотите только дружественный идентификатор в интерфейсе и не заботитесь о них внутри Active Admin, вы можете вернуть эффекты жемчужины friendly_id для своих контроллеров Active Admin.
Я не знаю точно, как 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 Dashboard администратора)
Обновление 2: Я просто попытался использовать выше взломанный вместе с жемчужиной friendly_id, и, похоже, он работает нормально:)
Обновление 3:. Очистите код, чтобы использовать стандартный способ добавления активного администратора перед фильтрами на базовый контроллер.
Ответ 2
Вы можете настроить поиск ресурсов в соответствии с http://activeadmin.info/docs/2-resource-customization.html#customizing_resource_retrieval. Обратите внимание, что вы хотите использовать метод find_resource
вместо resource
, иначе вы не сможете создавать новые записи.
(Подробнее см. https://github.com/gregbell/active_admin/blob/master/lib/active_admin/resource_controller/data_access.rb)
В классе ресурсов ActiveAdmin напишите:
controller do
def find_resource
scoped_collection.where(slug: params[:id]).first!
end
end
Вы также можете перезаписать поведение для всех ресурсов путем модификации ResourceController в инициализаторе 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
Надеюсь, что это поможет!
Боковое примечание. При создании новых записей через интерфейс администратора убедитесь, что вы не включаете поле slug в форму, или FriendlyId не будет генерировать пули. (Я считаю, что только для версии 5+)
Ответ 3
Этот метод работает для меня. добавьте этот код в app/admin/model_name.rb
ActiveAdmin.register model_name do
controller do
defaults finder: :find_by_slug
end
end
Ответ 4
Чтобы добавить к Denny solution, более "дружественным" решением будет использование finder friendly_id.
controller do
def find_resource
scoped_collection.friendly.find_by_friendly_id(params[:id])
end
end
Источник
Ответ 5
Вот мое решение, основанное на решении @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