Конфликт Friendly_id и активного администратора — возможно, из-за revert_freindly_id

впервые задаю вопрос о переполнении стека :)

У меня конфликт между friendly_id и активным администратором (это предположение), как обсуждалось во многих темах здесь. Я просмотрел все эти темы, но я не совсем уверен, что они решают мою проблему. Извините за очень длинный пост!

Я пытаюсь создать дружественные ссылки на продукты на моем сайте. Я добавил гем friendly_id, и все работает нормально в моих средах разработки и промежуточной среды, но дружественные ссылки не работают в рабочей среде. Вот весь мой код:

Модель:

class Product < ActiveRecord::Base
  extend FriendlyId
  friendly_id :name, use: :slugged
  ...
end

Контроллер:

class ProductsController < ApplicationController
  before_filter :get_product, only: [:show]
  ...

  private

  def get_product
    @product = Product.friendly.find(params[:id])
  end
end

На данный момент все мои записи о продуктах имеют заполненное поле slug. Я не хочу использовать слаги в своем административном интерфейсе, поэтому, когда я наткнулся на решение здесь, я пошел дальше и немного изменил его, чтобы активный админ работал вместе с friendly_id.

config/initializers/active_admin.rb:

ActiveAdmin.setup do |config|
  ...

  config.before_filter :revert_friendly_id
end

Я определил revert_friendly_id в контроллере приложения:

class ApplicationController < ActionController::Base
  ...
  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

Я заметил, что при первом развертывании в рабочей среде через capistrano дружественные ссылки работают, как и ожидалось. Таким образом, ссылки на мои продукты доступны с помощью: http://website.com/products/my-product-slug. Но в ту минуту, когда я получаю доступ к интерфейсу администратора на производстве, ссылки немедленно переключаются обратно на идентификаторы продуктов: http://website.com/products/12345. Я не совсем уверен, как решить эту проблему, хотя я понимаю, почему это может происходить, может кто-нибудь помочь мне, пожалуйста?


person harini    schedule 19.08.2014    source источник


Ответы (4)


Вот как я решил проблему. Основано на исправлении armstrjare по этой ссылке.

Я удалил функцию revert_friendly_id из моего контроллера приложений и before_filter из моей конфигурации. Затем просто добавил следующее в app/admin/product.rb:

ActiveAdmin.register Product do

  around_filter do |controller, action|
    Product.class_eval do
      alias :__active_admin_to_param :to_param
      def to_param() id.to_s end
    end

    begin
      action.call
    ensure
      Product.class_eval do
        alias :to_param :__active_admin_to_param
      end
    end
  end
...
end

И все заработало, как и ожидалось. Надеюсь, это поможет кому-то еще!

person harini    schedule 20.08.2014
comment
Вы можете переопределить метод find_resource в controller: ``` контроллер do def find_resource scoped_collection.friendly.find(params[:id]) end end ``` вам нужно использовать параметр finder: (из github.com/activeadmin/inherited_resources/blob/master/lib/) например : belongs_to :content, finder: :find_by_slug! - person Andrew Zelenets; 08.06.2021

Я нашел очень простое решение: просто перезапишите to_param в своей модели и проверьте, вызывается ли он из active_admin.

приложение/модели/продукт.рб:

class Product < ActiveRecord::Base
  def to_param
    if caller.to_s.include?"active_admin"
      id && id.to_s
    else
      slug
    end
  end
end
person René Meye    schedule 17.03.2016
comment
Я использовал свою собственную реализацию slug, а не дружественный идентификатор, и это работает для меня. Спасибо. - person John Moses; 14.07.2017

Когда вы устанавливаете метод to_param, он будет установлен для всего приложения. Таким образом, вы должны проверить, находится ли запрошенный контроллер в пространстве имен администратора или нет. Исходя из этого, вы должны переключить возврат метода to_param.

person nistvan    schedule 19.08.2014
comment
Но поскольку я вызываю revert_friendly_id только для активных моделей администратора через before_filter в конфигурации активного администратора, почему это влияет на другие модели в моем приложении? - person harini; 19.08.2014
comment
Метод to_param относится к общей (!!) модели ActiveRecord. Неважно, какой контроллер использует эту модель. При регистрации модели в ActiveAdmin не будет создана новая модель ActiveRecord. - person nistvan; 19.08.2014
comment
Спасибо, я проверю, как я могу решить эту проблему, и обновлю эту тему, если она работает :) - person harini; 19.08.2014
comment
знаете ли вы, почему это не прерывается при разработке/постановке, а происходит только при производстве? Я просто пытаюсь немного лучше понять эту проблему. - person harini; 19.08.2014
comment
В режиме разработки нет кэширования. Каждый запрос перезагружает все классы (включая модели). В производственном режиме классы будут кэшироваться по умолчанию. Вы можете установить это в файлах config/environments/*.rb. - person nistvan; 20.08.2014
comment
Спасибо за все ваши ответы, я смог решить эту проблему, используя решение, подробно описанное по этой ссылке используя исправление armstrjare. Я обновлю это как ответ на этот вопрос, надеюсь, это поможет кому-то еще! - person harini; 21.08.2014

Вы можете переопределить метод find_resource в controller:

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

Для ассоциации active_admin belongs_to вы можете использовать параметр finder: (из https://github.com/activeadmin/inherited_resources/blob/master/lib/inherited_resources/belongs_to_helpers.rb#L17)

Например: belongs_to :content, finder: :find_by_slug!

person Andrew Zelenets    schedule 08.06.2021