inherited_resources 0.9.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -1,7 +1,14 @@
1
- # Version 0.9.4
1
+ # Version 1.0
2
2
 
3
- * DEPRECATION: Use :success and :failure as flash messages instead :notice and :error
3
+ * responders was removed from InheritedResources core and is a dependency. To install it, please do:
4
4
 
5
+ sudo gem install responders
6
+
7
+ * has_scope was removed from InheritedResources core and is now available as a standalone gem.
8
+ To install it, please do:
9
+
10
+ sudo gem install has_scope
11
+
5
12
  # Version 0.9
6
13
 
7
14
  * Allow dual blocks in destroy;
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 José Valim
1
+ Copyright (c) 2009 José Valim http://blog.plataformatec.com.br
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -1,8 +1,4 @@
1
- Inherited Resources
2
- License: MIT
3
- Version: 0.9.2
4
-
5
- == Description
1
+ == Inherited Resources
6
2
 
7
3
  Inherited Resources speeds up development by making your controllers inherit
8
4
  all restful actions so you just have to focus on what is important. It makes
@@ -14,27 +10,60 @@ a screencast made by Fabio Akita about its features:
14
10
 
15
11
  http://akitaonrails.com/2009/09/01/screencast-real-thin-restful-controllers-with-inherited-resources
16
12
 
17
- Inherited Resources is tested and compatible with Rails 2.2.x and Rails 2.3.x.
18
-
19
- keywords: resources, controller, singleton, belongs_to, polymorphic, named_scope and I18n
13
+ This Inherited Resources branch is tested and compatible with Rails 2.3.x.
20
14
 
21
15
  == Installation
22
16
 
23
- Install Inherited Resources is very easy. It is stored in GitHub, so just run
24
- the following:
17
+ Inherited Resources is available as gem on Gemcutter, so just run the following:
25
18
 
26
- gem sources -a http://gemcutter.org
27
- sudo gem install inherited_resources
19
+ sudo gem install inherited_resources --version=1.0.3
28
20
 
29
21
  If you want it as plugin, just do:
30
22
 
31
23
  script/plugin install git://github.com/josevalim/inherited_resources.git
32
24
 
25
+ === HasScope
26
+
27
+ Since Inherited Resources 1.0, has_scope is not part of its core anymore.
28
+ However, if you are using has_scope in your application, Inherited Resources
29
+ will handle all the required hooks automatically.
30
+
31
+ has_scope gem is available at:
32
+
33
+ http://github.com/plataformatec/has_scope
34
+
35
+ And can be installed as:
36
+
37
+ sudo gem install has_scope
38
+
39
+ === Responders
40
+
41
+ Since Inherited Resources 1.0, responders are not part of its core anymore,
42
+ but is set as Inherited Resources dependency and it's used by default by
43
+ InheritedResources controllers. Be sure to check the documentation to see
44
+ how it will change your application:
45
+
46
+ http://github.com/plataformatec/responders
47
+
48
+ And it can be installed as:
49
+
50
+ sudo gem install responders
51
+
52
+ Using responders will set the flash message to :notice and :alert. You can change
53
+ that through the following configuration value:
54
+
55
+ InheritedResources.flash_keys = [ :success, :failure ]
56
+
33
57
  == Rspec known bug
34
58
 
35
- When used with integrate_views equals to false, rspec overwrites default_render,
36
- render and some other controller methods which makes Inherited Resources not work
37
- properly. In such cases, you have to set integrate_views to true.
59
+ Rspec monkey patches a couple of controller methods in a way that Controller specs
60
+ (with integrate views true or false) and Inherited Resources are not compatible.
61
+
62
+ However, since your controllers inherit from InheritedResources::Base, they are
63
+ already unit-tested in the plugin, so there is no need to test them again in Rspec.
64
+
65
+ You should test things like url redirection and associations in your integration
66
+ specs.
38
67
 
39
68
  == Basic Usage
40
69
 
@@ -45,7 +74,7 @@ To use Inherited Resources you just have to inherit (duh) it:
45
74
 
46
75
  And all actions are defined and working, check it! Your projects collection
47
76
  (in the index action) is still available in the instance variable @projects
48
- and your project resource (all other actions) is available as @ project.
77
+ and your project resource (all other actions) is available as @project.
49
78
 
50
79
  The next step is to define which mime types this controller provides:
51
80
 
