Области Active Admin для каждого экземпляра связанной модели

У меня проблема с динамической активной областью администрирования. Я пытаюсь создать область для каждого «менеджера» «проекта» в своем приложении. Тем не менее, кажется, что области не обновляются, когда создается новый менеджер (или назначается проекту), но они обновляются, если я перезапускаю сервер. Так что код "работает" сам по себе, но явно не так, как хотелось бы. Я новичок в ruby/rails, поэтому я не уверен, нужно ли мне что-то делать, чтобы каким-то образом «обновить» область видимости.

К вашему сведению, я использую Rails 3.2 на Heroku Cedar с ActiveAdmin.

Вот рассматриваемый код (который работает, но добавляет новых менеджеров только после перезапуска сервера):


Manager.find_each do |m|
  scope m.first_name do |projects|
    projects.where(:manager_id => m.id)
  end
end

И вся модель проекта Active Admin:

ActiveAdmin.register Project do
 menu :priority => 1
 index do
  column :name
  column :company_name
  column :status
  column :projection do |project|
   number_to_currency project.projection
  end
  column :updated_at
  default_actions
 end

 scope :all
 scope :working, :default => true do |projects|
  projects.where(:status => 'working')
 end

 Manager.find_each do |m|
  scope m.first_name do |projects|
    projects.where(:manager_id => m.id)
  end
 end
end

person Sean Powell    schedule 04.05.2012    source источник
comment
Следующий ответ отличный. Я не понимаю, почему вы не отметили это как ответ.   -  person Pedro Rolo    schedule 05.05.2015


Ответы (6)


Вот фактическое решение этой проблемы ... Хотя использование фильтров вместо этого более желательно с точки зрения стабильности и обслуживания, это выглядит лучше в ActiveAdmin и более удобно для пользователя, поскольку области действия становятся красивыми вкладками.

Это немного хак, но это жизнеспособное решение, где это уместно:

Хитрость заключается в том, чтобы обновить области видимости в before_filter в действии индекса контроллеров.

Это может быть плохо, если у вас есть много областей, созданных для ресурса (хотя вы можете легко установить некоторые ограничения).

ActiveAdmin.register Project do
  menu :priority => 1
  index do
    column :name
    column :company_name
    column :status
    column :projection do |project|
      number_to_currency project.projection
    end
    column :updated_at
    default_actions
  end

  scope :all
  scope :working, :default => true do |projects|
    projects.where(:status => 'working')
  end

  controller do
    before_filter :update_scopes, :only => :index

    def update_scopes
      resource = active_admin_config

      Manager.all.each do |m|
        next if resource.scopes.any? { |scope| scope.name == m.first_name }
        resource.scopes << (ActiveAdmin::Scope.new m.first_name do |projects|
          projects.where(:manager_id => m.id)
        end)
      end

      # try something like this for deletions (untested)
      resource.scopes.delete_if do |scope|
        !(Manager.all.any? { |m| scope.name == m.first_name } || ['all', 'working'].include?(scope.name)) # don't delete other scopes you have defined
      end

    end
  end
end
person Brant Sterling Wedel    schedule 06.08.2013
comment
Спасибо Daxter на github за несколько рекомендаций: связанная проблема с GitHub - person Brant Sterling Wedel; 07.08.2013
comment
Как насчет того, когда они будут удалены? - person Pedro Rolo; 04.05.2015
comment
Я не настроен для тестирования, но я просто добавил код, который должен помочь в удалении. - person Brant Sterling Wedel; 04.05.2015
comment
Это отлично сработало, однако default области действия необходимо установить заранее. - person Weston Ganger; 09.11.2019

Я нашел, что это работает для меня:

Файл ActiveAdmin

scope :working, :default => true do |projects|
  Project.working
end

Модель

scope :working, -> { where(:status => 'working') }

Немного поздно с ответом, но, надеюсь, это кому-то поможет.

person pdurbin    schedule 19.10.2012
comment
Это действительно работало для создания нескольких областей? Я вижу, что создается одна область. - person James; 17.05.2013

Настоящие динамические области внутри блоков регистров AA не будут работать. При этом я имею в виду, что изменения в таблице Manager не будут отражаться в динамических областях, созданных во время «инициализации». См. также: https://github.com/gregbell/active_admin/wiki/Creating-dynamic-scopes. Что вы можете попробовать, так это использовать фильтры вместо областей. Затем вы можете написать что-то вроде:

filter :managers, :as => :select, :collection => proc { Manager.order('name ASC').map(&:first_name) }  

и изменения в свойствах менеджеров будут отображаться (после обновления страницы) без перезапуска сервера. Также проверьте https://github.com/gregbell/active_admin/issues/1261#issuecomment-5296549

Также обратите внимание, что области действия активных записей !разные! из активных областей администрирования. вы можете проверить

http://apidock.com/rails/ActiveRecord/NamedScope/ClassMethods/scope

person Sjors Branderhorst    schedule 15.06.2012
comment
Спасибо! Инкапсуляция коллекции в proc является правильной, чтобы она запускалась по требованию. Это также устраняет проблемы rake db:schema:load и rake db:migrate. Фильтры ActiveAdmin попытаются получить доступ к схеме до того, как она будет создана, если она не заключена в proc. - person scarver2; 27.02.2014

Rails загружает классы только один раз в рабочем режиме. Это означает, что ваши области видимости вызываются только один раз, а затем кэшируются. Вот почему новые области не появляются до перезапуска. То же самое было бы верно, если бы вы отредактировали имя менеджера в вашем случае.

Я думаю, что решением может быть использование лямбды или Proc, но за те несколько минут, что я играл с этим, я не добился успеха. Это может быть невозможно и так, как написан activeadmin.

person Jared    schedule 11.05.2012
comment
Правильно, что нельзя. Способ, которым activeadmin реализовал свою оболочку области вокруг метода области активной записи, запрещает это. Возможно, метод reload_scope каким-то образом может быть представлен в activerecord после перехватчиков сохранения/фиксации. У вас есть идеи, как это сделать? - person Sjors Branderhorst; 15.06.2012

Вот мое оптимизированное решение, основанное на ответе Бранта Стерлинга Веделя.

Это решение содержит следующие дополнительные улучшения:

  • Удаляет все неиспользуемые области
  • Позволяет установить область действия по умолчанию
### Default scope must be set in advance
scope "Jeff", default: true do |x| 
  x.joins(:manager).where(manager: {name: "Jeff"})
end

controller do

  before_action :reload_scopes, only: :index

  def reload_scopes
    resource_config = active_admin_config

    resource_config.instance_variable_set(:@scopes, [
      resource_config.scopes.first ### Default scope
    ])

    Manager.all.each do |m|
      next if resource_config.scopes.first.name ==  m.name

      resource_config.scopes << ActiveAdmin::Scope.new(m.name){|scope| scope.where(manager_id: m.id) }
    end
  end

end
person Weston Ganger    schedule 08.11.2019

Решение, упомянутое Вестоном Гангером, работает как шарм. Если у вас нет области по умолчанию, вы можете использовать всю область по умолчанию.

  scope :all, default: true
person Bassirou Diaby    schedule 28.05.2020