相关模型的每个实例的活动管理范围

时间:2012-05-04 14:33:25

标签: ruby-on-rails ruby heroku activeadmin

我遇到动态有效管理范围的问题。我正在尝试为每个"经理"创建一个范围。一个"项目"在我的应用程序中但是,在创建(或分配给项目)新管理器时,范围似乎不会更新,但如果我重新启动服务器,它们会更新。所以代码"工作"本身但显然不是我想要的方式。我是一个ruby / rails noob所以我不确定我是否需要做些什么来刷新"范围在某种程度上。

作为一个FYI,我在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

6 个答案:

答案 0 :(得分:10)

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

答案 1 :(得分:3)

我发现这对我有用:

ActiveAdmin文件

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

模型

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

回复有点晚,但希望能帮助别人。

答案 2 :(得分: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

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

这是我根据布兰特·斯特林·韦德尔的回答而优化的解决方案。

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

  • 删除所有未使用的作用域
  • 允许设置默认范围
### 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

答案 5 :(得分:0)

韦斯顿·冈格(Weston Ganger)提到的解决方案就像一个魅力。 如果没有默认范围,则可以将所有范围用作默认范围。

  scope :all, default: true