@@ -228,6 +257,21 @@ give a block that expects two arguments, the first will be executed only in
228
257
  success scenarios and the second in failure scenarios. You keep everything
229
258
  clean and organized inside the same action.
230
259
 
260
+ == Success and failure scenarios on destroy
261
+
262
+ The destroy action can also fail, this usually happens when you have a
263
+ before_destroy callback in your model which returns false. However, in
264
+ order to tell InheritedResources that it really failed, you need to add
265
+ errors to your model. So your before_destroy callback on the model should
266
+ be something like this:
267
+
268
+ def before_destroy
269
+ if cant_be_destroyed?
270
+ errors.add(:base, "not allowed")
271
+ false
272
+ end
273
+ end
274
+
231
275
  == Some DSL
232
276
 
233
277
  For those DSL lovers, InheritedResources won't leave you alone. You can overwrite
@@ -246,109 +290,6 @@ And then you can rewrite the last example as:
246
290
  end
247
291
  end
248
292
 
249
- == Flash messages and I18n
250
-
251
- Flash messages are powered by I18n api. It checks for messages in the following
252
- order:
253
-
254
- flash.controller_name.action_name.status
255
- flash.actions.action_name.status
256
-
257
- If none is available, a default message in english set. In a create action
258
- on projects controller, it will search for:
259
-
260
- flash.projects.create.status
261
- flash.actions.create.status
262
-
263
- The status can be :notice (when the object can be created, updated
264
- or destroyed with success) or :error (when the objecy cannot be created
265
- or updated).
266
-
267
- Those messages are interpolated by using the resource class human name, which
268
- is also localized and it means you can set:
269
-
270
- flash:
271
- actions:
272
- create:
273
- notice: "Hooray! {{resource_name}} was successfully created!"
274
-
275
- It will replace {{resource_name}} by the human name of the resource class,
276
- which is "Project" in this case.
277
-
278
- But sometimes, flash messages are not that simple. Sometimes you want to say
279
- the title of the project while updating a project. Well, that's easy also:
280
-
281
- flash:
282
- projects:
283
- update:
284
- notice: "Hooray! The project "{{project_title}}" was updated!"
285
-
286
- Since :project_title is not available for interpolation by default, you have
287
- to overwrite interpolation_options.
288
-
289
- def interpolation_options
290
- { :project_title => @project.title }
291
- end
292
-
293
- Then you will finally have:
294
-
295
- "Hooray! The project "Plataforma" was updated!"
296
-
297
- By default, resource name is capitalized. If you want to make it lower case, you
298
- can add to your application controller:
299
-
300
- def interpolation_options
301
- { :resource_name => resource_class.human_name.downcase }
302
- end
303
-
304
- Finally, if your controller is namespaced, for example Admin::ProjectsController,
305
- the messages will be checked in the following order:
306
-
307
- flash.admin.projects.create.notice
308
- flash.admin.actions.create.notice
309
- flash.projects.create.notice
310
- flash.actions.create.notice
311
-
312
- == Has Scope
313
-
314
- InheritedResources tries to integrate nicely with your model. In order to do so,
315
- it also is named_scope fluent. Let's suppose our Project model with the scopes:
316
-
317
- class Project < ActiveRecord::Base
318
- named_scope :featured, :conditions => { :featured => true }
319
- named_scope :by_methodology, proc {|methodology| { :conditions => { :methodology => methodology } } }
320
- named_scope :limit, proc{|limit| :limit => limit.to_i }
321
- end
322
-
323
- Your controller:
324
-
325
- class ProjectsController < InheritedResources::Base
326
- has_scope :featured, :boolean => true, :only => :index
327
- has_scope :by_methodology
328
- has_scope :limit, :default => 10
329
- end
330
-
331
- Then for each request:
332
-
333
- /projects
334
- #=> acts like a normal request, but returning 10 projects
335
-
336
- /projects?featured=true
337
- #=> calls the featured named scope and bring 10 featured projects
338
-
339
- /projects?featured=true&by_methodology=agile&limit=20
340
- #=> brings 20 featured projects with methodology agile
341
-
342
- You can retrieve the current scopes in use with :current_scopes method.
343
- In the last case, it would return:
344
-
345
- { :featured => "true", :by_methodology => "agile", :limit => "20" }
346
-
347
- Finally, let's suppose you store on the session how many projects the user sees
348
- per page. In such cases, you can give a proc as default value:
349
-
350
- has_scope :limit, :default => proc{|c| c.session[:limit] || 10 }
351
-
352
293
  == Belongs to
