9

我对动态活动管理范围有疑问。我正在尝试为我的应用程序中“项目”的每个“经理”创建一个范围。但是,当创建新经理(或分配给项目)时,范围似乎没有更新,但如果我重新启动服务器,它们会更新。所以代码本身“有效”,但显然不是我想要的方式。我是一个 ruby​​/rails 菜鸟,所以我不确定我是否需要做一些事情以某种方式“刷新”范围。

作为一个仅供参考,我在 Heroku Cedar 上使用 Rails 3.2 和 ActiveAdmin

这是有问题的代码(有效但仅在服务器重新启动后引入新的管理器):


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

以及整个 Active Admin Project 模型:

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
4

6 回答 6

14

这是此问题的实际解决方案...尽管使用过滤器代替了更理想的稳定性和维护方式,这在 ActiveAdmin 中看起来更好,并且更用户友好,因为范围变成了漂亮的选项卡。

这有点像 hack,但在适当的情况下它是一个可行的解决方案:

诀窍是更新控制器索引操作的 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
于 2013-08-06T19:55:48.263 回答
4

我发现这对我有用:

活动管理文件

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

模型

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

回复有点晚,但希望它可以帮助某人。

于 2012-10-19T08:27:38.630 回答
2

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

于 2012-06-15T13:25:08.107 回答
1

Rails 在生产模式下只加载一次类。这意味着您的范围仅被调用一次,然后它们被缓存。这就是为什么新范围直到重新启动后才会出现的原因。如果您在案例中编辑了经理的名字,情况也是如此。

我认为解决方案可能是使用 lambda 或 Proc,但在我使用它的几分钟内,我没有成功。activeadmin 的编写方式可能也不可能。

于 2012-05-11T03:41:11.403 回答
0

韦斯顿·甘格(weston Ganger)提到的解决方案很有魅力。如果您没有默认范围,则可以使用 all 范围作为默认范围。

  scope :all, default: true
于 2020-05-28T02:43:21.473 回答
0

这是我根据 Brant Sterling Wedel 的回答优化的解决方案。

此解决方案包含以下附加增强功能:

  • 删除任何未使用的范围
  • 允许设置默认范围
### 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
于 2019-11-08T22:47:01.370 回答