Skip to content

Commit b7fa107

Browse files
committed
Resolves activeadmin#587 adding :if & :unless proc arguments to scope_to() method
1 parent 693471e commit b7fa107

File tree

7 files changed

+121
-57
lines changed

7 files changed

+121
-57
lines changed

docs/2-resource-customization.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,21 @@ has_many relationships, you can simply scope the listings and finders like so:
158158

159159
That approach limits the posts an admin can access to ```current_user.posts```.
160160

161+
If you want to conditionally apply the scope, then there are options for that as well:
162+
163+
ActiveAdmin.register Post do
164+
# Only scope the query if there is a user to scope to, helper provided via Devise
165+
scope_to :current_user, :if => proc{ admin_user_signed_in? }
166+
167+
# Don't scope the query if the user is an admin
168+
scope_to :current_user, :unless => proc{ current_admin_user.admin? }
169+
170+
# Get fancy and can combine with block syntax
171+
scope_to :if => proc{ admin_user_signed_in? } do
172+
User.most_popular
173+
end
174+
end
175+
161176
If you want to do something fancier, for example override a default scope, you can
162177
also use :association_method parameter with a normal method on your User model.
163178
The only requirement is that your method returns an instance of ActiveRecord::Relation.

features/index/index_scope_to.feature

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,27 @@ Feature: Index Scope To
3030

3131
When I follow "Published"
3232
Then I should see 1 posts in the table
33+
34+
Scenario: Viewing the index with conditional scope :if
35+
Given an index configuration of:
36+
"""
37+
ActiveAdmin.register Post do
38+
scope_to :if => proc{ false } do
39+
User.find_by_first_name_and_last_name("John", "Doe")
40+
end
41+
end
42+
"""
43+
When I am on the index page for posts
44+
Then I should see 12 posts in the table
45+
46+
Scenario: Viewing the index with conditional scope :unless
47+
Given an index configuration of:
48+
"""
49+
ActiveAdmin.register Post do
50+
scope_to :unless => proc{ true } do
51+
User.find_by_first_name_and_last_name("John", "Doe")
52+
end
53+
end
54+
"""
55+
When I am on the index page for posts
56+
Then I should see 12 posts in the table

lib/active_admin/resource.rb

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
require 'active_admin/resource/routes'
77
require 'active_admin/resource/naming'
88
require 'active_admin/resource/scopes'
9+
require 'active_admin/resource/scope_to'
910
require 'active_admin/resource/sidebars'
1011
require 'active_admin/resource/belongs_to'
1112

@@ -39,12 +40,6 @@ class Resource
3940
# The default sort order to use in the controller
4041
attr_accessor :sort_order
4142

42-
# Scope this resource to an association in the controller
43-
attr_accessor :scope_to
44-
45-
# If we're scoping resources, use this method on the parent to return the collection
46-
attr_accessor :scope_to_association_method
47-
4843
# Set the configuration for the CSV
4944
attr_writer :csv_builder
5045

@@ -79,6 +74,7 @@ def initialize(namespace, resource_class, options = {})
7974
include PagePresenters
8075
include Pagination
8176
include Scopes
77+
include ScopeTo
8278
include Sidebars
8379
include Menu
8480
include Routes