353
294
 
354
295
  Finally, our Projects are going to get some Tasks. Then you create a
@@ -522,3 +463,4 @@ If you discover any bugs or want to drop a line, join us in the mailing list:
522
463
  http://groups.google.com/group/inherited_resources
523
464
 
524
465
  Copyright (c) 2009 José Valim http://blog.plataformatec.com.br
466
+ See the attached MIT License.
data/Rakefile CHANGED
@@ -16,7 +16,9 @@ begin
16
16
  s.homepage = "http://github.com/josevalim/inherited_resources"
17
17
  s.description = "Inherited Resources speeds up development by making your controllers inherit all restful actions so you just have to focus on what is important."
18
18
  s.authors = ['José Valim']
19
- s.files = FileList["[A-Z]*", "{lib}/**/*"]
19
+ s.files = FileList["[A-Z]*", "rails/init.rb", "{lib}/**/*"]
20
+ s.add_dependency("responders", "~> 0.4.6")
21
+ s.add_dependency("has_scope", "~> 0.5.0")
20
22
  end
21
23
 
22
24
  Jeweler::GemcutterTasks.new
@@ -3,26 +3,26 @@ module InheritedResources
3
3
  module Actions
4
4
 
5
5
  # GET /resources
6
- def index(&block)
7
- respond_with(collection, &block)
6
+ def index(options={}, &block)
7
+ respond_with(*(with_chain(collection) << options), &block)
8
8
  end
9
9
  alias :index! :index
10
10
 
11
11
  # GET /resources/1
12
- def show(&block)
13
- respond_with(resource, &block)
12
+ def show(options={}, &block)
13
+ respond_with(*(with_chain(resource) << options), &block)
14
14
  end
15
15
  alias :show! :show
16
16
 
17
17
  # GET /resources/new
18
- def new(&block)
19
- respond_with(build_resource, &block)
18
+ def new(options={}, &block)
19
+ respond_with(*(with_chain(build_resource) << options), &block)
20
20
  end
21
21
  alias :new! :new
22
22
 
23
23
  # GET /resources/1/edit
24
- def edit(&block)
25
- respond_with(resource, &block)
24
+ def edit(options={}, &block)
25
+ respond_with(*(with_chain(resource) << options), &block)
26
26
  end
27
27
  alias :edit! :edit
28
28
 
@@ -31,13 +31,10 @@ module InheritedResources
31
31
  object = build_resource
32
32
 
33
33
  if create_resource(object)
34
- set_flash_message!(:notice, '{{resource_name}} was successfully created.')
35
34
  options[:location] ||= resource_url rescue nil
36
- respond_with_dual_blocks(object, options, true, block)
37
- else
38
- set_flash_message!(:error)
39
- respond_with_dual_blocks(object, options, false, block)
40
35
  end
36
+
37
+ respond_with_dual_blocks(object, options, &block)
41
38
  end
42
39
  alias :create! :create
43
40
 
@@ -46,13 +43,10 @@ module InheritedResources
46
43
  object = resource
47
44
 
48
45
  if update_resource(object, params[resource_instance_name])
49
- set_flash_message!(:notice, '{{resource_name}} was successfully updated.')
50
46
  options[:location] ||= resource_url rescue nil
51
- respond_with_dual_blocks(object, options, true, block)
52
- else
53
- set_flash_message!(:error)
54
- respond_with_dual_blocks(object, options, false, block)
55
47
  end
48
+
49
+ respond_with_dual_blocks(object, options, &block)
56
50
  end
57
51
  alias :update! :update
58
52
 
@@ -61,19 +55,13 @@ module InheritedResources
61
55
  object = resource
62
56
  options[:location] ||= collection_url rescue nil
63
57
 
64
- if destroy_resource(object)
65
- set_flash_message!(:notice, '{{resource_name}} was successfully destroyed.')
66
- respond_with_dual_blocks(object, options, true, block)
67
- else
68
- set_flash_message!(:error, '{{resource_name}} could not be destroyed.')
69
- respond_with_dual_blocks(object, options, false, block)
70
- end
58
+ destroy_resource(object)
59
+ respond_with_dual_blocks(object, options, &block)
71
60
  end
72
61
  alias :destroy! :destroy
73
62
 
74
63
  # Make aliases protected
75
64
  protected :index!, :show!, :new!, :create!, :edit!, :update!, :destroy!
76
-
77
65
  end
