irie 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 70d0c4b896c361b3118094166c14bae9a734a530
4
+ data.tar.gz: ea3ff0813dabc51ba793191d92797f8c9f2b6704
5
+ SHA512:
6
+ metadata.gz: 9733f3a4277253428161f1c4b735832fbd5f53bf958b48236a90ec2a5249d143fe476d15814536126d3a690e47ef9fc5c53e6271af89dca314069837072acb62
7
+ data.tar.gz: c4b1a88c2571906e7378ee09a76409f2669dcd41e5402da6b55927881dfd33a9baf4e9bb248e6cbedd9dea7de921e05cceac16a6e0f56b17e8ac0ce9e4cdf7ba
data/README.md ADDED
@@ -0,0 +1,657 @@
1
+ [![Build Status](https://secure.travis-ci.org/FineLinePrototyping/irie.png?branch=master)][travis] [![Gem Version](https://badge.fury.io/rb/irie.png)][badgefury]
2
+
3
+ # Irie
4
+
5
+ Inherited Resources including extensions. Tested with Rails 4/edge, Inherited Resources 1.4/edge in Ruby 1.9.3, 2.0.0, and jruby-19mode.
6
+
7
+ Extend [Inherited Resources][inherited_resources] actions with the `extensions` method which provides symbolic references to do module includes as well as automatic inclusion of modules based on what actions are in-use. The included extensions provide more of a DSL-like way to define your controllers, and instead of model-heavy development via `scope` in models and `has_scope` in the controller, you can just define request parameter-based filters and their defaults in the controller. Also, ordering, parameter conversion, param value split delimiters, pagination, and more are supported.
8
+
9
+ ```ruby
10
+ class PostsController < ApplicationController
11
+
12
+ respond_to :json
13
+ inherit_resources
14
+
15
+ actions :index
16
+ extensions :count, :limit, :offset, :paging
17
+
18
+ can_filter_by :author, through: {author: :name}
19
+ default_filter_by :author, eq: 'anonymous'
20
+
21
+ can_filter_by :posted_on, using: [:lt, :eq, :gt]
22
+ default_filter_by :posted_on, gt: 1.year.ago
23
+
24
+ can_filter_by :company, through: {author: {company: :name}
25
+
26
+ can_order_by :posted_on, :author, :id
27
+ default_order_by {:posted_on => :desc}, :id
28
+
29
+ end
30
+ ```
31
+
32
+ Then set up your routes and any views.
33
+
34
+ Now here are some of the URLs you can hit:
35
+
36
+ ```
37
+ https://example.org/posts?author=John
38
+ https://example.org/posts?posted_on.gt=2012-08-08
39
+ https://example.org/posts?posted_on.gt=2012-08-08&count=
40
+ https://example.org/posts?company=Lipton
41
+ https://example.org/posts?page_count=
42
+ https://example.org/posts?page=1
43
+ https://example.org/posts?offset=30&limit=15
44
+ https://example.org/posts?order=author,-id
45
+ ```
46
+
47
+ You can also define a query to allow only admins to see private posts:
48
+
49
+ ```ruby
50
+ index_query ->(q) { @current_user.admin? ? q : q.where(:access => 'public') }
51
+ ```
52
+
53
+ and change the query depending on a supplied param:
54
+
55
+ ```ruby
56
+ can_filter_by_query \
57
+ status: ->(q, status) {
58
+ status == 'all' ? q : q.where(:status => status)
59
+ },
60
+ color: ->(q, color) {
61
+ if color == 'red'
62
+ q.where("color = 'red' or color = 'ruby'")
63
+ else
64
+ q.where(:color => color)
65
+ end
66
+ }
67
+ ```
68
+
69
+ Note: `extensions` also automatically includes common sets of extensions with certain actions. So, just specify `extensions` by itself can include things you can use, e.g.
70
+
71
+ ```ruby
72
+ class PostsController < ApplicationController
73
+ inherit_resources
74
+
75
+ actions :index
76
+ extensions
77
+ end
78
+ ```
79
+
80
+ ### Installation
81
+
82
+ In your Rails app's `Gemfile`:
83
+
84
+ ```ruby
85
+ gem 'irie'
86
+ ```
87
+
88
+ Then:
89
+
90
+
91
+ ```
92
+ bundle install
93
+ ```
94
+
95
+ ### Application Configuration
96
+
97
+ Each application-level configuration option can be configured one line at a time:
98
+
99
+ ```ruby
100
+ ::Irie.number_of_records_in_a_page = 30
101
+ ```
102
+
103
+ or in bulk, like:
104
+
105
+ ```ruby
106
+ ::Irie.configure do
107
+
108
+ # Default for :using in can_filter_by.
109
+ self.can_filter_by_default_using = [:eq]
110
+
111
+ # Use one or more alternate request parameter names for functions, e.g.
112
+ # `self.function_param_names = {distinct: :very_distinct, limit: [:limit, :limita]}`
113
+ self.function_param_names = {}
114
+
115
+ # Delimiter for ARel predicate in the request parameter name.
116
+ self.predicate_prefix = '.'
117
+
118
+ # You'd set this to false if id is used for something else other than primary key.
119
+ self.id_is_primary_key_param = true
120
+
121
+ # Used when paging is enabled.
122
+ self.number_of_records_in_a_page = 15
123
+
124
+ # Included if the action method exists when `extensions` is called.
125
+ self.autoincludes = {
126
+ create: [:smart_layout, :query_includes],
127
+ destroy: [:smart_layout, :query_includes],
128
+ edit: [:smart_layout, :query_includes],
129
+ index: [:smart_layout, :index_query, :order, :param_filters, :params_to_joins, :query_filter, :query_includes],
130
+ new: [:smart_layout],
131
+ show: [:smart_layout, :query_includes],
132
+ update: [:smart_layout, :query_includes]
133
+ }
134
+
135
+ end
136
+ ```
137
+
138
+ You may want to put your configuration in an initializer like `config/initializers/irie.rb`.
139
+
140
+ ### Controller Configuration
141
+
142
+ The default controller config may be fine, but you can customize it.
143
+
144
+ In the controller, you can set a variety of class attributes with `self.something = ...` in the body of your controller.
145
+
146
+ All of the app-level configuration parameters are configurable in the controller class body, e.g.:
147
+
148
+ ```ruby
149
+ self.can_filter_by_default_using = [:eq]
150
+ self.function_param_names = {}
151
+ self.predicate_prefix = '.'
152
+ self.number_of_records_in_a_page = 15
153
+ self.id_is_primary_key_param = true
154
+ self.update_should_return_entity = false
155
+ ```
156
+
157
+ #### About Extensions
158
+
159
+ As you may have noticed in `autoincludes`, some concerns are included as a package along with the action include.
160
+
161
+ The following assumes that you are using the default autoincludes and included the relevant action.
162
+
163
+ #### Filtering by Attribute(s)
164
+
165
+ Inherited Resources has `has_scope` via the [has_scope][has_scope] dependency, which is still available for use, and is very powerful. But, Irie also has `can_filter_by`. It is an alternative, not a replacement.
166
+
167
+ Unlike `has_scope`, `can_filter_by` doesn't require a `scope` on the model and `has_scope` on the controller. Instead you just have a single `can_filter_by` in the controller rather. Other differences are that the request parameter syntax is more brief, and it adds support for defining deeply associated attributes via either `define_params` or a `through` option.
168
+
169
+ Like the combination of `scope` and `has_scope`, `can_filter_by` filters the index action the request parameter name as a symbol will filter the results by the value of that request parameter, e.g. assuming `:eq` is in the configured `can_filter_by_default_using` in your config, as it is by default:
170
+
171
+ ```ruby
172
+ can_filter_by :title
173
+ ```
174
+
175
+ allows you to:
176
+
177
+ ```
178
+ http://localhost:3000/posts?title=Awesome
179
+ ```
180
+
181
+ or
182
+
183
+ ```
184
+ http://localhost:3000/posts?title.eq=Awesome
185
+ ```
186
+
187
+ Since `.eq` is optional in the param name.
188
+
189
+ And, like `has_scope`, predications are supported. Do `Arel::Predications.public_instance_methods.sort` in Rails console to see the list:
190
+
191
+ ```ruby
192
+ :does_not_match, :does_not_match_all, :does_not_match_any, :eq, :eq_all, :eq_any, :gt,
193
+ :gt_all, :gt_any, :gteq, :gteq_all, :gteq_any, :in, :in_all, :in_any, :lt, :lt_all,
194
+ :lt_any, :lteq, :lteq_all, :lteq_any, :matches, :matches_all, :matches_any, :not_eq,
195
+ :not_eq_all, :not_eq_any, :not_in, :not_in_all, :not_in_any
196
+ ```
197
+
198
+ You can specify these via the `using:` option:
199
+
200
+ ```ruby
201
+ can_filter_by :seen_on, using: [:gteq, :eq_any]
202
+ ```
203
+
204
+ For predicates that take more than one value, by default it expects that you send in multiple request parameters, that way if a value contains something that would be a delimiter of the value, you don't have to worry about additional escaping characters in the value to what you'd have to do otherwise. But, if a value is numeric, for example, you might want to be able to specify a comma-delimited list, and you can do so via:
205
+
206
+ ```ruby
207
+ can_filter_by :mileage, using: [:eq_any], split: ","
208
+ ```
209
+
210
+ Unlike `has_scope` which uses a much lengthier request parameter syntax, by appending the predicate prefix (`.` by default) to the request parameter name, you can use any [ARel][arel] predicate you allowed, e.g.:
211
+
212
+ ```
213
+ http://localhost:3000/posts?seen_on.gteq=2012-08-08
214
+ ```
215
+
216
+ And, `can_filter_by` supports (inner) joins created by `define_params` or if you'd rather, you can specify a `:through` which (inner) joins and sets the deepest symbol in the hash as the key for the parameter value, then does a where, e.g.:
217
+
218
+ ```ruby
219
+ can_filter_by :name, through: {company: {employee: :full_name}}
220
+ ```
221
+
222
+ If a MagicalUnicorn `has_many :friends` and a MagicalUnicorn's friend has a name attribute:
223
+
224
+ ```ruby
225
+ can_filter_by :magical_unicorn_friend_name,
226
+ through: {magical_unicorns:{friends: :name}}
227
+ ```
228
+
229
+ and use this to get valleys associated with unicorns who in turn have a friend named Oscar:
230
+
231
+ ```
232
+ http://localhost:3000/magical_valleys?magical_unicorn_friend_name=Oscar
233
+ ```
234
+
235
+ Similar to specifying a proc/lambda in the `scope` and then using `has_scope` to use it, or defining a `scope` in the model and defining `has_scope` and passing a block into it, you can use `can_filter_by_query`, but again you only have to define something in the controller- not the model and controller. It works a little bit differently; the proc/lambda is in the context of the controller, so unlike the `has_scope` that takes a block, the `controller` doesn't have to be passed in, since that is `self`. The relation object is passed in as `q`, e.g.:
236
+
237
+ ```ruby
238
+ can_filter_by_query a_request_param_name: ->(q, param_value_or_values) {
239
+ q.joins(:some_assoc).where(some_assocs_table_name: {some_attr: param_value_or_values})
240
+ }
241
+ ```
242
+
243
+ The second argument sent to the lambda (`param_value_or_values`) is the request parameter value converted by the `convert_param(param_name, param_values)` method, which may be customized through included extensions or your own extension. See elsewhere in this document for more information about the behavior of this method.
244
+
245
+ The return value of the lambda becomes the new query, so you could really change the behavior of the query depending on the request parameter provided.
246
+
247
+ ##### Customizing Request Parameter Value Conversion
248
+
249
+ Implement the `convert_param(param_name, param_values)` in your controller or an included module, e.g.
250
+
251
+ ```ruby
252
+ # example of custom parameter value converter
253
+ module Example
254
+ module BooleanParams
255
+ extend ::ActiveSupport::Concern
256
+
257
+ TRUE_VALUE = 'true'.freeze
258
+ FALSE_VALUE = 'false'.freeze
259
+
260
+ protected
261
+
262
+ # Converts request param value(s) 'true' to true and 'false' to false
263
+ def convert_param(param_name, param_value_or_values)
264
+ logger.debug("Example::BooleanParams.convert_param(#{param_name.inspect}, #{param_value_or_values.inspect})") if ::Irie.debug?
265
+ param_value_or_values = super if defined?(super)
266
+ if param_value_or_values.is_a? Array
267
+ param_value_or_values.map {|v| convert_boolean(v)}
268
+ else
269
+ convert_boolean(param_value_or_values)
270
+ end
271
+ end
272
+
273
+ private
274
+
275
+ def convert_boolean(value)
276
+ case value
277
+ when TRUE_VALUE
278
+ true
279
+ when FALSE_VALUE
280
+ false
281
+ else
282
+ value
283
+ end
284
+ end
285
+ end
286
+ end
287
+ ```
288
+
289
+ #### Default Filters
290
+
291
+ Like the combination of `scope` and `has_scope` available via [has_scope][has_scope], which you can still use, defaults are supported that are compatible with `can_filter_by`.
292
+
293
+ Specify default filters to define attributes, ARel predicates, and values to use if no filter is provided by the client with the same param name, e.g. if you have:
294
+
295
+ ```ruby
296
+ can_filter_by :attr_name_1
297
+ can_filter_by :production_date, :creation_date, using: [:gt, :eq, :lteq]
298
+ default_filter_by :attr_name_1, eq: 5
299
+ default_filter_by :production_date, :creation_date, gt: 1.year.ago,
300
+ lteq: 1.year.from_now
301
+ ```
302
+
303
+ and both `attr_name_1` and `production_date` are supplied by the client, then it would filter by the client's `attr_name_1` and `production_date` and filter creation_date by both > 1 year ago and <= 1 year from now.
304
+
305
+ #### Extensions
306
+
307
+ ##### Count
308
+
309
+ In the controller:
310
+
311
+ ```ruby
312
+ extensions :count
313
+ ```
314
+
315
+ enables:
316
+
317
+ ```
318
+ http://localhost:3000/posts?count=
319
+ ```
320
+
321
+ That will set the `@count` instance variable that you can use in your view.
322
+
323
+ Use `extensions :autorender_count` to render count automatically for non-HTML (JSON, etc.) views.
324
+
325
+ ##### Page Count
326
+
327
+ In the controller:
328
+
329
+ ```ruby
330
+ extensions :paging
331
+ ```
332
+
333
+ enables:
334
+
335
+ ```
336
+ http://localhost:3000/posts?page_count=
337
+ ```
338
+
339
+ That will set the `@page_count` instance variable that you can use in your view.
340
+
341
+ Use `extensions :autorender_page_count` to render count automatically for non-HTML (JSON, etc.) views.
342
+
343
+ ##### Getting a Page
344
+
345
+ In the controller:
346
+
347
+ ```ruby
348
+ extensions :paging
349
+ ```
350
+
351
+ To access each page of results:
352
+
353
+ ```
354
+ http://localhost:3000/posts?page=1
355
+ http://localhost:3000/posts?page=2
356
+ ```
357
+
358
+ To set page size at application level:
359
+
360
+ ```ruby
361
+ ::Irie.number_of_records_in_a_page = 15
362
+ ```
363
+
364
+ To set page size at controller level:
365
+
366
+ ```ruby
367
+ self.number_of_records_in_a_page = 15
368
+ ```
369
+
370
+ ##### Offset and Limit
371
+
372
+ In the controller:
373
+
374
+ ```ruby
375
+ extensionss :offset, :limit
376
+ ```
377
+
378
+ enables:
379
+
380
+ ```
381
+ http://localhost:3000/posts?offset=5
382
+ http://localhost:3000/posts?limit=5
383
+ ```
384
+
385
+ You can combine them to act like page:
386
+
387
+ ```
388
+ http://localhost:3000/posts?limit=15
389
+ http://localhost:3000/posts?offset=15&limit=15
390
+ http://localhost:3000/posts?offset=30&limit=15
391
+ ```
392
+
393
+ #### Order
394
+
395
+ You can allow request specified order:
396
+
397
+ ```ruby
398
+ can_order_by :foo_date, :foo_color
399
+ ```
400
+
401
+ Will let the client send the order parameter with those parameters and optional +/- prefix to designate sort direction, e.g. the following will sort by foo_date ascending then foo_color descending:
402
+
403
+ ```
404
+ http://localhost:3000/posts?order=foo_date,-foo_color
405
+ ```
406
+
407
+ The `default_order_by` specifies an ordered array of ascending attributes and/or hashes of attributes to sort direction:
408
+
409
+ ```ruby
410
+ default_order_by :posted_at => :desc, :id => :desc
411
+ ```
412
+
413
+ or:
414
+
415
+ ```ruby
416
+ default_order_by {:this_is_desc => :desc}, :this_is_asc,
417
+ {:no_different_than_a_symbol => :asc},
418
+ :this_is_asc_also, :id => :desc
419
+ ```
420
+
421
+ `can_order_by` and `default_order_by` support joins/`names_params` as well as a `through` option on `can_order_by` similar to `can_filter_by`.
422
+
423
+ #### Custom Index Queries
424
+
425
+ To filter the list where the status_code attribute is 'green':
426
+
427
+ ```ruby
428
+ index_query ->(q) { q.where(:status_code => 'green') }
429
+ ```
430
+
431
+ You can also filter out items that have associations that don't have a certain attribute value (or anything else you can think up with [ARel][arel]/[ActiveRecord relations][ar]), e.g. to filter the list where the object's apples and pears associations are green:
432
+
433
+ ```ruby
434
+ index_query ->(q) {
435
+ q.joins(:apples, :pears)
436
+ .where(apples: {color: 'green'})
437
+ .where(pears: {color: 'green'})
438
+ }
439
+ ```
440
+
441
+ To avoid n+1 queries, use `.includes(...)` in your query to eager load any associations that you will need in the JSON view.
442
+
443
+ #### Smart Layout
444
+
445
+ By default, Rails rendering goes through some extra hoops to attempt to find your layout unless you tell it not to, so With default autoincludes, Irie will use the `:smart_layout` extension to specify `layout: false` unless the request format is html.
446
+
447
+ #### Avoid n+1 Queries
448
+
449
+ ```ruby
450
+ # load all the posts and the associated category and comments for each post
451
+ query_includes :category, :comments
452
+ ```
453
+
454
+ or
455
+
456
+ ```ruby
457
+ # load all of the associated posts, the associated posts’ tags and comments, and every comment’s guest association
458
+ query_includes posts: [{comments: :guest}, :tags]
459
+ ```
460
+
461
+ and action-specific:
462
+
463
+ ```ruby
464
+ query_includes_for :create, are: [:category, :comments]
465
+ query_includes_for :index, :show, are: [posts: [{comments: :guest}, :tags]]
466
+ ```
467
+
468
+ #### Using define_params vs :through option
469
+
470
+ The `:through` option in `can_filter_by` and `can_order_by` just uses `define_params` to set the attribute name alias and options (which is parsed into a joins hash and attribute name internally). So, if you don't mind a little more typing, it might make the intent clearer, e.g.
471
+
472
+ ```ruby
473
+ define_params name: {company: {employee: :full_name}},
474
+ color: :external_color
475
+ can_filter_by :name
476
+ default_filter_by :name, eq: 'Guest'
477
+ can_order_by :color
478
+ default_filter_by :color, eq: 'blue'
479
+ ```
480
+
481
+ #### Other Extensions
482
+
483
+ The following concerns, which you can include via `extensions ...` or via including the corresponding module, might also be of use in your controller:
484
+
485
+ * `:nil_params` - convert 'NULL', 'null', and 'nil' to nil when passed in as request params.
486
+
487
+ #### Writing Your Own Extensions
488
+
489
+ Extensions are just modules. There is no magic.
490
+
491
+ The somewhat special thing about Irie extensions if that you can `@action_result = ...; throw(:action_break)` in any method that is called by an Irie action and it will break the execution of the action and return `@action_result`. This allows the ease of control that you'd have typically in a single long action method, but lets you use modules to easily share action method functionality. To those unfamiliar, `throw` in Ruby is a normal flow control mechanism, unlike `raise` which is for exceptions.
492
+
493
+ Some hopefully good examples of how to extend modules are in lib/irie/extensions/* and the actions themselves are in lib/irie/actions/*. Get familiar with the code even if you don't plan on customizing, if for no other reason than to have another set of eyes on the code.
494
+
495
+ Here's another example:
496
+
497
+ ```ruby
498
+ # Converts all 'true' and 'false' param values to true and false
499
+ module BooleanParams
500
+ extend ::ActiveSupport::Concern
501
+
502
+ protected
503
+
504
+ def convert_param(param_name, param_values)
505
+ case param_values
506
+ when 'true'
507
+ true
508
+ when 'false'
509
+ false
510
+ else
511
+ super if defined?(super)
512
+ end
513
+ end
514
+
515
+ end
516
+ ```
517
+
518
+ If you are just doing regular `include`'s in your controllers, that's all you need. If you'd like to use `extensions`, you get autoincludes and can use symbols, e.g. in `app/controllers/concerns/service_controller.rb`:
519
+
520
+ ```ruby
521
+ module ServiceController
522
+ extend ::ActiveSupport::Concern
523
+
524
+ included do
525
+ inherit_resources
526
+ respond_to :json
527
+
528
+ # reference as string so we don't load the concern before it is used.
529
+ ::Irie.register_extension :boolean_params, '::Example::BooleanParams'
530
+
531
+ # register_extension also can define the order of inclusion, e.g.:
532
+ # ::Irie.register_extension :boolean_params, '::Example::BooleanParams', include: :last #default
533
+ # ::Irie.register_extension :boolean_params, '::Example::BooleanParams', include: :first
534
+ # ::Irie.register_extension :boolean_params, '::Example::BooleanParams', after: :nil_params
535
+ # ::Irie.register_extension :boolean_params, '::Example::BooleanParams', before: :nil_params
536
+
537
+ end
538
+
539
+ end
540
+ ```
541
+
542
+ Now you could use this in your controller:
543
+
544
+ ```ruby
545
+ include ServiceController
546
+
547
+ actions :index
548
+ extensions :boolean_params
549
+ ```
550
+
551
+ Doing that doesn't make as much sense when you just have modules in the root namespace, but it might if you have longer namespaces for organization and to avoid class/module name conflicts.
552
+
553
+ #### Primary Keys
554
+
555
+ Supports composite primary keys. If `resource_class.primary_key.is_a?(Array)`, show/edit/update/destroy will use your two or more request params for the ids that make up the composite.
556
+
557
+ #### Exception Handling
558
+
559
+ Rails 4 has basic exception handling in the [public_exceptions][public_exceptions] and [show_exceptions][show_exceptions] Rack middleware.
560
+
561
+ If you want to customize Rails 4's Rack exception handling, search the web for customizing `config.exceptions_app`, although the default behavior should work for most.
562
+
563
+ You can also use `rescue_from` or `around_action` in Rails to have more control over error rendering.
564
+
565
+ ### Troubleshooting
566
+
567
+ #### Irie::Extensions::QueryIncludes
568
+
569
+ If you get `missing FROM-clause entry for table` errors, it might mean that `query_includes`/`query_includes_for` you are using are overlapping with joins that are being done in the query. This is the nasty head of AR relational includes, unfortunately.
570
+
571
+ To fix, you may decide to either: (1) change order/definition of includes in `query_includes`/`query_includes_for`, (2) don't use `query_includes`/`query_includes_for` for the actions it affects (may cause n+1 queries), (3) implement `apply_includes` to do includes in an appropriate order (messy), or (4) use custom query (if index/custom list action) to define joins with handcoded SQL, e.g. (thanks to Tommy):
572
+
573
+ ```ruby
574
+ index_query ->(q) {
575
+ # Using standard joins performs an INNER JOIN like we want, but doesn't
576
+ # eager load.
577
+ # Using includes does an eager load, but does a LEFT OUTER JOIN, which
578
+ # isn't really what we want, but in this scenario is probably ok.
579
+ # Using standard joins & includes results in bad SQL with table aliases.
580
+ # So, using includes & custom joins seems like a decent solution.
581
+ q.includes(:bartender, :waitress, :owner, :customer)
582
+ .joins('INNER JOIN employees bartenders ON bartenders.employee_id = ' +
583
+ 'shifts.bartender_id')
584
+ .joins('INNER JOIN waitresses shift_workers ON shift_workers.id = ' +
585
+ 'shifts.waitress_id')
586
+ .where(bartenders: {certified: 'yes'})
587
+ .where(shift_workers: {attitude: 'great'})
588
+ }
589
+
590
+ # set includes for all actions except index
591
+ query_includes :owner, :customer, :bartender, :waitress
592
+
593
+ # includes specified in index query
594
+ query_includes_for :index, are: []
595
+ ```
596
+
597
+ #### Debugging Includes
598
+
599
+ ##### Logging
600
+
601
+ If you enabled Irie's debug option via:
602
+
603
+ ```ruby
604
+ ::Irie.debug = true
605
+ ```
606
+
607
+ Then all the included modules (actions, extensions) will use `logger.debug ...` to log some information about what is executed.
608
+
609
+ To log debug to console only in your tests, you could put this in your test helper:
610
+
611
+ ```ruby
612
+ ::Irie.debug = true
613
+ ::ActionController::Base.logger = Logger.new(STDOUT)
614
+ ::ActionController::Base.logger.level = Logger::DEBUG
615
+ ```
616
+
617
+ However, that might not catch all the initialization debug logging that could occur. Instead, you might put the following into the block in `config/environments/test.rb`:
618
+
619
+ ```ruby
620
+ ::Irie.debug = true
621
+ config.log_level = :debug
622
+ ```
623
+
624
+ ### restful_json
625
+
626
+ The project was originally named [restful_json][restful_json]. Old commit tags corresponding to restful_json versions may be found in [legacy][legacy].
627
+
628
+ ### Release Notes
629
+
630
+ See [changelog][changelog] and git log.
631
+
632
+ ### Contributing
633
+
634
+ Please fork, make changes in a separate branch, and do a pull request. Thanks!
635
+
636
+ ### Authors
637
+
638
+ This was written by [FineLine Prototyping, Inc.](http://www.finelineprototyping.com) by the following contributors:
639
+ * [Gary Weaver](https://github.com/garysweaver)
640
+ * [Tommy Odom](https://github.com/tpodom)
641
+
642
+ ### License
643
+
644
+ Copyright (c) 2013 FineLine Prototyping, Inc., released under the [MIT license][lic].
645
+
646
+ [travis]: http://travis-ci.org/FineLinePrototyping/irie
647
+ [badgefury]: http://badge.fury.io/rb/irie
648
+ [arel]: https://github.com/rails/arel
649
+ [ar]: http://api.rubyonrails.org/classes/ActiveRecord/Relation.html
650
+ [has_scope]: https://github.com/plataformatec/has_scope
651
+ [public_exceptions]: https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
652
+ [show_exceptions]: https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
653
+ [changelog]: https://github.com/FineLinePrototyping/irie/blob/master/CHANGELOG.md
654
+ [inherited_resources]: https://github.com/josevalim/inherited_resources
655
+ [restful_json]: http://rubygems.org/gems/restful_json
656
+ [legacy]: http://github.com/FineLinePrototyping/irie/blob/master/LEGACY.md
657
+ [lic]: http://github.com/FineLinePrototyping/irie/blob/master/LICENSE