Active Admin scopes for each instance of a related model

≡放荡痞女 提交于 2019-12-18 13:21:03

问题


I have an issue with a dynamic active admin scope. I am attempting to create a scope for each "manager" of a "project" in my app. However, the scopes don't seem to update when a new manager is created (or assigned to a project) but they DO update if I restart the server. So the code "works" per se but obviously not in the way I would like it to. I'm a ruby/rails noob so I am not sure if I need to do something to "refresh" the scope in some way.

As an FYI, I am using Rails 3.2 on Heroku Cedar with ActiveAdmin

Here is the code in question (that works but only brings in new managers after the server is restarted):


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

And the entire Active Admin Project model:

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

回答1:


Here is an actual solution to this problem ... Altho using filters instead is more desirable stability and maintenance wise, this looks nicer in ActiveAdmin and is more user friendly since scopes become nice looking tabs.

It is a bit of a hack, but it is a viable solution where appropriate:

The trick is to update the scopes in a before_filter on the controllers index action.

This could get bad if you have many scopes created on a resource (altho you can easily set some limits)

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



回答2:


I found this to work for me:

ActiveAdmin file

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

Model

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

A bit late in the reply but hopefully it helps someone out.




回答3:


True dynamic scopes inside the AA register blocks won't work. With that I mean that changes in the Manager table won't be reflected in the at 'initialization'-time created dynamic scopes. Also see: https://github.com/gregbell/active_admin/wiki/Creating-dynamic-scopes. What you could try is using filters instead of scopes. Then you can write something like:

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

and changes in the managers properties will show (after page refresh) without restarting the server. Also check https://github.com/gregbell/active_admin/issues/1261#issuecomment-5296549

Also note that active record scopes are !different! from active admin scopes. you might want to check

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




回答4:


Rails only loads classes once in production mode. This means your scopes are only being called once and then they are cached. This is why new scopes don't show up until after a restart. The same thing would be true if you edited the manager's first name in your case.

I think the solution may be to use a lambda or Proc, but in the few minutes I played with it, I wasn't successful. It may not be possible the way activeadmin is written too.




回答5:


Here is my optimized solution based on Brant Sterling Wedel's answer.

This solution contains the following additional enhancements:

  • Removes any unused scopes
  • Allows to set default scope
### 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


来源:https://stackoverflow.com/questions/10450905/active-admin-scopes-for-each-instance-of-a-related-model

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!