78
66
  end
79
67
 
@@ -1,3 +1,6 @@
1
+ require 'inherited_resources/blank_slate'
2
+ require 'inherited_resources/responder'
3
+
1
4
  module InheritedResources
2
5
  # = Base
3
6
  #
@@ -22,6 +25,7 @@ module InheritedResources
22
25
 
23
26
  # Add at least :html mime type
24
27
  respond_to :html
28
+ self.responder = InheritedResources::Responder
25
29
 
26
30
  helper_method :collection_url, :collection_path, :resource_url, :resource_path,
27
31
  :new_resource_url, :new_resource_path, :edit_resource_url, :edit_resource_path,
@@ -31,10 +35,10 @@ module InheritedResources
31
35
  base.with_options :instance_writer => false do |c|
32
36
  c.class_inheritable_accessor :resource_class
33
37
  c.class_inheritable_array :parents_symbols
34
- c.class_inheritable_hash :resources_configuration, :scopes_configuration
38
+ c.class_inheritable_hash :resources_configuration
35
39
  end
36
40
 
37
- protected :resource_class, :parents_symbols, :resources_configuration, :scopes_configuration
41
+ protected :resource_class, :parents_symbols, :resources_configuration
38
42
  end
39
43
  end
40
44
 
@@ -1,5 +1,5 @@
1
1
  # Whenever base is required load the dumb responder since it's used inside actions.
2
- require File.dirname(__FILE__) + '/dumb_responder.rb'
2
+ require 'inherited_resources/blank_slate'
3
3
 
4
4
  module InheritedResources
5
5
  # Base helpers for InheritedResource work. Some methods here can be overwriten
@@ -138,6 +138,11 @@ module InheritedResources
138
138
 
139
139
  private
140
140
 
141
+ # Adds the given object to association chain.
142
+ def with_chain(object)
143
+ association_chain + [ object ]
144
+ end
145
+
141
146
  # Fast accessor to resource_collection_name
142
147
  #
143
148
  def resource_collection_name #:nodoc:
@@ -156,7 +161,7 @@ module InheritedResources
156
161
  def end_of_association_chain #:nodoc:
157
162
  if chain = association_chain.last
158
163
  if method_for_association_chain
159
- apply_scope_to(chain.send(method_for_association_chain))
164
+ apply_scopes_if_available(chain.send(method_for_association_chain))
160
165
  else
161
166
  # This only happens when we specify begin_of_association_chain in
162
167
  # a singletion controller without parents. In this case, the chain
@@ -165,7 +170,7 @@ module InheritedResources
165
170
  chain
166
171
  end
167
172
  else
168
- apply_scope_to(resource_class)
173
+ apply_scopes_if_available(resource_class)
169
174
  end
170
175
  end
171
176
 
@@ -214,98 +219,6 @@ module InheritedResources
214
219
  instance_variable_set("@#{resource_collection_name}", collection)
215
220
  end
216
221
 
