giraffesoft-resource_controller 0.4.10 → 0.4.12
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -312
- data/README.rdoc +40 -10
- data/Rakefile +1 -1
- data/lib/resource_controller/version.rb +1 -1
- metadata +2 -4
- data/lib/tasks/gem.rake +0 -67
data/README
CHANGED
@@ -1,312 +1 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
resource_controller makes RESTful controllers easier, more maintainable, and super readable. With the RESTful controller pattern hidden away, you can focus on what makes your controller special.
|
4
|
-
|
5
|
-
== Get It
|
6
|
-
|
7
|
-
svn export http://svn.jamesgolick.com/resource_controller/tags/stable vendor/plugins/resource_controller
|
8
|
-
|
9
|
-
SVN (stable): {http://svn.jamesgolick.com/resource_controller/tags/stable}[http://svn.jamesgolick.com/resource_controller/tags/stable]
|
10
|
-
|
11
|
-
SVN (ongoing): {http://svn.jamesgolick.com/resource_controller/trunk}[http://svn.jamesgolick.com/resource_controller/trunk]
|
12
|
-
|
13
|
-
= Usage
|
14
|
-
|
15
|
-
Creating a basic RESTful controller is as easy as...
|
16
|
-
|
17
|
-
class PostsController < ResourceController::Base
|
18
|
-
end
|
19
|
-
|
20
|
-
...or if you prefer, you can use the method-call syntax. If you need to inherit from some other class, this syntax is definitely for you:
|
21
|
-
|
22
|
-
class PostsController < ApplicationController
|
23
|
-
resource_controller
|
24
|
-
end
|
25
|
-
|
26
|
-
Both syntaxes are identical in their behavior. Just make sure you call resource_controller before you use any other r_c functionality in your controller.
|
27
|
-
|
28
|
-
|
29
|
-
Nobody just uses the default RESTful controller, though. resource_controller provides a simple API for customizations.
|
30
|
-
|
31
|
-
== Action Lifecycle
|
32
|
-
|
33
|
-
It's really easy to make changes to the lifecycle of your actions.
|
34
|
-
|
35
|
-
Note: We had to call the new accessor "new_action", since new is somewhat reserved in ruby.
|
36
|
-
|
37
|
-
=== Before and After
|
38
|
-
|
39
|
-
class ProjectsController < ResourceController::Base
|
40
|
-
|
41
|
-
new_action.before do
|
42
|
-
3.times { object.tasks.build }
|
43
|
-
end
|
44
|
-
|
45
|
-
create.after do
|
46
|
-
object.creator = current_user
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
=== Flash
|
52
|
-
|
53
|
-
class ProjectsController < ResourceController::Base
|
54
|
-
create.flash "Can you believe how easy it is to use resource_controller? Neither could I!"
|
55
|
-
end
|
56
|
-
|
57
|
-
=== respond_to
|
58
|
-
|
59
|
-
You can add to what's already there...
|
60
|
-
|
61
|
-
class ProjectsController < ResourceController::Base
|
62
|
-
create.wants.js { render :template => "show.rjs" }
|
63
|
-
end
|
64
|
-
|
65
|
-
Or you can create a whole new block. This syntax destroys everything that's there, and starts again...
|
66
|
-
|
67
|
-
class ProjectsController < ResourceController::Base
|
68
|
-
create.response do |wants|
|
69
|
-
wants.html
|
70
|
-
wants.js { render :template => "show.rjs" }
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
=== Scoping
|
75
|
-
|
76
|
-
Because sometimes you want to make a bunch of customizations at once, most of the helpers accept blocks that make grouping calls really easy. Is it a DSL? Maybe; maybe not. But, it's definitely awesome.
|
77
|
-
|
78
|
-
With actions that can fail, the scoping defaults to success. That means that create.flash == create.success.flash.
|
79
|
-
|
80
|
-
class ProjectsController < ResourceController::Base
|
81
|
-
|
82
|
-
create do
|
83
|
-
flash "Object successfully created!"
|
84
|
-
wants.js { render :template => "show.rjs" }
|
85
|
-
|
86
|
-
failure.wants.js { render :template => "display_errors.rjs" }
|
87
|
-
end
|
88
|
-
|
89
|
-
destroy do
|
90
|
-
flash "You destroyed your project. Good work."
|
91
|
-
|
92
|
-
failure do
|
93
|
-
flash "You cannot destroy that project. Stop trying!"
|
94
|
-
wants.js { render :template => "display_errors.rjs" }
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
== Helpers (ResourceController::Helpers)
|
101
|
-
|
102
|
-
=== Loading objects
|
103
|
-
|
104
|
-
You want to add something like pagination to your controller...
|
105
|
-
|
106
|
-
class PostsController < ResourceController::Base
|
107
|
-
private
|
108
|
-
def collection
|
109
|
-
@collection ||= end_of_association_chain.find(:all, :page => {:size => 10, :current => params[:page]})
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
Or maybe you used a permalink...
|
114
|
-
|
115
|
-
class PostsController < ResourceController::Base
|
116
|
-
private
|
117
|
-
def object
|
118
|
-
@object ||= end_of_association_chain.find_by_permalink(param)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
=== Building objects
|
123
|
-
|
124
|
-
Maybe you have some alternative way of building objects...
|
125
|
-
|
126
|
-
class PostsController < ResourceController::Base
|
127
|
-
private
|
128
|
-
def build_object
|
129
|
-
@object ||= end_of_association_chain.build_my_object_some_funky_way object_params
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
...and there are tons more helpers in the ResourceController::Helpers
|
134
|
-
|
135
|
-
== Nested Resources
|
136
|
-
|
137
|
-
Nested controllers can be a pain, especially if routing is such that you may or may not have a parent. Not so with Resource Controller.
|
138
|
-
|
139
|
-
class CommentsController < ResourceController::Base
|
140
|
-
belongs_to :post
|
141
|
-
end
|
142
|
-
|
143
|
-
All of the finding, and creation, and everything will be done at the scope of the post automatically.
|
144
|
-
|
145
|
-
== Namespaced Resources
|
146
|
-
|
147
|
-
...are handled automatically, and any namespaces are always available, symbolized, in array form @ ResourceController::Helpers#namespaces
|
148
|
-
|
149
|
-
== Polymorphic Resources
|
150
|
-
|
151
|
-
Everything, including url generation is handled completely automatically. Take this example...
|
152
|
-
|
153
|
-
## comment.rb
|
154
|
-
class Comment
|
155
|
-
belongs_to :commentable, :polymorphic => true
|
156
|
-
end
|
157
|
-
|
158
|
-
## comments_controller.rb
|
159
|
-
class CommentsController < ResourceController::Base
|
160
|
-
belongs_to :post, :product, :user
|
161
|
-
end
|
162
|
-
*Note:* Your model doesn't have to be polymorphic in the ActiveRecord sense. It can be associated in whichever way you want.
|
163
|
-
|
164
|
-
## routes.rb
|
165
|
-
map.resources :posts, :has_many => :comments
|
166
|
-
map.resources :products, :has_many => :comments
|
167
|
-
map.resources :users, :has_many => :comments
|
168
|
-
|
169
|
-
All you have to do is that, and r_c will infer whichever relationship is present, and perform all the actions at the scope of the parent object.
|
170
|
-
|
171
|
-
=== Parent Helpers
|
172
|
-
|
173
|
-
You also get some helpers for reflecting on your parent.
|
174
|
-
|
175
|
-
parent? # => true/false is there a parent present?
|
176
|
-
parent_type # => :post
|
177
|
-
parent_model # => Post
|
178
|
-
parent_object # => @post
|
179
|
-
|
180
|
-
=== Non-standard resource names
|
181
|
-
|
182
|
-
resource_controller supports overrides for every non-standard configuration of resources.
|
183
|
-
|
184
|
-
The most common example is where the resource has a different name than the associated model. Simply overriding the model_name helper will get resource_controller working with your model.
|
185
|
-
|
186
|
-
map.resources :tags
|
187
|
-
...
|
188
|
-
class PhotoTag < ActiveRecord::Base
|
189
|
-
...
|
190
|
-
class TagsController < ResourceController::Base
|
191
|
-
private
|
192
|
-
def model_name
|
193
|
-
'photo_tag'
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
In the above example, the variable, and params will be set to @tag, @tags, and params[:tag]. If you'd like to change that, override object_name.
|
198
|
-
|
199
|
-
def object_name
|
200
|
-
'photo_tag'
|
201
|
-
end
|
202
|
-
|
203
|
-
If you're using a non-standard controller name, but everything else is standard, overriding resource_name will propagate through all of the other helpers.
|
204
|
-
|
205
|
-
map.resources :tags, :controller => "somethings"
|
206
|
-
...
|
207
|
-
class Tag < ActiveRecord::Base
|
208
|
-
...
|
209
|
-
class SomethingsController < ResourceController::Base
|
210
|
-
private
|
211
|
-
def resource_name
|
212
|
-
'tag'
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
Finally, the route_name helper is used by Urligence to determine which url helper to call, so if you have non-standard route names, override it.
|
217
|
-
|
218
|
-
map.resources :tags, :controller => "taggings"
|
219
|
-
...
|
220
|
-
class Taggings < ActiveRecord::Base
|
221
|
-
...
|
222
|
-
class TaggingsController < ResourceController::Base
|
223
|
-
private
|
224
|
-
def route_name
|
225
|
-
'tag'
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
== Singleton Resource
|
230
|
-
|
231
|
-
If you want to create a singleton RESTful controller inherit from ResourceController::Singleton.
|
232
|
-
|
233
|
-
class AccountsController < ResourceController::Singleton
|
234
|
-
end
|
235
|
-
|
236
|
-
*Note:* This type of controllers handle a single resource only so the index action and all the collection helpers (collection_url, collection_path...) are not available for them.
|
237
|
-
|
238
|
-
Loading objects in singletons is similar to plural controllers with one exception. For non-nested singleton controllers you should override the object method as it defaults to nil for them.
|
239
|
-
|
240
|
-
class AccountsController < ResourceController::Singleton
|
241
|
-
private
|
242
|
-
def object
|
243
|
-
@object ||= Account.find(session[:account_id])
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
In other cases you can use the default logic and override it only if you use permalinks or anything special.
|
248
|
-
|
249
|
-
Singleton nesting with both :has_many and :has_one associations is provided...
|
250
|
-
|
251
|
-
map.resource :account, :has_many => :options # /account/options, account is a singleton parent
|
252
|
-
map.resources :users, :has_one => :image # /users/1/image, image is a singleton child
|
253
|
-
|
254
|
-
If you have the :has_many association with a singleton parent remember to override parent_object for your :has_many controller as it returns nil by default in this case.
|
255
|
-
|
256
|
-
class OptionsController < ResourceController::Base
|
257
|
-
belongs_to :account
|
258
|
-
|
259
|
-
protected
|
260
|
-
def parent_object
|
261
|
-
Account.find(session[:account_id])
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
== Url Helpers
|
266
|
-
|
267
|
-
Thanks to Urligence, you also get some free url helpers.
|
268
|
-
|
269
|
-
No matter what your controller looks like...
|
270
|
-
|
271
|
-
[edit_|new_]object_url # is the equivalent of saying [edit_|new_]post_url(@post)
|
272
|
-
[edit_|new_]object_url(some_other_object) # allows you to specify an object, but still maintain any paths or namespaces that are present
|
273
|
-
|
274
|
-
collection_url # is like saying posts_url
|
275
|
-
|
276
|
-
Url helpers are especially useful when working with polymorphic controllers.
|
277
|
-
|
278
|
-
# /posts/1/comments
|
279
|
-
object_url # => /posts/1/comments/#{@comment.to_param}
|
280
|
-
object_url(comment) # => /posts/1/comments/#{comment.to_param}
|
281
|
-
edit_object_url # => /posts/1/comments/#{@comment.to_param}/edit
|
282
|
-
collection_url # => /posts/1/comments
|
283
|
-
|
284
|
-
# /products/1/comments
|
285
|
-
object_url # => /products/1/comments/#{@comment.to_param}
|
286
|
-
object_url(comment) # => /products/1/comments/#{comment.to_param}
|
287
|
-
edit_object_url # => /products/1/comments/#{@comment.to_param}/edit
|
288
|
-
collection_url # => /products/1/comments
|
289
|
-
|
290
|
-
# /comments
|
291
|
-
object_url # => /comments/#{@comment.to_param}
|
292
|
-
object_url(comment) # => /comments/#{comment.to_param}
|
293
|
-
edit_object_url # => /comments/#{@comment.to_param}/edit
|
294
|
-
collection_url # => /comments
|
295
|
-
|
296
|
-
Or with namespaced, nested controllers...
|
297
|
-
|
298
|
-
# /admin/products/1/options
|
299
|
-
object_url # => /admin/products/1/options/#{@option.to_param}
|
300
|
-
object_url(option) # => /admin/products/1/options/#{option.to_param}
|
301
|
-
edit_object_url # => /admin/products/1/options/#{@option.to_param}/edit
|
302
|
-
collection_url # => /admin/products/1/options
|
303
|
-
|
304
|
-
You get the idea. Everything is automagical! All parameters are inferred.
|
305
|
-
|
306
|
-
== Credits
|
307
|
-
|
308
|
-
resource_controller was created, and is maintained by {James Golick}[http://jamesgolick.com].
|
309
|
-
|
310
|
-
== License
|
311
|
-
|
312
|
-
resource_controller is available under the {MIT License}[http://en.wikipedia.org/wiki/MIT_License]
|
1
|
+
README.rdoc
|
data/README.rdoc
CHANGED
@@ -4,17 +4,11 @@ resource_controller makes RESTful controllers easier, more maintainable, and sup
|
|
4
4
|
|
5
5
|
== Get It
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
config.gem 'giraffesoft-resource_controller', :lib => 'resource_controller', :source => 'http://gems.github.com'
|
10
|
-
|
11
|
-
Or install it as a gem manually
|
12
|
-
|
13
|
-
sudo gem install giraffesoft-resource_controller
|
7
|
+
svn export http://svn.jamesgolick.com/resource_controller/tags/stable vendor/plugins/resource_controller
|
14
8
|
|
15
|
-
|
16
|
-
|
17
|
-
|
9
|
+
SVN (stable): {http://svn.jamesgolick.com/resource_controller/tags/stable}[http://svn.jamesgolick.com/resource_controller/tags/stable]
|
10
|
+
|
11
|
+
SVN (ongoing): {http://svn.jamesgolick.com/resource_controller/trunk}[http://svn.jamesgolick.com/resource_controller/trunk]
|
18
12
|
|
19
13
|
= Usage
|
20
14
|
|
@@ -232,6 +226,42 @@ Finally, the route_name helper is used by Urligence to determine which url helpe
|
|
232
226
|
end
|
233
227
|
end
|
234
228
|
|
229
|
+
== Singleton Resource
|
230
|
+
|
231
|
+
If you want to create a singleton RESTful controller inherit from ResourceController::Singleton.
|
232
|
+
|
233
|
+
class AccountsController < ResourceController::Singleton
|
234
|
+
end
|
235
|
+
|
236
|
+
*Note:* This type of controllers handle a single resource only so the index action and all the collection helpers (collection_url, collection_path...) are not available for them.
|
237
|
+
|
238
|
+
Loading objects in singletons is similar to plural controllers with one exception. For non-nested singleton controllers you should override the object method as it defaults to nil for them.
|
239
|
+
|
240
|
+
class AccountsController < ResourceController::Singleton
|
241
|
+
private
|
242
|
+
def object
|
243
|
+
@object ||= Account.find(session[:account_id])
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
In other cases you can use the default logic and override it only if you use permalinks or anything special.
|
248
|
+
|
249
|
+
Singleton nesting with both :has_many and :has_one associations is provided...
|
250
|
+
|
251
|
+
map.resource :account, :has_many => :options # /account/options, account is a singleton parent
|
252
|
+
map.resources :users, :has_one => :image # /users/1/image, image is a singleton child
|
253
|
+
|
254
|
+
If you have the :has_many association with a singleton parent remember to override parent_object for your :has_many controller as it returns nil by default in this case.
|
255
|
+
|
256
|
+
class OptionsController < ResourceController::Base
|
257
|
+
belongs_to :account
|
258
|
+
|
259
|
+
protected
|
260
|
+
def parent_object
|
261
|
+
Account.find(session[:account_id])
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
235
265
|
== Url Helpers
|
236
266
|
|
237
267
|
Thanks to Urligence, you also get some free url helpers.
|
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@ require 'rake'
|
|
2
2
|
require 'rake/testtask'
|
3
3
|
require 'rake/rdoctask'
|
4
4
|
require File.dirname(__FILE__)+'/lib/resource_controller/version'
|
5
|
-
Dir['
|
5
|
+
Dir['tasks/**.rake'].each { |tasks| load tasks }
|
6
6
|
|
7
7
|
desc 'Default: run unit tests.'
|
8
8
|
task :default => :test
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: giraffesoft-resource_controller
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Golick
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-08-
|
12
|
+
date: 2008-08-10 21:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -46,8 +46,6 @@ files:
|
|
46
46
|
- lib/resource_controller/singleton.rb
|
47
47
|
- lib/resource_controller/version.rb
|
48
48
|
- lib/resource_controller.rb
|
49
|
-
- lib/tasks
|
50
|
-
- lib/tasks/gem.rake
|
51
49
|
- lib/urligence.rb
|
52
50
|
- test/app
|
53
51
|
- test/app/controllers
|
data/lib/tasks/gem.rake
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
require 'rake/gempackagetask'
|
2
|
-
require 'yaml'
|
3
|
-
|
4
|
-
task :clean => :clobber_package
|
5
|
-
|
6
|
-
spec = Gem::Specification.new do |s|
|
7
|
-
s.name = 'resource_controller'
|
8
|
-
s.version = ResourceController::VERSION::STRING
|
9
|
-
s.summary = "resource_controller makes RESTful controllers easier, more maintainable, and super readable. With the RESTful controller pattern hidden away, you can focus on what makes your controller special."
|
10
|
-
s.rubyforge_project = "giraffesoft"
|
11
|
-
s.description = "Rails RESTful controller abstraction plugin."
|
12
|
-
s.author = "James Golick"
|
13
|
-
s.email = "james@giraffesoft.ca"
|
14
|
-
s.homepage = "http://jamesgolick.com/resource_controller"
|
15
|
-
s.has_rdoc = true
|
16
|
-
|
17
|
-
s.required_ruby_version = '>= 1.8.5'
|
18
|
-
|
19
|
-
s.files = %w(README.rdoc README LICENSE init.rb Rakefile) +
|
20
|
-
Dir.glob("{lib,test,generators,rails}/**/*")
|
21
|
-
|
22
|
-
s.require_path = "lib"
|
23
|
-
end
|
24
|
-
|
25
|
-
Rake::GemPackageTask.new(spec) do |p|
|
26
|
-
p.gem_spec = spec
|
27
|
-
end
|
28
|
-
|
29
|
-
task :tag_warn do
|
30
|
-
puts "*" * 40
|
31
|
-
puts "Don't forget to tag the release:"
|
32
|
-
puts
|
33
|
-
puts " git tag -a v#{ResourceController::VERSION::STRING}"
|
34
|
-
puts
|
35
|
-
puts "or run rake tag"
|
36
|
-
puts "*" * 40
|
37
|
-
end
|
38
|
-
|
39
|
-
task :tag do
|
40
|
-
sh "git tag -a v#{ResourceController::VERSION::STRING}"
|
41
|
-
end
|
42
|
-
task :gem => :tag_warn
|
43
|
-
|
44
|
-
namespace :gem do
|
45
|
-
desc 'Upload gems to rubyforge.org'
|
46
|
-
task :rubyforge => :gem do
|
47
|
-
sh 'rubyforge login'
|
48
|
-
sh "rubyforge add_release giraffesoft resource_controller #{ResourceController::VERSION::STRING} pkg/#{spec.full_name}.gem"
|
49
|
-
sh "rubyforge add_file giraffesoft resource_controller #{ResourceController::VERSION::STRING} pkg/#{spec.full_name}.gem"
|
50
|
-
end
|
51
|
-
|
52
|
-
desc "Update the gemspec for GitHub's gem server"
|
53
|
-
task :github do
|
54
|
-
File.open("resource_controller.gemspec", 'w'){|f| f.puts YAML::dump(spec) }
|
55
|
-
puts "gemspec generated here: resource_controller.gemspec"
|
56
|
-
end
|
57
|
-
|
58
|
-
desc "Build and install the gem locally."
|
59
|
-
task :install => [:clobber, :package] do
|
60
|
-
sh "sudo gem install pkg/#{spec.full_name}.gem"
|
61
|
-
end
|
62
|
-
|
63
|
-
desc "Remove the gem."
|
64
|
-
task :uninstall => :clean do
|
65
|
-
sh "sudo gem uninstall -v #{ResourceController::VERSION::STRING} -x #{ResourceController::NAME}"
|
66
|
-
end
|
67
|
-
end
|