ActiveRecord :: ReadOnlyRecord при использовании ActiveAdmin и Friendly_id - PullRequest
16 голосов
/ 07 октября 2011

Я недавно начал использовать 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"=>"info@somedomain.com"},
"commit"=>"Update Space",
"id"=>"the-kosmonaut"}  <--- culprit

Я предполагаю, что последняя строка является виновником, поскольку это атрибут только для чтения, он не в моей форме, а скорее в 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

ОБНОВЛЕНИЕ: Это тоже не работает, так что это не 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

ОБНОВЛЕНИЕ ОБНОВЛЕНИЕ: удаление scope_to устраняет проблему.

scope_to :current_user, :unless => proc{ current_user.admin? }

Единственная проблема в том, что мне нужно scope_to, чтобы пользователи не могли видеть записи, которыми они не владеют Я предполагаю (как я предполагаю, что scope_to обычно работает с has_many), что моя ассоциация HABTM вызывает некоторую странность? Т.е. пользователи <- HABTM -> пробелы?

Ответы [ 5 ]

28 голосов
/ 07 октября 2011

Если вам нужны только дружественные идентификаторы во внешнем интерфейсе, и вам нет дела до их использования в 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 Admin Dashboard)

Обновление 2: Я только что попытался использовать вышеупомянутый хак вместе с гемом friendly_id икажется, что он работает просто отлично:)

Обновление 3: Очистил код, чтобы использовать стандартный способ добавления Active Admin перед фильтрами на базовый контроллер

16 голосов
/ 17 августа 2013

Вы можете настроить поиск ресурсов в соответствии с 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+)

4 голосов
/ 11 декабря 2013

Этот метод работает для меня. добавить этот код в app / admin / model_name.rb

ActiveAdmin.register model_name do
  controller do
    defaults finder: :find_by_slug
  end
end
2 голосов
/ 27 августа 2014

Чтобы добавить к решение Денни , более "дружественным" решением было бы использование искателей friendly_id.

controller do
  def find_resource
    scoped_collection.friendly.find_by_friendly_id(params[:id])
  end
end

Источник

1 голос
/ 22 октября 2013

Вот мое решение, основанное на решении @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
...