217
- # Helper to set flash messages. It's powered by I18n API.
218
- # It checks for messages in the following order:
219
- #
220
- # flash.controller_name.action_name.status
221
- # flash.actions.action_name.status
222
- #
223
- # If none is available, a default message is set. So, if you have
224
- # a CarsController, create action, it will check for:
225
- #
226
- # flash.cars.create.status
227
- # flash.actions.create.status
228
- #
229
- # The statuses can be :notice (when the object can be created, updated
230
- # or destroyed with success) or :error (when the objecy cannot be created
231
- # or updated).
232
- #
233
- # Those messages are interpolated by using the resource class human name.
234
- # This means you can set:
235
- #
236
- # flash:
237
- # actions:
238
- # create:
239
- # notice: "Hooray! {{resource_name}} was successfully created!"
240
- #
241
- # But sometimes, flash messages are not that simple. Going back
242
- # to cars example, you might want to say the brand of the car when it's
243
- # updated. Well, that's easy also:
244
- #
245
- # flash:
246
- # cars:
247
- # update:
248
- # notice: "Hooray! You just tuned your {{car_brand}}!"
249
- #
250
- # Since :car_name is not available for interpolation by default, you have
251
- # to overwrite interpolation_options.
252
- #
253
- # def interpolation_options
254
- # { :car_brand => @car.brand }
255
- # end
256
- #
257
- # Then you will finally have:
258
- #
259
- # 'Hooray! You just tuned your Aston Martin!'
260
- #
261
- # If your controller is namespaced, for example Admin::CarsController,
262
- # the messages will be checked in the following order:
263
- #
264
- # flash.admin.cars.create.status
265
- # flash.admin.actions.create.status
266
- # flash.cars.create.status
267
- # flash.actions.create.status
268
- #
269
- def set_flash_message!(status, default_message=nil)
270
- return flash[status] = default_message unless defined?(::I18n)
271
-
272
- resource_name = if resource_class
273
- if resource_class.respond_to?(:human_name)
274
- resource_class.human_name
275
- else
276
- resource_class.name.underscore.humanize
277
- end
278
- else
279
- "Resource"
280
- end
281
-
282
- given_options = if self.respond_to?(:interpolation_options)
283
- interpolation_options
284
- else
285
- {}
286
- end
287
-
288
- options = {
289
- :default => default_message || '',
290
- :resource_name => resource_name
291
- }.merge(given_options)
292
-
293
- defaults = []
294
- slices = controller_path.split('/')
295
-
296
- while slices.size > 0
297
- defaults << :"flash.#{slices.fill(controller_name, -1).join('.')}.#{action_name}.#{status}"
298
- defaults << :"flash.#{slices.fill(:actions, -1).join('.')}.#{action_name}.#{status}"
299
- slices.shift
300
- end
301
-
302
- options[:default] = defaults.push(options[:default])
303
- options[:default].flatten!
304
-
305
- message = ::I18n.t options[:default].shift, options
306
- flash[status] = message unless message.blank?
307
- end
308
-
309
222
  # Used to allow to specify success and failure within just one block:
310
223
  #
311
224
  # def create
@@ -317,38 +230,32 @@ module InheritedResources
317
230
  # It also calculates the response url in case a block without arity is
318
231
  # given and returns it. Otherwise returns nil.
319
232
  #
320
- def respond_with_dual_blocks(object, options, success, given_block, &block) #:nodoc:
321
- case given_block.try(:arity)
233
+ def respond_with_dual_blocks(object, options, &block) #:nodoc:
234
+ args = (with_chain(object) << options)
235
+
236
+ case block.try(:arity)
322
237
  when 2
323
- respond_with(object, options) do |responder|
324
- dumb_responder = InheritedResources::DumbResponder.new
325
- if success
326
- given_block.call(responder, dumb_responder)
238
+ respond_with(*args) do |responder|
239
+ blank_slate = InheritedResources::BlankSlate.new
240
+ if object.errors.empty?
241
+ block.call(responder, blank_slate)
327
242
  else
328
- given_block.call(dumb_responder, responder)
243
+ block.call(blank_slate, responder)
329
244
  end
330
- block.try(:call, responder)
331
245
  end
332
246
  when 1
333
- if block
334
- respond_with(object, options) do |responder|
335
- given_block.call(responder)
336
- block.call(responder)
337
- end
338
- else
339
- respond_with(object, options, &given_block)
340
- end
247
+ respond_with(*args, &block)
341
248
  else
342
- options[:location] = given_block.call if given_block
343
- respond_with(object, options, &block)
249
+ options[:location] = block.call if block
250
+ respond_with(*args)
344
251
  end
345
252
  end
346
253
 
347
254
  # Hook to apply scopes. By default returns only the target_object given.
348
255
  # It's extend by HasScopeHelpers.
349
256
  #
350
- def apply_scope_to(target_object) #:nodoc:
351
- target_object
257
+ def apply_scopes_if_available(target_object) #:nodoc:
258
+ respond_to?(:apply_scopes) ? apply_scopes(target_object) : target_object
352
259
  end
353
260
 
354
261
  # Symbols chain in base helpers return nothing. This is later overwriten
@@ -56,6 +56,14 @@ module InheritedResources
56
56
  def parent?
57
57
  true
58
58
  end
59
+
60
+ def parent
61
+ @parent ||= association_chain[-1]
62
+ end
63
+
64
+ def parent_type
65
+ parent.class.name.underscore.to_sym
66
+ end
59
67
 
60
68
  private
61
69
 
@@ -0,0 +1,12 @@
1
+ module InheritedResources
2
+ # An object from BlankSlate simply discards all messages sent to it.
3
+ class BlankSlate
4
+ instance_methods.each do |m|
5
+ undef_method m unless m =~ /^(__|object_id)/
6
+ end
7
+
8
+ def method_missing(*args)
9
+ nil
10
+ end
11
+ end
12
+ end