Skip to content

Commit

Permalink
Update docs, writed tests, fixed logic
Browse files Browse the repository at this point in the history
  • Loading branch information
killondark authored and palkan committed May 22, 2024
1 parent 2c7b52d commit 2f14a9c
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 1 deletion.
23 changes: 23 additions & 0 deletions docs/scoping.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,29 @@ class PostPolicy < ApplicationPolicy
end
```

Or just pass class name where included logic of scope to `relation_scope` and write `.call` method:

```ruby
class PostsController < ApplicationController
def index
@posts = authorized_scope(Post.all)
end
end

class PostPolicy < ApplicationPolicy
relation_scope AuthorizedPosts
end

class AuthorizedPosts
class << self
def call(policy, relation)
user = policy.user
user.admin? ? relation : relation.where(user: user)
end
end
end
```

## Define scopes

To define scope you should use either `scope_for` or `smth_scope` methods in your policy:
Expand Down
2 changes: 1 addition & 1 deletion lib/action_policy/policy/scoping.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def scope_for(type, name = :default, callable = nil, &block)
name, callable = prepare_args(name, callable)

mid = :"__scoping__#{type}__#{name}"
block = ->(target) { callable.call(target) } if callable
block = ->(target) { callable.call(self, target) } if callable

define_method(mid, &block)

Expand Down
90 changes: 90 additions & 0 deletions test/action_policy/rails/scope_matchers_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,96 @@ def test_named_filtered_params_admin
end
end

class TestRailsScopeMatchersViaClass < ActionController::TestCase
class AuthorizedPosts
class << self
def call(policy, relation)
user = policy.user
scope = user.admin? ? relation : relation.where(user: user)
scope.order(:title)
end
end
end

class PostPolicy < ActionPolicy::Base
relation_scope AuthorizedPosts
end

class PostsController < ActionController::Base
authorize :user, through: :current_user

def index
render json: authorized_scope(AR::Post.all)
end

private

def current_user
@current_user ||= AR::User.find(params[:user_id])
end
end

tests PostsController

attr_reader :admin, :guest

def setup
ActiveRecord::Base.connection.begin_transaction(joinable: false)
@guest = AR::User.create!(name: "Jack")
@admin = AR::User.create!(name: "John", role: "admin")
end

def teardown
ActiveRecord::Base.connection.rollback_transaction
end

def json_body
@json_body ||= JSON.parse(response.body)
end

def test_authorized_relation_guest
get :index, params: {user_id: guest.id}

assert_equal 0, json_body.size
end

def test_authorized_relation_admin
get :index, params: {user_id: admin.id}

assert_equal 0, json_body.size
end

def test_authorized_association
AR::Post.create!(title: "[wip]", user: admin)
AR::Post.create!(title: "Good news!", user: guest)

get :index, params: {user_id: guest.id}

assert_equal 1, json_body.size
assert_equal "Good news!", json_body.first["title"]
end

def test_authorized_association_2
AR::Post.create!(title: "[wip]", user: admin)
AR::Post.create!(title: "Good news!", user: guest)

get :index, params: {user_id: admin.id}

assert_equal 2, json_body.size
assert_equal ["Good news!", "[wip]"], json_body.map { _1["title"] }
end

def test_authorized_association_3
AR::Post.create!(title: "[wip]", user: guest)
AR::Post.create!(title: "Admin news", user: admin)
AR::Post.create!(title: "Good news!", user: guest)

get :index, params: {user_id: guest.id}

assert_equal 2, json_body.size
end
end

# See https://github.com/palkan/action_policy/issues/101
class TestRelationMutability < ActionController::TestCase
class UserPolicy < ActionPolicy::Base
Expand Down

0 comments on commit 2f14a9c

Please sign in to comment.