lib/active_admin/resource/scope_to.rb

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
module ActiveAdmin
2+
class Resource
3+
module ScopeTo
4+
5+
# Scope this controller to some object which has a relation
6+
# to the resource. Can either accept a block or a symbol
7+
# of a method to call.
8+
#
9+
# Eg:
10+
#
11+
# ActiveAdmin.register Post do
12+
# scope_to :current_user
13+
# end
14+
#
15+
# Then every time we instantiate and object, it would call
16+
#
17+
# current_user.posts.build
18+
#
19+
# By default Active Admin will use the resource name to build a
20+
# method to call as the association. If its different, you can
21+
# pass in the association_method as an option.
22+
#
23+
# scope_to :current_user, :association_method => :blog_posts
24+
#
25+
# will result in the following
26+
#
27+
# current_user.blog_posts.build
28+
#
29+
# To conditionally use this scope, you can use conditional procs
30+
#
31+
# scope_to :current_user, :if => proc{ admin_user_signed_in? }
32+
#
33+
# or
34+
#
35+
# scope_to :current_user, :unless => proc{ current_user.admin? }
36+
#
37+
def scope_to(*args, &block)
38+
options = args.extract_options!
39+
method = args.first
40+
41+
scope_to_config[:method] = block || method
42+
scope_to_config[:association_method] = options[:association_method]
43+
scope_to_config[:if] = options[:if]
44+
scope_to_config[:unless] = options[:unless]
45+
46+
end
47+
48+
def scope_to_association_method
49+
scope_to_config[:association_method]
50+
end
51+
52+
def scope_to_method
53+
scope_to_config[:method]
54+
end
55+
56+
def scope_to_config
57+
@scope_to_config ||= {
58+
:method => nil,
59+
:association_method => nil,
60+
:if => nil,
61+
:unless => nil
62+
}
63+
end
64+
65+
def scope_to?(context = nil)
66+
return false if scope_to_method.nil?
67+
return render_in_context(context, scope_to_config[:if]) unless scope_to_config[:if].nil?
68+
return !render_in_context(context, scope_to_config[:unless]) unless scope_to_config[:unless].nil?
69+
true
70+
end
71+
72+
end
73+
end
74+
end

lib/active_admin/resource_controller/scoping.rb

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,11 @@ module Scoping
1111
# the scope to be defined in the active admin configuration.
1212
#
1313
# If scope_to is a proc, we eval it, otherwise we call the method on the controller.
14+
#
15+
# Collection can be scoped conditionally with an :if or :unless proc.
1416
def begin_of_association_chain
15-
return nil unless active_admin_config.scope_to
16-
case active_admin_config.scope_to
17-
when Proc
18-
instance_eval &active_admin_config.scope_to
19-
when Symbol
20-
send active_admin_config.scope_to
21-
else
22-
raise ArgumentError, "#scope_to accepts a symbol or a block"
23-
end
17+
return nil unless active_admin_config.scope_to?(self)
18+
render_in_context(self, active_admin_config.scope_to_method)
2419
end
2520

2621
# Overriding from InheritedResources::BaseHelpers

lib/active_admin/resource_dsl.rb

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,9 @@ def belongs_to(target, options = {})
77
config.belongs_to(target, options)
88
end
99

10-
# Scope this controller to some object which has a relation
11-
# to the resource. Can either accept a block or a symbol
12-
# of a method to call.
13-
#
14-
# Eg:
15-
#
16-
# ActiveAdmin.register Post do
17-
# scope_to :current_user
18-
# end
19-
#
20-
# Then every time we instantiate and object, it would call
21-
#
22-
# current_user.posts.build
23-
#
24-
# By default Active Admin will use the resource name to build a
25-
# method to call as the association. If its different, you can
26-
# pass in the association_method as an option.
27-
#
28-
# scope_to :current_user, :association_method => :blog_posts
29-
#
30-
# will result in the following
31-
#
32-
# current_user.blog_posts.build
33-
#
10+
# Scope collection to a relation
3411
def scope_to(*args, &block)
35-
options = args.extract_options!
36-
method = args.first
37-
38-
config.scope_to = block_given? ? block : method
39-
config.scope_to_association_method = options[:association_method]
12+
config.scope_to(*args, &block)
4013
end
4114

4215
# Create a scope

spec/unit/resource_spec.rb

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -155,19 +155,6 @@ class ::News; def self.has_many(*); end end
155155
end
156156
end
157157

158-
context "when not using a block or symbol" do
159-
before do
160-
@resource = application.register Category do
161-
scope_to "Some string"
162-
end
163-
end
164-
it "should raise and exception" do
165-
lambda {
166-
@resource.controller.new.send(:begin_of_association_chain)
167-
}.should raise_error(ArgumentError)
168-
end
169-
end
170-
171158
describe "getting the method for the association chain" do
172159
context "when a simple registration" do
173160
before do

0 commit comments

Comments
 (0)