Подтвердить что ты не робот

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 → Пробелы?

4b9b3361

Ответ 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