This repository has been archived by the owner on Dec 12, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 783
/
controller_additions.rb
188 lines (179 loc) · 6.7 KB
/
controller_additions.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
module CanCan
# This module is automatically included into all controllers.
# It also makes the "can?" and "cannot?" methods available to all views.
module ControllerAdditions
module ClassMethods
# Sets up a before filter which loads and authorizes the current resource. This performs both
# load_resource and authorize_resource and accepts the same arguments. See those methods for details.
#
# class BooksController < ApplicationController
# load_and_authorize_resource
# end
#
def load_and_authorize_resource(options = {})
before_filter(options.slice(:only, :except)) { |c| ResourceAuthorization.new(c, c.params, options.except(:only, :except)).load_and_authorize_resource }
end
# Sets up a before filter which loads the appropriate model resource into an instance variable.
# For example, given an ArticlesController it will load the current article into the @article
# instance variable. It does this by either calling Article.find(params[:id]) or
# Article.new(params[:article]) depending upon the action. It does nothing for the "index"
# action.
#
# Call this method directly on the controller class.
#
# class BooksController < ApplicationController
# load_resource
# end
#
# A resource is not loaded if the instance variable is already set. This makes it easy to override
# the behavior through a before_filter on certain actions.
#
# class BooksController < ApplicationController
# before_filter :find_book_by_permalink, :only => :show
# load_resource
#
# private
#
# def find_book_by_permalink
# @book = Book.find_by_permalink!(params[:id)
# end
# end
#
# See load_and_authorize_resource to automatically authorize the resource too.
#
# Options:
# [:+only+]
# Only applies before filter to given actions.
#
# [:+except+]
# Does not apply before filter to given actions.
#
# [:+nested+]
# Specify which resource this is nested under.
#
# load_resource :nested => :author
#
# Deep nesting can be defined in an array.
#
# load_resource :nested => [:publisher, :author]
#
# [:+class+]
# The class to use for the model.
#
# [:+collection+]
# Specify which actions are resource collection actions in addition to :+index+. This
# is usually not necessary because it will try to guess depending on if an :+id+
# is present in +params+.
#
# load_resource :collection => [:sort, :list]
#
# [:+new+]
# Specify which actions are new resource actions in addition to :+new+ and :+create+.
# Pass an action name into here if you would like to build a new resource instead of
# fetch one.
#
# load_resource :new => :build
#
def load_resource(options = {})
before_filter(options.slice(:only, :except)) { |c| ResourceAuthorization.new(c, c.params, options.except(:only, :except)).load_resource }
end
# Sets up a before filter which authorizes the current resource using the instance variable.
# For example, if you have an ArticlesController it will check the @article instance variable
# and ensure the user can perform the current action on it. Under the hood it is doing
# something like the following.
#
# unauthorized! if cannot?(params[:action].to_sym, @article || Article)
#
# Call this method directly on the controller class.
#
# class BooksController < ApplicationController
# authorize_resource
# end
#
# See load_and_authorize_resource to automatically load the resource too.
#
# Options:
# [:+only+]
# Only applies before filter to given actions.
#
# [:+except+]
# Does not apply before filter to given actions.
#
# [:+class+]
# The class to use for the model.
#
def authorize_resource(options = {})
before_filter(options.slice(:only, :except)) { |c| ResourceAuthorization.new(c, c.params, options.except(:only, :except)).authorize_resource }
end
end
def self.included(base)
base.extend ClassMethods
base.helper_method :can?, :cannot?
end
# Raises the CanCan::AccessDenied exception. This is often used in a
# controller action to mark a request as unauthorized.
#
# def show
# @article = Article.find(params[:id])
# unauthorized! if cannot? :read, @article
# end
#
# You can rescue from the exception in the controller to specify
# the user experience.
#
# class ApplicationController < ActionController::Base
# rescue_from CanCan::AccessDenied, :with => :access_denied
#
# protected
#
# def access_denied
# flash[:error] = "Sorry, you are not allowed to access that page."
# redirect_to root_url
# end
# end
#
# See the load_and_authorize_resource method to automatically add
# the "unauthorized!" behavior to a RESTful controller's actions.
def unauthorized!
raise AccessDenied, "You are unable to access this page."
end
# Creates and returns the current user's ability. You generally do not invoke
# this method directly, instead you can override this method to change its
# behavior if the Ability class or current_user method are different.
#
# def current_ability
# UserAbility.new(current_account) # instead of Ability.new(current_user)
# end
#
def current_ability
::Ability.new(current_user)
end
# Use in the controller or view to check the user's permission for a given action
# and object.
#
# can? :destroy, @project
#
# You can also pass the class instead of an instance (if you don't have one handy).
#
# <% if can? :create, Project %>
# <%= link_to "New Project", new_project_path %>
# <% end %>
#
# This simply calls "can?" on the current_ability. See Ability#can?.
def can?(*args)
(@current_ability ||= current_ability).can?(*args)
end
# Convenience method which works the same as "can?" but returns the opposite value.
#
# cannot? :destroy, @project
#
def cannot?(*args)
(@current_ability ||= current_ability).cannot?(*args)
end
end
end
if defined? ActionController
ActionController::Base.class_eval do
include CanCan::ControllerAdditions
end
end