inherited_resources 1.4.0 → 1.4.1

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.
@@ -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.