【问题标题】:Active Admin scopes for each instance of a related model相关模型的每个实例的活动管理范围
【发布时间】:2012-05-04 14:33:25
【问题描述】:

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

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

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


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

【问题讨论】:

  • 下一个答案很棒。我不明白您为什么不将其标记为已回答。

标签: ruby-on-rails ruby heroku activeadmin


【解决方案1】:

这里是这个问题的一个实际解决方案...Altho 使用过滤器代替更理想的稳定性和维护明智,这在 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

【讨论】:

  • 感谢 github 上的 Daxter 提出一些建议:Associated GitHub Issue
  • 什么时候删除呢?
  • 我没有准备好对其进行测试,但我只是添加了一些有助于删除的代码。
  • 这很好,但是default 范围需要提前设置
【解决方案2】:

我发现这对我有用:

ActiveAdmin 文件

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

型号

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

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

【讨论】:

  • 这真的可以创建多个作用域吗?我可以看到创建了一个范围..
【解决方案3】:

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

【讨论】:

  • 谢谢!将集合封装在 proc 中是正确的,以便按需运行。这也解决了rake db:schema:loadrake db:migrate 问题。如果未包含在 proc 中,ActiveAdmin 过滤器将尝试在创建模式之前访问它。
【解决方案4】:

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

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

【讨论】:

  • 不可能是正确的。 activeadmin 围绕活动记录范围方法实现其范围包装器的方式禁止这样做。也许“reload_scope”方法可能会在保存/提交挂钩后以某种方式暴露给 activerecord。你知道怎么做吗?
【解决方案5】:

这是我根据 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

【讨论】:

    【解决方案6】:

    weston Ganger 提到的解决方案很有魅力。 如果没有默认作用域,可以使用 all 作用域作为默认作用域。

      scope :all, default: true
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-04
      • 1970-01-01
      • 1970-01-01
      • 2012-08-27
      • 2021-11-20
      • 2012-03-09
      • 2020-11-19
      • 2014-03-04
      相关资源
      最近更新 更多