inherited_resources 1.4.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,6 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.homepage = "http://github.com/josevalim/inherited_resources"
12
12
  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."
13
13
  s.authors = ['José Valim']
14
+ s.license = "MIT"
14
15
 
15
16
  s.rubyforge_project = "inherited_resources"
16
17
 
@@ -18,6 +19,6 @@ Gem::Specification.new do |s|
18
19
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
20
  s.require_paths = ["lib"]
20
21
 
21
- s.add_dependency("responders", "~> 0.9")
22
- s.add_dependency("has_scope", "~> 0.5.0")
22
+ s.add_dependency("responders", "~> 1.0.0.rc")
23
+ s.add_dependency("has_scope", "~> 0.6.0.rc")
23
24
  end
@@ -34,7 +34,7 @@ end
34
34
 
35
35
  class ActionController::Base
36
36
  # If you cannot inherit from InheritedResources::Base you can call
37
- # inherit_resource in your controller to have all the required modules and
37
+ # inherit_resources in your controller to have all the required modules and
38
38
  # funcionality included.
39
39
  def self.inherit_resources
40
40
  InheritedResources::Base.inherit_resources(self)
@@ -4,25 +4,25 @@ module InheritedResources
4
4
 
5
5
  # GET /resources
6
6
  def index(options={}, &block)
