effective_datatables 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +581 -0
  4. data/Rakefile +23 -0
  5. data/app/assets/images/effective_datatables/copy_csv_xls_pdf.swf +0 -0
  6. data/app/assets/javascripts/effective_datatables.bootstrap2.js +11 -0
  7. data/app/assets/javascripts/effective_datatables.js +12 -0
  8. data/app/assets/javascripts/effective_datatables/initialize.js.coffee +65 -0
  9. data/app/assets/javascripts/vendor/jquery.dataTables.columnFilter.js +829 -0
  10. data/app/assets/stylesheets/effective_datatables.bootstrap2.css.scss +8 -0
  11. data/app/assets/stylesheets/effective_datatables.css.scss +8 -0
  12. data/app/assets/stylesheets/effective_datatables/_overrides.scss +72 -0
  13. data/app/controllers/effective/datatables_controller.rb +36 -0
  14. data/app/helpers/effective_datatables_helper.rb +74 -0
  15. data/app/models/effective/access_denied.rb +17 -0
  16. data/app/models/effective/active_record_datatable_tool.rb +87 -0
  17. data/app/models/effective/array_datatable_tool.rb +66 -0
  18. data/app/models/effective/datatable.rb +352 -0
  19. data/app/views/effective/datatables/_datatable.html.haml +11 -0
  20. data/app/views/effective/datatables/_spacer_template.html +1 -0
  21. data/config/routes.rb +11 -0
  22. data/lib/effective_datatables.rb +32 -0
  23. data/lib/effective_datatables/engine.rb +20 -0
  24. data/lib/effective_datatables/version.rb +3 -0
  25. data/lib/generators/effective_datatables/install_generator.rb +17 -0
  26. data/lib/generators/templates/README +1 -0
  27. data/lib/generators/templates/effective_datatables.rb +23 -0
  28. data/lib/tasks/effective_datatables_tasks.rake +17 -0
  29. data/spec/dummy/README.rdoc +261 -0
  30. data/spec/dummy/Rakefile +7 -0
  31. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  32. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  33. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  34. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  35. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  36. data/spec/dummy/config.ru +4 -0
  37. data/spec/dummy/config/application.rb +59 -0
  38. data/spec/dummy/config/boot.rb +10 -0
  39. data/spec/dummy/config/database.yml +25 -0
  40. data/spec/dummy/config/environment.rb +5 -0
  41. data/spec/dummy/config/environments/development.rb +37 -0
  42. data/spec/dummy/config/environments/production.rb +67 -0
  43. data/spec/dummy/config/environments/test.rb +37 -0
  44. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  45. data/spec/dummy/config/initializers/inflections.rb +15 -0
  46. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  47. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  48. data/spec/dummy/config/initializers/session_store.rb +8 -0
  49. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  50. data/spec/dummy/config/locales/en.yml +5 -0
  51. data/spec/dummy/config/routes.rb +58 -0
  52. data/spec/dummy/db/development.sqlite3 +0 -0
  53. data/spec/dummy/db/schema.rb +16 -0
  54. data/spec/dummy/db/test.sqlite3 +0 -0
  55. data/spec/dummy/log/development.log +17 -0
  56. data/spec/dummy/log/test.log +1 -0
  57. data/spec/dummy/public/404.html +26 -0
  58. data/spec/dummy/public/422.html +26 -0
  59. data/spec/dummy/public/500.html +25 -0
  60. data/spec/dummy/public/favicon.ico +0 -0
  61. data/spec/dummy/script/rails +6 -0
  62. data/spec/effective_datatables_spec.rb +7 -0
  63. data/spec/spec_helper.rb +34 -0
  64. data/spec/support/factories.rb +1 -0
  65. metadata +217 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 414d2116620a9a9fc13a0bc1834558b06d962d45