7
- respond_with(*(with_chain(collection) << 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
12
  def show(options={}, &block)
13
- respond_with(*(with_chain(resource) << 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
18
  def new(options={}, &block)
19
- respond_with(*(with_chain(build_resource) << 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
24
  def edit(options={}, &block)
25
- respond_with(*(with_chain(resource) << options), &block)
25
+ respond_with(*with_chain(resource), options, &block)
26
26
  end
27
27
  alias :edit! :edit
28
28
 
@@ -22,7 +22,14 @@ module InheritedResources
22
22
  def collection
23
23
  get_collection_ivar || begin
24
24
  c = end_of_association_chain
25
- set_collection_ivar(c.respond_to?(:scoped) ? c.scoped : c.all)
25
+ if defined?(ActiveRecord::DeprecatedFinders)
26
+ # ActiveRecord::Base#scoped and ActiveRecord::Relation#all
27
+ # are deprecated in Rails 4. If it's a relation just use
28
+ # it, otherwise use .all to get a relation.
29
+ set_collection_ivar(c.is_a?(ActiveRecord::Relation) ? c : c.all)
30
+ else
31
+ set_collection_ivar(c.respond_to?(:scoped) ? c.scoped : c.all)
32
+ end
26
33
  end
27
34
  end
28
35
 
@@ -126,18 +133,17 @@ module InheritedResources
126
133
  # current resource).
127
134
  #
128
135
  def association_chain
129
- return @association_chain if @association_chain
130
-
131
- symbol_chain = if resources_configuration[:self][:singleton]
132
- symbols_for_association_chain.reverse
133
- else
134
- symbols_for_association_chain
135
- end
136
+ @association_chain ||= begin
137
+ symbol_chain = if resources_configuration[:self][:singleton]
138
+ symbols_for_association_chain.reverse
139
+ else
140
+ symbols_for_association_chain
141
+ end
136
142
 
137
- @association_chain =
138
143
  symbol_chain.inject([begin_of_association_chain]) do |chain, symbol|
139
144
  chain << evaluate_parent(symbol, resources_configuration[symbol], chain.last)
140
145
  end.compact.freeze
146
+ end
141
147
  end
142
148
 
143
149
  # Overwrite this method to provide other interpolation options when
@@ -312,7 +318,7 @@ module InheritedResources
312
318
 
313
319
  # extract attributes from params
314
320
  def build_resource_params
315
- parameters = respond_to?(:permitted_params) ? permitted_params : params
321
+ parameters = respond_to?(:permitted_params, true) ? permitted_params : params
316
322
  rparams = [parameters[resource_request_name] || parameters[resource_instance_name] || {}]
317
323
  if without_protection_given?
318
324
  rparams << without_protection
@@ -32,7 +32,7 @@ module InheritedResources
32
32
  #
33
33
  # * <tt>:finder</tt> - Specifies which method should be called to instantiate the resource.
34
34
  #
35
- # defaults :project, :finder => :find_by_slug
35
+ # defaults :finder => :find_by_slug
36
36
  #
37
37
  def defaults(options)
38
38
  raise ArgumentError, 'Class method :defaults expects a hash of options.' unless options.is_a? Hash
@@ -154,7 +154,7 @@ module InheritedResources
154
154
  acts_as_shallow! if shallow
155
155
 
156
156
  raise ArgumentError, 'You have to give me at least one association name.' if symbols.empty?
157
- raise ArgumentError, 'You cannot define multiple associations with options: #{options.keys.inspect} to belongs to.' unless symbols.size == 1 || options.empty?
157
+ raise ArgumentError, "You cannot define multiple associations with options: #{options.keys.inspect} to belongs to." unless symbols.size == 1 || options.empty?
158
158
 
159
159
  symbols.each do |symbol|
160
160
  symbol = symbol.to_sym
@@ -201,7 +201,7 @@ module InheritedResources
201
201
  def polymorphic_belongs_to(*symbols, &block)
202
202
  options = symbols.extract_options!
203
203
  options.merge!(:polymorphic => true)
204
- belongs_to(*symbols << options, &block)
204
+ belongs_to(*symbols, options, &block)
205
205
  end
206
206
 
207
207
  # A quick method to declare singleton belongs to.
@@ -209,7 +209,7 @@ module InheritedResources
209
209
  def singleton_belongs_to(*symbols, &block)
210
210
  options = symbols.extract_options!
211
211
  options.merge!(:singleton => true)
212
- belongs_to(*symbols << options, &block)
212
+ belongs_to(*symbols, options, &block)
213
213
  end
214
214
 
215
215
  # A quick method to declare optional belongs to.
@@ -217,7 +217,7 @@ module InheritedResources
217
217
  def optional_belongs_to(*symbols, &block)
218
218
  options = symbols.extract_options!
219
219
  options.merge!(:optional => true)
220
- belongs_to(*symbols << options, &block)
220
+ belongs_to(*symbols, options, &block)
221
221
  end
222
222
 
223
223
  # Defines custom restful actions by resource or collection basis.
@@ -358,7 +358,7 @@ module InheritedResources
358
358
  def create_custom_action(resource_or_collection, action)
359
359
  class_eval <<-CUSTOM_ACTION, __FILE__, __LINE__
360
360
  def #{action}(options={}, &block)
361
- respond_with(*(with_chain(#{resource_or_collection}) << options), &block)
361
+ respond_with(*with_chain(#{resource_or_collection}), options, &block)
362
362
  end
363
363
  alias :#{action}! :#{action}
364
364
  protected :#{action}!
@@ -1,3 +1,3 @@
1
1
  module InheritedResources
2
- VERSION = '1.4.0'.freeze
2
+ VERSION = '1.4.1'.freeze
3
3
  end
@@ -12,6 +12,9 @@ class StrongParametersTest < ActionController::TestCase
12
12
  @controller = WidgetsController.new
13
13
  @controller.stubs(:widget_url).returns("/")
14
14
  @controller.stubs(:permitted_params).returns(:widget => {:permitted => 'param'})
15
+ class << @controller
16
+ private :permitted_params
17
+ end
15
18
  end
16
19
 
17
20
  def test_permitted_params_from_new
@@ -27,8 +27,8 @@ ActionController::Base.view_paths = File.join(File.dirname(__FILE__), 'views')
27
27
 
28
28
  InheritedResources::Routes = ActionDispatch::Routing::RouteSet.new
29
29
  InheritedResources::Routes.draw do
30
- match ':controller(/:action(/:id))'
31
- match ':controller(/:action)'
30
+ get ':controller(/:action(/:id))'
31
+ get ':controller(/:action)'
32
32
  resources 'posts'
33
33
  root :to => 'posts#index'
34
34
  end
metadata CHANGED
@@ -1,48 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inherited_resources
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
5
- prerelease:
4
+ version: 1.4.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - José Valim
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-03-25 00:00:00.000000000 Z
11
+ date: 2013-07-31 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: responders
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
21
- version: '0.9'
19
+ version: 1.0.0.rc
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
29
- version: '0.9'
26
+ version: 1.0.0.rc
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: has_scope
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ~>
36
32
  - !ruby/object:Gem::Version
37
- version: 0.5.0
33
+ version: 0.6.0.rc
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ~>
44
39
  - !ruby/object:Gem::Version
45
- version: 0.5.0
40
+ version: 0.6.0.rc
46
41
  description: Inherited Resources speeds up development by making your controllers
47
42
  inherit all restful actions so you just have to focus on what is important.
48
43
  email: developers@plataformatec.com.br
@@ -55,7 +50,7 @@ files:
55
50
  - Gemfile
56
51
  - Gemfile.lock
57
52
  - MIT-LICENSE
58
- - README.rdoc
53
+ - README.md
59
54
  - Rakefile
60
55
  - app/controllers/inherited_resources/base.rb
61
56
  - inherited_resources.gemspec
@@ -175,28 +170,28 @@ files:
175
170
  - test/views/venue/show.html.erb
176
171
  - test/views/widgets/new.html.erb
177
172
  homepage: http://github.com/josevalim/inherited_resources
178
- licenses: []
173
+ licenses:
174
+ - MIT
175
+ metadata: {}
179
176
  post_install_message:
180
177
  rdoc_options: []
181
178
  require_paths:
182
179
  - lib
183
180
  required_ruby_version: !ruby/object:Gem::Requirement
184
- none: false
185
181
  requirements:
186
- - - ! '>='
182
+ - - '>='
187
183
  - !ruby/object:Gem::Version
188
184
  version: '0'
189
185
  required_rubygems_version: !ruby/object:Gem::Requirement
190
- none: false
191
186
  requirements:
192
- - - ! '>='
187
+ - - '>='
193
188
  - !ruby/object:Gem::Version
194
189
  version: '0'
195
190
  requirements: []
196
191
  rubyforge_project: inherited_resources
197
- rubygems_version: 1.8.23
192
+ rubygems_version: 2.0.6
198
193
  signing_key:
199
- specification_version: 3
194
+ specification_version: 4
200
195
  summary: Inherited Resources speeds up development by making your controllers inherit
201
196
  all restful actions so you just have to focus on what is important.
202
197
  test_files:
@@ -299,3 +294,4 @@ test_files:
299
294
  - test/views/users/update.js.erb
300
295
  - test/views/venue/show.html.erb
301
296
  - test/views/widgets/new.html.erb
297
+ has_rdoc:
@@ -1,559 +0,0 @@
1
- == Inherited Resources
2
-
3
- Inherited Resources speeds up development by making your controllers inherit
4
- all restful actions so you just have to focus on what is important. It makes
5
- your controllers more powerful and cleaner at the same time.
6
-
7
- In addition to making your controllers follow a pattern, it helps you to write better
8
- code by following fat models and skinny controllers convention. There are
9
- two screencasts available besides this README:
10
-
11
- * http://railscasts.com/episodes/230-inherited-resources
12
- * http://akitaonrails.com/2009/09/01/screencast-real-thin-restful-controllers-with-inherited-resources
13
-
14
- == Installation
15
-
16
- === Rails 3
17
-
18
- You can let bundler install Inherited Resources by adding this line to your application's Gemfile:
19
-
20
- gem 'inherited_resources'
21
-
22
- And then execute:
23
-
24
- bundle install
25
-
26
- Or install it yourself with:
27
-
28
- gem install inherited_resources
29
-
30
- === Rails 2.3.x
31
-
32
- If you want to use the Rails 2.3.x version, you should install:
33
-
34
- gem install inherited_resources --version=1.0.6
35
-
36
- Or checkout from the v1.0 branch:
37
-
38
- http://github.com/josevalim/inherited_resources/tree/v1.0
39
-
40
- == HasScope
41
-
42
- Since Inherited Resources 1.0, has_scope is not part of its core anymore but
43
- a gem dependency. Be sure to check the documentation to see how you can use it:
44
-
45
- http://github.com/plataformatec/has_scope
46
-
47
- And it can be installed as:
48
-
49
- gem install has_scope
50
-
51
- == Responders
52
-
53
- Since Inherited Resources 1.0, responders are not part of its core anymore,
54
- but is set as Inherited Resources dependency and it's used by default by
55
- InheritedResources controllers. Be sure to check the documentation to see
56
- how it will change your application:
57
-
58
- http://github.com/plataformatec/responders
59
-
60
- And it can be installed with:
61
-
62
- gem install responders
63
-
64
- Using responders will set the flash message to :notice and :alert. You can change
65
- that through the following configuration value:
66
-
67
- InheritedResources.flash_keys = [ :success, :failure ]
68
-
69
- Notice the CollectionResponder won't work with InheritedResources, as InheritedResources hardcodes the redirect path based on the current scope (like belongs to, polymorphic associations, etc).
70
-
71
- == Basic Usage
72
-
73
- To use Inherited Resources you just have to inherit (duh) it:
74
-
75
- class ProjectsController < InheritedResources::Base
76
- end
77
-
78
- And all actions are defined and working, check it! Your projects collection
79
- (in the index action) is still available in the instance variable @projects
80
- and your project resource (all other actions) is available as @project.
81
-
82
- The next step is to define which mime types this controller provides:
83
-
84
- class ProjectsController < InheritedResources::Base
85
- respond_to :html, :xml, :json
86
- end
87
-
88
- You can also specify them per action:
89
-
90
- class ProjectsController < InheritedResources::Base
91
- respond_to :html, :xml, :json
92
- respond_to :js, :only => :create
93
- respond_to :iphone, :except => [ :edit, :update ]
94
- end
95
-
96
- For each request, it first checks if the "controller/action.format" file is
97
- available (for example "projects/create.xml") and if it's not, it checks if
98
- the resource respond to :to_format (in this case, :to_xml). Otherwise returns 404.
99
-
100
- Another option is to specify which actions the controller will inherit from
101
- the InheritedResources::Base:
102
-
103
- class ProjectsController < InheritedResources::Base
104
- actions :index, :show, :new, :create
105
- end
106
-
107
- Or:
108
-
109
- class ProjectsController < InheritedResources::Base
110
- actions :all, :except => [ :edit, :update, :destroy ]
111
- end
112
-
113
- In your views, you will get the following helpers:
114
-
115
- resource #=> @project
116
- collection #=> @projects
117
- resource_class #=> Project
118
-
119
- As you might expect, collection (@projects instance variable) is only available
120
- on index actions.
121
-
122
- If for some reason you cannot inherit from InheritedResources::Base, you can
123
- call inherit_resources in your controller class scope:
124
-
125
- class AccountsController < ApplicationController
126
- inherit_resources
127
- end
128
-
129
- One reason to use the "inherit_resources" macro would be to ensure that your controller never responds with the html mime-type. InheritedResources::Base already responds_to :html, and the respond_to macro is strictly additive. Therefore, if you want to create a controller that, for example, responds ONLY via :js, you will have write it this way:
130
-
131
- class AccountsController < ApplicationController
132
- respond_to :js
133
- inherit_resources
134
- end
135
-
136
-
137
- == Overwriting defaults
138
-
139
- Whenever you inherit from InheritedResources, several defaults are assumed.
140
- For example you can have an AccountsController for account management while the
141
- resource is a User:
142
-
143
- class AccountsController < InheritedResources::Base
144
- defaults :resource_class => User, :collection_name => 'users', :instance_name => 'user'
145
- end
146
-
147
- In the case above, in your views you will have @users and @user variables, but
148
- the routes used will still be accounts_url and account_url. If you plan also to
149
- change the routes, you can use :route_collection_name and :route_instance_name.
150
-
151
- Namespaced controllers work out of the box, but if you need to specify a
152
- different route prefix you can do the following:
153
-
154
- class Administrators::PeopleController < InheritedResources::Base
155
- defaults :route_prefix => 'admin'
156
- end
157
-
158
- Then your named routes will be: 'admin_people_url', 'admin_person_url' instead
159
- of 'administrators_people_url' and 'administrators_person_url'.
160
-
161
- If you want to customize how resources are retrieved you can overwrite
162
- collection and resource methods. The first is called on index action and the
163
- second on all other actions. Let's suppose you want to add pagination to your
164
- projects collection:
165
-
166
- class ProjectsController < InheritedResources::Base
167
- protected
168
- def collection
169
- @projects ||= end_of_association_chain.paginate(:page => params[:page])
170
- end
171
- end
172
-
173
- The end_of_association_chain returns your resource after nesting all associations
174
- and scopes (more about this below).
175
-
176
- InheritedResources also introduces another method called begin_of_association_chain.
177
- It's mostly used when you want to create resources based on the @current_user and
178
- you have urls like "account/projects". In such cases you have to do
179
- @current_user.projects.find or @current_user.projects.build in your actions.
180
-
181
- You can deal with it just by doing:
182
-
183
- class ProjectsController < InheritedResources::Base
184
- protected
185
- def begin_of_association_chain
186
- @current_user
187
- end
188
- end
189
-
190
- == Overwriting actions
191
-
192
- Let's suppose that after destroying a project you want to redirect to your
193
- root url instead of redirecting to projects url. You just have to do:
194
-
195
- class ProjectsController < InheritedResources::Base
196
- def destroy
197
- super do |format|
198
- format.html { redirect_to root_url }
199
- end
200
- end
201
- end
202
-
203
- You are opening your action and giving the parent action a new behavior. On
204
- the other hand, I have to agree that calling super is not very readable. That's
205
- why all methods have aliases. So this is equivalent:
206
-
207
- class ProjectsController < InheritedResources::Base
208
- def destroy
209
- destroy! do |format|
210
- format.html { redirect_to root_url }
211
- end
212
- end
213
- end
214
-
215
- Since most of the time when you change a create, update or destroy
216
- action you do so because you want to to change its redirect url, a shortcut is
217
- provided. So you can do:
218
-
219
- class ProjectsController < InheritedResources::Base
220
- def destroy
221
- destroy! { root_url }
222
- end
223
- end
224
-
225
- If you simply want to change the flash message for a particular action, you can
226
- pass the message to the parent action using the keys :notice and :alert (as you
227
- would with flash):
228
-
229
- class ProjectsController < InheritedResources::Base
230
- def create
231
- create!(:notice => "Dude! Nice job creating that project.")
232
- end
233
- end
234
-
235
- You can still pass the block to change the redirect, as mentioned above:
236
-
237
- class ProjectsController < InheritedResources::Base
238
- def create
239
- create!(:notice => "Dude! Nice job creating that project.") { root_url }
240
- end
241
- end
242
-
243
- Now let's suppose that before create a project you have to do something special
244
- but you don't want to create a before filter for it:
245
-
246
- class ProjectsController < InheritedResources::Base
247
- def create
248
- @project = Project.new(params[:project])
249
- @project.something_special!
250
- create!
251
- end
252
- end
253
-
254
- Yes, it's that simple! The nice part is since you already set the instance variable
255
- @project, it will not build a project again.
256
-
257
- Before we finish this topic, we should talk about one more thing: "success/failure
258
- blocks". Let's suppose that when we update our project, in case of failure, we
259
- want to redirect to the project url instead of re-rendering the edit template.
260
-
261
- Our first attempt to do this would be:
262
-
263
- class ProjectsController < InheritedResources::Base
264
- def update
265
- update! do |format|
266
- unless @project.errors.empty? # failure
267
- format.html { redirect_to project_url(@project) }
268
- end
269
- end
270
- end
271
- end
272
-
273
- Looks too verbose, right? We can actually do:
274
-
275
- class ProjectsController < InheritedResources::Base
276
- def update
277
- update! do |success, failure|
278
- failure.html { redirect_to project_url(@project) }
279
- end
280
- end
281
- end
282
-
283
- Much better! So explaining everything: when you give a block which expects one
284
- argument it will be executed in both scenarios: success and failure. But if you
285
- give a block that expects two arguments, the first will be executed only in
286
- success scenarios and the second in failure scenarios. You keep everything
287
- clean and organized inside the same action.
288
-
289
- == Smart redirects
290
-
291
- Although the syntax above is a nice shortcut, you won't need to do it frequently
292
- because (since version 1.2) Inherited Resources has smart redirects. Redirects
293
- in actions calculates depending on the existent controller methods.
294
-
295
- Redirects in create and update actions calculates in the following order resource_url,
296
- collection_url, parent_url (which we are going to see later), and root_url. Redirect
297
- in destroy action calculate in following order collection_url, parent_url, root_url.
298
-
299
- Example:
300
-
301
- class ButtonsController < InheritedResources::Base
302
- belongs_to :window
303
- actions :all, :except => [:show, :index]
304
- end
305
-
306
- This controller redirect to parent window after all CUD actions.
307
-
308
- == Success and failure scenarios on destroy
309
-
310
- The destroy action can also fail, this usually happens when you have a
311
- before_destroy callback in your model which returns false. However, in
312
- order to tell InheritedResources that it really failed, you need to add
313
- errors to your model. So your before_destroy callback on the model should
314
- be something like this:
315
-
316
- def before_destroy
317
- if cant_be_destroyed?
318
- errors.add(:base, "not allowed")
319
- false
320
- end
321
- end
322
-
323
- == Belongs to
324
-
325
- Finally, our Projects are going to get some Tasks. Then you create a
326
- TasksController and do:
327
-
328
- class TasksController < InheritedResources::Base
329
- belongs_to :project
330
- end
331
-
332
- belongs_to accepts several options to be able to configure the association.
333
- For example, if you want urls like /projects/:project_title/tasks, you can
334
- customize how InheritedResources find your projects:
335
-
336
- class TasksController < InheritedResources::Base
337
- belongs_to :project, :finder => :find_by_title!, :param => :project_title
338
- end
339
-
340
- It also accepts :route_name, :parent_class and :instance_name as options.
341
- Check the lib/inherited_resources/class_methods.rb for more.
342
-
343
- == Nested belongs to
344
-
345
- Now, our Tasks get some Comments and you need to nest even deeper. Good
346
- practices says that you should never nest more than two resources, but sometimes
347
- you have to for security reasons. So this is an example of how you can do it:
348
-
349
- class CommentsController < InheritedResources::Base
350
- nested_belongs_to :project, :task
351
- end
352
-
353
- If you need to configure any of these belongs to, you can nest them using blocks:
354
-
355
- class CommentsController < InheritedResources::Base
356
- belongs_to :project, :finder => :find_by_title!, :param => :project_title do
357
- belongs_to :task
358
- end
359
- end
360
-
361
- Warning: calling several belongs_to is the same as nesting them:
362
-
363
- class CommentsController < InheritedResources::Base
364
- belongs_to :project
365
- belongs_to :task
366
- end
367
-
368
- In other words, the code above is the same as calling nested_belongs_to.
369
-
370
- == Polymorphic belongs to
371
-
372
- We can go even further. Let's suppose our Projects can now have Files, Messages
373
- and Tasks, and they are all commentable. In this case, the best solution is to
374
- use polymorphism:
375
-
376
- class CommentsController < InheritedResources::Base
377
- belongs_to :task, :file, :message, :polymorphic => true
378
- # polymorphic_belongs_to :task, :file, :message
379
- end
380
-
381
- You can even use it with nested resources:
382
-
383
- class CommentsController < InheritedResources::Base
384
- belongs_to :project do
385
- belongs_to :task, :file, :message, :polymorphic => true
386
- end
387
- end
388
-
389
- The url in such cases can be:
390
-
391
- /project/1/task/13/comments
392
- /project/1/file/11/comments
393
- /project/1/message/9/comments
394
-
395
- When using polymorphic associations, you get some free helpers:
396
-
397
- parent? #=> true
398
- parent_type #=> :task
399
- parent_class #=> Task
400
- parent #=> @task
401
-
402
- Right now, Inherited Resources is limited and does not allow you
403
- to have two polymorphic associations nested.
404
-
405
- == Optional belongs to
406
-
407
- Later you decide to create a view to show all comments, independent if they belong
408
- to a task, file or message. You can reuse your polymorphic controller just doing:
409
-
410
- class CommentsController < InheritedResources::Base
411
- belongs_to :task, :file, :message, :optional => true
412
- # optional_belongs_to :task, :file, :message
413
- end
414
-
415
- This will handle all those urls properly:
416
-
417
- /comment/1
418
- /tasks/2/comment/5
419
- /files/10/comment/3
420
- /messages/13/comment/11
421
-
422
- This is treated as a special type of polymorphic associations, thus all helpers
423
- are available. As you expect, when no parent is found, the helpers return:
424
-
425
- parent? #=> false
426
- parent_type #=> nil
427
- parent_class #=> nil
428
- parent #=> nil
429
-
430
- == Singletons
431
-
432
- Now we are going to add manager to projects. We say that Manager is a singleton
433
- resource because a Project has just one manager. You should declare it as
434
- has_one (or resource) in your routes.
435
-
436
- To declare an association as singleton, you just have to give the :singleton
437
- option.
438
-
439
- class ManagersController < InheritedResources::Base
440
- belongs_to :project, :singleton => true
441
- # singleton_belongs_to :project
442
- end
443
-
444
- It will deal with everything again and hide the action :index from you.
445
-
446
- == Namespaced Controllers
447
-
448
- Namespaced controllers works out the box.
449
-
450
- class Forum::PostsController < InheritedResources::Base
451
- end
452
-
453
- Inherited Resources prioritizes the default resource class for the namespaced controller in
454
- this order:
455
-
456
- Forum::Post
457
- ForumPost
458
- Post
459
-
460
- == URL Helpers
461
-
462
- When you use InheritedResources it creates some URL helpers.
463
- And they handle everything for you. :)
464
-
465
- # /posts/1/comments
466
- resource_url # => /posts/1/comments/#{@comment.to_param}
467
- resource_url(comment) # => /posts/1/comments/#{comment.to_param}
468
- new_resource_url # => /posts/1/comments/new
469
- edit_resource_url # => /posts/1/comments/#{@comment.to_param}/edit
470
- edit_resource_url(comment) # => /posts/1/comments/#{comment.to_param}/edit
471
- collection_url # => /posts/1/comments
472
- parent_url # => /posts/1
473
-
474
- # /projects/1/tasks
475
- resource_url # => /projects/1/tasks/#{@task.to_param}
476
- resource_url(task) # => /projects/1/tasks/#{task.to_param}
477
- new_resource_url # => /projects/1/tasks/new
478
- edit_resource_url # => /projects/1/tasks/#{@task.to_param}/edit
479
- edit_resource_url(task) # => /projects/1/tasks/#{task.to_param}/edit
480
- collection_url # => /projects/1/tasks
481
- parent_url # => /projects/1
482
-
483
- # /users
484
- resource_url # => /users/#{@user.to_param}
485
- resource_url(user) # => /users/#{user.to_param}
486
- new_resource_url # => /users/new
487
- edit_resource_url # => /users/#{@user.to_param}/edit
488
- edit_resource_url(user) # => /users/#{user.to_param}/edit
489
- collection_url # => /users
490
- parent_url # => /
491
-
492
- Those urls helpers also accepts a hash as options, just as in named routes.
493
-
494
- # /projects/1/tasks
495
- collection_url(:page => 1, :limit => 10) #=> /projects/1/tasks?page=1&limit=10
496
-
497
- In polymorphic cases, you can also give the parent as parameter to collection_url.
498
-
499
- Another nice thing is that those urls are not guessed during runtime. They are
500
- all created when your application is loaded (except for polymorphic
501
- associations, that relies on Rails polymorphic_url).
502
-
503
- == Custom actions
504
-
505
- Since version 1.2, Inherited Resources allows you to define custom actions in controller:
506
-
507
- class ButtonsController < InheritedResources::Base
508
- custom_actions :resource => :delete, :collection => :search
509
- end
510
-
511
- This code creates delete and search actions in controller (they behaves like show and
512
- index actions accordingly). Also, it will produce delete_resource_{path,url} and
513
- search_resources_{path,url} url helpers.
514
-
515
- == What about views?
516
-
517
- Sometimes just DRYing up the controllers is not enough. If you need to DRY up your views,
518
- check this Wiki page:
519
-
520
- https://github.com/josevalim/inherited_resources/wiki/Views-Inheritance
521
-
522
- Notice that Rails 3.1 ships with view inheritance built-in.
523
-
524
- == Some DSL
525
-
526
- For those DSL lovers, InheritedResources won't leave you alone. You can overwrite
527
- your success/failure blocks straight from your class binding. For it, you just
528
- need to add a DSL module to your application controller:
529
-
530
- class ApplicationController < ActionController::Base
531
- include InheritedResources::DSL
532
- end
533
-
534
- And then you can rewrite the last example as:
535
-
536
- class ProjectsController < InheritedResources::Base
537
- update! do |success, failure|
538
- failure.html { redirect_to project_url(@project) }
539
- end
540
- end
541
-
542
- == Strong Parameters
543
-
544
- If your controller defines a method named permitted_params, Inherited Resources will call it where it would normally call params. This allows for easy integration with the strong_parameters gem:
545
-
546
- def permitted_params
547
- params.permit(:widget => [:permitted_field, :other_permitted_field])
548
- end
549
-
550
- Note that this doesn't work if you use strong_parameters' require method instead of permit, because whereas permit returns the entire sanitized parameter hash, require returns only the sanitized params below the parameter you required.
551
-
552
- == Bugs and Feedback
553
-
554
- If you discover any bugs, please describe it in the issues tracker, including Rails and Inherited Resources versions.
555
-
556
- Questions are better handled on StackOverflow.
557
-
558
- Copyright (c) 2009-2012 José Valim http://blog.plataformatec.com.br
559
- See the attached MIT License.