4
+ data.tar.gz: 23396e31fee70831e41f9e90aec1d269c9009248
5
+ SHA512:
6
+ metadata.gz: abb7a4c4b53a0c3218ac24d07cea39fb245eac48d7c8f3764a1362005c7bd012fc20107fd8c6f81b82efcac168e0e6f6c5eee30754b009bc69a66c1a6f003a25
7
+ data.tar.gz: 80a229f44939b2d4762d53e412217443c3f8402fd3be82523e7013809530e517867252800d97e049ab93b19ad9afc4a63b9e98aa80bf11147adabf74940a7450
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Code and Effect Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,581 @@
1
+ # Effective DataTables
2
+
3
+ Uniquely powerful server-side searching, sorting and filtering of any ActiveRecord or Array collection as well as post-rendered content displayed as a frontend jQuery Datatable.
4
+
5
+ Use a simple DSL in just one ruby file to implement all features
6
+
7
+ Search raw database tables and ruby post-rendered results at the same time
8
+
9
+ Packages the jQuery DataTables assets for use in a Rails 3.2.x & Rails 4.x application using Twitter Bootstrap 2 or 3
10
+
11
+ ## Getting Started
12
+
13
+ ```ruby
14
+ gem 'effective_datatables'
15
+ ```
16
+
17
+ Run the bundle command to install it:
18
+
19
+ ```console
20
+ bundle install
21
+ ```
22
+
23
+ Install the configuration file:
24
+
25
+ ```console
26
+ rails generate effective_datatables:install
27
+ ```
28
+
29
+ The generator will install an initializer which describes all configuration options.
30
+
31
+
32
+ Require the javascript on the asset pipeline by adding the following to your application.js:
33
+
34
+ ```ruby
35
+ # For use with Bootstrap3 (which is not included in this gem):
36
+ //= require effective_datatables
37
+
38
+ # For use with Bootstrap2 (which is not includled in this gem):
39
+ //= require effective_datatables.bootstrap2
40
+ ```
41
+
42
+ Require the stylesheet on the asset pipeline by adding the following to your application.css:
43
+
44
+ ```ruby
45
+ # For use with Bootstrap3 (which is not included in this gem):
46
+ *= require effective_datatables
47
+
48
+ # For use with Bootstrap2 (which is not not included in this gem):
49
+ *= require effective_datatables.bootstrap2
50
+ ```
51
+
52
+ ## Usage
53
+
54
+ We create a model, initialize it within our controller, then render it from a view
55
+
56
+ ### The Model
57
+
58
+ Start by creating a model in the `/app/models/effective/datatables/` directory.
59
+
60
+ Any `Effective::Datatable` models that exist in this directory will be automatically detected and 'just work'.
61
+
62
+ Below is a very simple example file, which we will expand upon later.
63
+
64
+ This model exists at `/app/models/effective/datatables/posts.rb`:
65
+
66
+ ```ruby
67
+ module Effective
68
+ module Datatables
69
+ class Posts < Effective::Datatable
70
+ table_column :id
71
+ table_column :user # if Post belongs_to :user
72
+ table_column :title
73
+ table_column :created_at
74
+
75
+ def collection
76
+ Post.all
77
+ end
78
+
79
+ end
80
+ end
81
+ end
82
+ ```
83
+
84
+ ### The Controller
85
+
86
+ We're going to display this DataTable on the posts#index action
87
+
88
+ ```ruby
89
+ class PostsController < ApplicationController
90
+ def index
91
+ @datatable = Effective::Datatables::Posts.new()
92
+ end
93
+ end
94
+ ```
95
+
96
+ ### The View
97
+
98
+ Here we just render the datatable:
99
+
100
+ ```erb
101
+ <h1>All Posts</h1>
102
+
103
+ <% if @datatable.collection.length == 0 %>
104
+ <p>There are no posts.</p>
105
+ <% else %>
106
+ <%= render_datatable(@datatable) %>
107
+ <% end %>
108
+ ```
109
+
110
+ ## How It Works
111
+
112
+ When the jQuery DataTable is first initialized on the front-end, it makes an AJAX request back to the server asking for data.
113
+
114
+ The effective_datatables gem intercepts this request and returns the appropriate results.
115
+
116
+ Whenever a search, sort, filter or pagination is initiated on the front end, that request is interpretted by the server and the appropriate results returned.
117
+
118
+ Due to the unique search/filter ability of this gem, a mix of raw database tables and processed results may be worked with at the same time.
119
+
120
+
121
+ ### Effective::Datatable Model & DSL
122
+
123
+ Once your controller and view are set up to render a Datatable, the model is the central point to configure all behaviour.
124
+
125
+ This single model file contains just 1 required method and responds to only 3 DSL commands.
126
+
127
+ Each `Effective::Datatable` model must be defined in the `/app/models/effective/datatables/` directory.
128
+
129
+ For example: `/app/models/effective/datatables/posts.rb`:
130
+
131
+ ```ruby
132
+ module Effective
133
+ module Datatables
134
+ class Posts < Effective::Datatable
135
+ default_order :created_at, :desc
136
+
137
+ table_column :id, :visible => false
138
+
139
+ table_column :created_at, :width => '25%' do |post|
140
+ post.created_at.strftime("%Y-%m-%d %H:%M:%S")
141
+ end
142
+
143
+ table_column :updated_at, :proc => Proc.new { |post| nicetime(post.updated_at) } # just a standard helper as defined in helpers/application_helper.rb
144
+
145
+ table_column :user
146
+
147
+ table_column :post_category_id, :filter => {:type => :select, :values => Proc.new { PostCategory.all } } do |post|
148
+ post.post_category.name.titleize
149
+ end
150
+
151
+ array_column :comments do |post|
152
+ content_tag(:ul) do
153
+ post.comments.where(:archived => false).map do |comment|
154
+ content_tag(:li, comment.title)
155
+ end.join('').html_safe
156
+ end
157
+ end
158
+
159
+ table_column :title, :label => 'Post Title'
160
+ table_column :actions, :sortable => false, :filter => false, :partial => '/posts/actions'
161
+
162
+ def collection
163
+ Post.where(:archived => false).includes(:post_category)
164
+ end
165
+
166
+ end
167
+ end
168
+ end
169
+ ```
170
+
171
+ ### The collection
172
+
173
+ A required method `def collection` must be defined to return the base ActiveRecord collection.
174
+
175
+ It can be as simple or as complex as you'd like:
176
+
177
+ ```ruby
178
+ def collection
179
+ Posts.all
180
+ end
181
+ ```
182
+
183
+ or (complex example):
184
+
185
+ ```ruby
186
+ def collection
187
+ User.unscoped.uniq
188
+ .joins('LEFT JOIN customers ON customers.user_id = users.id')
189
+ .select('users.*')
190
+ .select('customers.stripe_customer_id AS stripe_customer_id')
191
+ .includes(:addresses)
192
+ end
193
+ ```
194
+
195
+ ## table_column
196
+
197
+ This is the main DSL method that you will interact with.
198
+
199
+ table_column defines a 1:1 mapping between a SQL database table column and a frontend jQuery Datatables table column. It creates a column.
200
+
201
+ Options may be passed to specify the display, search, sort and filter behaviour for that column.
202
+
203
+ When the given name of the table_column matches an ActiveRecord attribute, the options are set intelligently based on the underlying datatype.
204
+
205
+ ```ruby
206
+ # The name of the table column as per the Database
207
+ # This column is detected as an Integer, therefore it is :type => :integer
208
+ # Any SQL used to search this field will take the form of "id = ?"
209
+ table_column :id
210
+
211
+ # As per our 'complex' example above, using the .select('customers.stripe_customer_id AS stripe_customer_id') syntax to create a faux database table
212
+ # This column is detected as a String, therefore it is :type => :string
213
+ # Any SQL used to search this field will take the form of "customers.stripe_customer_id ILIKE %?%"
214
+ table_column :stripe_customer_id, :column => 'customers.stripe_customer_id'
215
+
216
+ # The name of the table column as per the Database
217
+ # This column is detected as a DateTime, therefore it is :type => :datetime
218
+ # Any SQL used to search this field will take the form of
219
+ # "to_char(#{column} AT TIME ZONE 'GMT', 'YYYY-MM-DD HH24:MI') ILIKE '%?%'"
220
+ table_column :created_at
221
+
222
+ # If the name of the table column matches a belongs_to in our collection's main class
223
+ # This column will be detected as a belongs_to and some predefined filters will be set up
224
+ # So declaring the following
225
+ table_column :user
226
+
227
+ # Will have the same behaviour as declaring
228
+ table_column :user_id, :if => Proc.new { attributes[:user_id].blank? }, :filter => {:type => :select, :values => Proc.new { User.all.map { |user| [user.id, user.to_s] }.sort { |x, y| x[1] <=> y[1] } } } do |post|
229
+ post.user.to_s
230
+ end
231
+ ```
232
+
233
+ All table_columns are `:visible => true`, `:sortable => true` by default.
234
+
235
+ ### General Options
236
+
237
+ The following options control the general behaviour of the column:
238
+
239
+ ```ruby
240
+ :column => 'users.id' # Set this if you're doing something tricky with the database. Used internally for .order() and .where() clauses
241
+ :type => :string # Derived from the ActiveRecord attribute default datatype. Controls searching behaviour. Valid options include :string, :text, :datetime, :integer, :boolean, :year
242
+ :if => Proc.new { attributes[:user_id].blank? } # Excludes this table_column entirely if false. See "Initialize with attributes" section of this README below
243
+ ```
244
+
245
+ ### Display Options
246
+
247
+ The following options control the display behaviour of the column:
248
+
249
+ ```ruby
250
+ :label => 'Nice Label' # Override the default column header label
251
+ :sortable => true|false # Allow sorting of this column. Otherwise the up/down arrows on the frontend will be disabled.
252
+ :visible => true|false # Hide this column at startup. Column visbility can be changed on the frontend. By default, hidden column filter terms are ignored.
253
+ :width => '100%'|'100px' # Set the width of this column. Can be set on one, all or some of the columns. If using percentages, should never add upto more than 100%
254
+ ```
255
+
256
+ ### Filtering Options
257
+
258
+ Setting a filter will create an appropriate text/number/select input in the header row of the column.
259
+
260
+ The following options control the filtering behaviour of the column:
261
+
262
+ ```ruby
263
+ table_column :created_at, :filter => false # Disable filtering on this column entirely
264
+ table_column :created_at, :filter => {...} # Enable filtering with these options
265
+
266
+ :filter => {:type => :number}
267
+ :filter => {:type => :text}
268
+
269
+ :filter => {:type => :select, :values => ['One', 'Two'], :selected => 'Two'}
270
+ :filter => {:type => :select, :values => [*2010..(Time.zone.now.year+6)]}
271
+ :filter => {:type => :select, :values => Proc.new { PostCategory.all } }
272
+ :filter => {:type => :select, :values => Proc.new { User.all.order(:email).map { |obj| [obj.id, obj.email] } } }
273
+ ```
274
+
275
+ Some additional, lesser used options include:
276
+
277
+ ```ruby
278
+ :filter => {:when_hidden => true} # By default a hidden column's search filter will be ignored, unless this is true. Can be used for scoping.
279
+ :filter => {:fuzzy => true} # Will use an ILIKE/includes rather than = when filtering. Use this for selects.
280
+ ```
281
+
282
+ ### Rendering Options
283
+
284
+ There are a few different ways to render each column's output.
285
+
286
+ Any standard view helpers like `link_to` or `simple_format` and any custom helpers available to your views will be available.
287
+
288
+ All of the following rendering options can be used interchangeably:
289
+
290
+ Block format (really, this is your cleanest option):
291
+
292
+ ```ruby
293
+ table_column :created_at do |post|
294
+ if post.created_at > (Time.zone.now-1.year)
295
+ link_to('this year', post_path(post))
296
+ else
297
+ link_to(post.created_at.strftime("%Y-%m-%d %H:%M:%S"), post_path(post))
298
+ end
299
+ end
300
+ ```
301
+
302
+ Proc format:
303
+
304
+ ```ruby
305
+ table_column :created_at, :proc => Proc.new { |post| link_to(post.created_at, post_path(post)) }
306
+ ```
307
+
308
+ Partial format:
309
+
310
+ ```ruby
311
+ table_column :actions, :partial => '/posts/actions' # render this partial for each row of the table
312
+ ```
313
+
314
+ then in your `/app/views/posts/_actions.html.erb` file:
315
+
316
+ ```erb
317
+ <p><%= link_to('View', post_path(post)) %></p>
318
+ <p><%= link_to('Edit', edit_post_path(post)) %></p>
319
+ ```
320
+
321
+ The local object name will either match the database table singular name `post`, the name of the partial `actions`, or `obj` unless overridden with:
322
+
323
+ ```ruby
324
+ table_column :actions, :partial => '/posts/actions', :partial_local => 'the_post'
325
+ ```
326
+
327
+ There are also a built in helper, `datatables_admin_path?` to considering if the current screen is in the `/admin` namespace:
328
+
329
+ ```ruby
330
+ table_column :created_at do |post|
331
+ if datatables_admin_path?
332
+ link_to admin_posts_path(post)
333
+ else
334
+ link_to posts_path(post)
335
+ end
336
+ end
337
+ ```
338
+
339
+ The request object is available to the table_column, so you could just as easily call:
340
+
341
+ ```ruby
342
+ request.referer.include?('/admin/')
343
+ ```
344
+
345
+
346
+ ## table_columns
347
+
348
+ Quickly create multiple table_columns all with default options:
349
+
350
+ ```ruby
351
+ table_columns :id, :created_at, :updated_at, :category, :title
352
+ ```
353
+
354
+ ## array_column
355
+
356
+ `array_column` accepts the same options as `table_column` and behaves identically on the frontend.
357
+
358
+ The difference occurs with sorting and filtering:
359
+
360
+ With a `table_column`, the frontend sends some search terms to the server, the raw database table is searched & sorted using standard ActiveRecord .where(), the appropriate rows returned, and then each row is rendered as per the rendering options.
361
+
362
+ With an `array_column`, the front end sends some search terms to the server, all rows are returned and rendered, and then the rendered output is searched & sorted.
363
+
364
+ This allows the output of an `array_column` to be anything complex that cannot be easily computed from the database.
365
+
366
+ When searching & sorting with a mix of table_columns and array_columns, all the table_columns are processed first so the most work is put on the database, the least on rails.
367
+
368
+
369
+ ## default_order
370
+
371
+ Sort the table by this field and direction on start up
372
+
373
+ ```ruby
374
+ default_order :created_at, :asc|:desc
375
+ ```
376
+
377
+ ## Additional Functionality
378
+
379
+ There are a few other ways to customize the behaviour of effective_datatables
380
+
381
+ ### Customize Filter Behaviour
382
+
383
+ This gem does its best to provide "just works" filtering of both raw SQL (table_column) and processed results (array_column) out-of-the-box.
384
+
385
+ It's also very easy to override the filter behaviour on a per-column basis.
386
+
387
+ Keep in mind, columns that are hidden will not be considered by the filter results unless `:filter => {:when_hidden => true}` is passed to table_column
388
+
389
+ For custom filter behaviour, specify a `def search_column` method in the datatables model file:
390
+
391
+ ```ruby
392
+ def collection
393
+ User.unscoped.uniq
394
+ .joins('LEFT JOIN customers ON customers.user_id = users.id')
395
+ .select('users.*')
396
+ .select('customers.stripe_customer_id AS stripe_customer_id')
397
+ .includes(:addresses)
398
+ end
399
+
400
+ def search_column(collection, table_column, search_term)
401
+ if table_column[:name] == 'subscription_types'
402
+ collection.where('subscriptions.stripe_plan_id ILIKE ?', "%#{search_term}%")
403
+ else
404
+ super
405
+ end
406
+ end
407
+ ```
408
+
409
+ ### Initialize with attributes
410
+
411
+ Any attributes passed to `.new()` will be persisted through the lifecycle of the datatable.
412
+
413
+ You can use this to scope the datatable collection or create even more advanced search behaviour.
414
+
415
+ In the following example we will hide the User column and scope the collection to a specific user.
416
+
417
+ In your controller:
418
+
419
+ ```ruby
420
+ class PostsController < ApplicationController
421
+ def index
422
+ @datatable = Effective::Datatables::Posts.new(:user_id => current_user.try(:id))
423
+ end
424
+ end
425
+ ```
426
+
427
+ Scope the query to the passed user in in your collection method:
428
+
429
+ ```ruby
430
+ def collection
431
+ if attributes[:user_id]
432
+ Post.where(:user_id => attributes[:user_id])
433
+ else
434
+ Post.all
435
+ end
436
+ end
437
+ ```
438
+
439
+ and remove the table_column when a user_id is present:
440
+
441
+ ```ruby
442
+ table_column :user_id, :if => Proc.new { attributes[:user_id].blank? } do |post|
443
+ post.user.email
444
+ end
445
+ ```
446
+
447
+ ## Array Backed collection
448
+
449
+ Don't want to use ActiveRecord? Not a problem.
450
+
451
+ Define your collection as an Array of Arrays, declare only array_columns, and everything works as expected.
452
+
453
+ ```ruby
454
+ module Effective
455
+ module Datatables
456
+ class ArrayBackedDataTable < Effective::Datatable
457
+ array_column :id
458
+ array_column :first_name
459
+ array_column :last_name
460
+ array_column :email
461
+
462
+ def collection
463
+ [
464
+ [1, 'Matthew', 'Riemer', 'matthew@agilestyle.com'],
465
+ [2, 'Dallas', 'Meidinger', 'dallas@agilestyle.com'],
466
+ [3, 'Warren', 'Uhrich', 'warren@agilestyle.com'],
467
+ [4, 'Stephen', 'Brown', 'stephen@agilestyle.com'],
468
+ [5, 'Dana', 'Janssen', 'dana@agilestyle.com'],
469
+ [6, 'Ashley', 'Janssen', 'ashley@agilestyle.com'],
470
+ ]
471
+ end
472
+
473
+ end
474
+ end
475
+ end
476
+ ```
477
+
478
+ ## Get access to the raw results
479
+
480
+ After all the searching, sorting and rendering of final results is complete, the server sends back an Array of Arrays to the front end jQuery DataTable
481
+
482
+ The finalize method provides a hook to process the final collection as an Array of Arrays just before it is convered to JSON.
483
+
484
+ This final collection is available after searching, sorting and pagination.
485
+
486
+ As you have full control over the table_column presentation, I can't think of any reason you would actually need or want this:
487
+
488
+ ```ruby
489
+ def finalize(collection)
490
+ collection.each do |row|
491
+ row.each do |column|
492
+ column.gsub!('horse', 'force') if column.kind_of?(String)
493
+ end
494
+ end
495
+ end
496
+ ```
497
+
498
+ ## Authorization
499
+
500
+ All authorization checks are handled via the config.authorization_method found in the `config/initializers/effective_datatables.rb` file.
501
+
502
+ It is intended for flow through to CanCan or Pundit, but neither of those gems are required.
503
+
504
+ This method is called by the controller action with the appropriate action and resource
505
+
506
+ Action will be `:index`
507
+
508
+ The resource will be the collection base class, such as `Post`. This can be overridden:
509
+
510
+ ```ruby
511
+ def collection_class
512
+ NotPost
513
+ end
514
+ ```
515
+
516
+ The authorization method is defined in the initializer file:
517
+
518
+ ```ruby
519
+ # As a Proc (with CanCan)
520
+ config.authorization_method = Proc.new { |controller, action, resource| authorize!(action, resource) }
521
+ ```
522
+
523
+ ```ruby
524
+ # As a Custom Method
525
+ config.authorization_method = :my_authorization_method
526
+ ```
527
+
528
+ and then in your application_controller.rb:
529
+
530
+ ```ruby
531
+ def my_authorization_method(action, resource)
532
+ current_user.is?(:admin) || EffectivePunditPolicy.new(current_user, resource).send('#{action}?')
533
+ end
534
+ ```
535
+
536
+ or disabled entirely:
537
+
538
+ ```ruby
539
+ config.authorization_method = false
540
+ ```
541
+
542
+ If the method or proc returns false (user is not authorized) an `Effective::AccessDenied` exception will be raised
543
+
544
+ You can rescue from this exception by adding the following to your application_controller.rb:
545
+
546
+ ```ruby
547
+ rescue_from Effective::AccessDenied do |exception|
548
+ respond_to do |format|
549
+ format.html { render 'static_pages/access_denied', :status => 403 }
550
+ format.any { render :text => 'Access Denied', :status => 403 }
551
+ end
552
+ end
553
+ ```
554
+
555
+
556
+ ## License
557
+
558
+ MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
559
+
560
+ Code and Effect is the product arm of [AgileStyle](http://www.agilestyle.com/), an Edmonton-based shop that specializes in building custom web applications with Ruby on Rails.
561
+
562
+
563
+ ## Testing
564
+
565
+ The test suite for this gem is unfortunately not yet complete.
566
+
567
+ Run tests by:
568
+
569
+ ```ruby
570
+ rake spec
571
+ ```
572
+
573
+ ## Contributing
574
+
575
+ 1. Fork it
576
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
577
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
578
+ 4. Push to the branch (`git push origin my-new-feature`)
579
+ 5. Bonus points for test coverage
580
+ 6. Create new Pull Request
581
+