resource_controller 0.4.9 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +37 -1
- data/Rakefile +2 -2
- data/lib/resource_controller.rb +10 -5
- data/lib/resource_controller/class_methods.rb +3 -1
- data/lib/resource_controller/controller.rb +6 -0
- data/lib/resource_controller/helpers/nested.rb +21 -3
- data/lib/resource_controller/helpers/singleton_customizations.rb +60 -0
- data/lib/resource_controller/helpers/urls.rb +5 -1
- data/lib/resource_controller/singleton.rb +15 -0
- data/lib/resource_controller/version.rb +2 -2
- data/test/app/controllers/accounts_controller.rb +6 -0
- data/test/app/controllers/cms/products_controller.rb +1 -1
- data/test/app/controllers/images_controller.rb +4 -0
- data/test/app/controllers/options_controller.rb +8 -0
- data/test/app/helpers/accounts_helper.rb +2 -0
- data/test/app/helpers/images_helper.rb +2 -0
- data/test/app/models/account.rb +1 -0
- data/test/app/models/image.rb +3 -0
- data/test/app/models/user.rb +3 -0
- data/test/app/views/accounts/_form.html.erb +4 -0
- data/test/app/views/accounts/edit.html.erb +14 -0
- data/test/app/views/accounts/new.html.erb +12 -0
- data/test/app/views/accounts/show.html.erb +5 -0
- data/test/app/views/images/_form.html.erb +4 -0
- data/test/app/views/images/edit.html.erb +14 -0
- data/test/app/views/images/new.html.erb +12 -0
- data/test/app/views/options/_form.html.erb +8 -0
- data/test/app/views/options/edit.html.erb +16 -0
- data/test/app/views/options/index.html.erb +21 -0
- data/test/app/views/options/new.html.erb +12 -0
- data/test/app/views/options/show.html.erb +10 -0
- data/test/config/database.yml +0 -3
- data/test/config/environment.rb +2 -2
- data/test/config/routes.rb +8 -1
- data/test/db/migrate/002_create_products.rb +1 -1
- data/test/db/migrate/004_create_options.rb +3 -2
- data/test/db/migrate/011_create_images.rb +12 -0
- data/test/db/migrate/012_create_users.rb +11 -0
- data/test/db/schema.rb +13 -6
- data/test/log/development.log +84 -0
- data/test/log/test.log +4880 -0
- data/test/test/fixtures/images.yml +6 -0
- data/test/test/fixtures/users.yml +5 -0
- data/test/test/functional/images_controller_test.rb +37 -0
- data/test/test/unit/helpers/current_objects_test.rb +6 -0
- data/test/test/unit/helpers/nested_test.rb +5 -1
- data/test/test/unit/helpers/singleton_current_objects_test.rb +68 -0
- data/test/test/unit/helpers/singleton_nested_test.rb +77 -0
- data/test/test/unit/helpers/singleton_urls_test.rb +67 -0
- data/test/test/unit/helpers/urls_test.rb +5 -1
- data/test/test/unit/image_test.rb +7 -0
- metadata +35 -5
- data/README +0 -282
- data/lib/tasks/gem.rake +0 -67
data/README
DELETED
@@ -1,282 +0,0 @@
|
|
1
|
-
= Resource Controller
|
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
|
-
Add it as a gem dependency
|
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
|
14
|
-
|
15
|
-
Or grab the source
|
16
|
-
|
17
|
-
git clone git://github.com/giraffesoft/resource_controller.git
|
18
|
-
|
19
|
-
= Usage
|
20
|
-
|
21
|
-
Creating a basic RESTful controller is as easy as...
|
22
|
-
|
23
|
-
class PostsController < ResourceController::Base
|
24
|
-
end
|
25
|
-
|
26
|
-
...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:
|
27
|
-
|
28
|
-
class PostsController < ApplicationController
|
29
|
-
resource_controller
|
30
|
-
end
|
31
|
-
|
32
|
-
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.
|
33
|
-
|
34
|
-
|
35
|
-
Nobody just uses the default RESTful controller, though. resource_controller provides a simple API for customizations.
|
36
|
-
|
37
|
-
== Action Lifecycle
|
38
|
-
|
39
|
-
It's really easy to make changes to the lifecycle of your actions.
|
40
|
-
|
41
|
-
Note: We had to call the new accessor "new_action", since new is somewhat reserved in ruby.
|
42
|
-
|
43
|
-
=== Before and After
|
44
|
-
|
45
|
-
class ProjectsController < ResourceController::Base
|
46
|
-
|
47
|
-
new_action.before do
|
48
|
-
3.times { object.tasks.build }
|
49
|
-
end
|
50
|
-
|
51
|
-
create.after do
|
52
|
-
object.creator = current_user
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
=== Flash
|
58
|
-
|
59
|
-
class ProjectsController < ResourceController::Base
|
60
|
-
create.flash "Can you believe how easy it is to use resource_controller? Neither could I!"
|
61
|
-
end
|
62
|
-
|
63
|
-
=== respond_to
|
64
|
-
|
65
|
-
You can add to what's already there...
|
66
|
-
|
67
|
-
class ProjectsController < ResourceController::Base
|
68
|
-
create.wants.js { render :template => "show.rjs" }
|
69
|
-
end
|
70
|
-
|
71
|
-
Or you can create a whole new block. This syntax destroys everything that's there, and starts again...
|
72
|
-
|
73
|
-
class ProjectsController < ResourceController::Base
|
74
|
-
create.response do |wants|
|
75
|
-
wants.html
|
76
|
-
wants.js { render :template => "show.rjs" }
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
=== Scoping
|
81
|
-
|
82
|
-
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.
|
83
|
-
|
84
|
-
With actions that can fail, the scoping defaults to success. That means that create.flash == create.success.flash.
|
85
|
-
|
86
|
-
class ProjectsController < ResourceController::Base
|
87
|
-
|
88
|
-
create do
|
89
|
-
flash "Object successfully created!"
|
90
|
-
wants.js { render :template => "show.rjs" }
|
91
|
-
|
92
|
-
failure.wants.js { render :template => "display_errors.rjs" }
|
93
|
-
end
|
94
|
-
|
95
|
-
destroy do
|
96
|
-
flash "You destroyed your project. Good work."
|
97
|
-
|
98
|
-
failure do
|
99
|
-
flash "You cannot destroy that project. Stop trying!"
|
100
|
-
wants.js { render :template => "display_errors.rjs" }
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
|
-
== Helpers (ResourceController::Helpers)
|
107
|
-
|
108
|
-
=== Loading objects
|
109
|
-
|
110
|
-
You want to add something like pagination to your controller...
|
111
|
-
|
112
|
-
class PostsController < ResourceController::Base
|
113
|
-
private
|
114
|
-
def collection
|
115
|
-
@collection ||= end_of_association_chain.find(:all, :page => {:size => 10, :current => params[:page]})
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
Or maybe you used a permalink...
|
120
|
-
|
121
|
-
class PostsController < ResourceController::Base
|
122
|
-
private
|
123
|
-
def object
|
124
|
-
@object ||= end_of_association_chain.find_by_permalink(param)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
=== Building objects
|
129
|
-
|
130
|
-
Maybe you have some alternative way of building objects...
|
131
|
-
|
132
|
-
class PostsController < ResourceController::Base
|
133
|
-
private
|
134
|
-
def build_object
|
135
|
-
@object ||= end_of_association_chain.build_my_object_some_funky_way object_params
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
...and there are tons more helpers in the ResourceController::Helpers
|
140
|
-
|
141
|
-
== Nested Resources
|
142
|
-
|
143
|
-
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.
|
144
|
-
|
145
|
-
class CommentsController < ResourceController::Base
|
146
|
-
belongs_to :post
|
147
|
-
end
|
148
|
-
|
149
|
-
All of the finding, and creation, and everything will be done at the scope of the post automatically.
|
150
|
-
|
151
|
-
== Namespaced Resources
|
152
|
-
|
153
|
-
...are handled automatically, and any namespaces are always available, symbolized, in array form @ ResourceController::Helpers#namespaces
|
154
|
-
|
155
|
-
== Polymorphic Resources
|
156
|
-
|
157
|
-
Everything, including url generation is handled completely automatically. Take this example...
|
158
|
-
|
159
|
-
## comment.rb
|
160
|
-
class Comment
|
161
|
-
belongs_to :commentable, :polymorphic => true
|
162
|
-
end
|
163
|
-
|
164
|
-
## comments_controller.rb
|
165
|
-
class CommentsController < ResourceController::Base
|
166
|
-
belongs_to :post, :product, :user
|
167
|
-
end
|
168
|
-
*Note:* Your model doesn't have to be polymorphic in the ActiveRecord sense. It can be associated in whichever way you want.
|
169
|
-
|
170
|
-
## routes.rb
|
171
|
-
map.resources :posts, :has_many => :comments
|
172
|
-
map.resources :products, :has_many => :comments
|
173
|
-
map.resources :users, :has_many => :comments
|
174
|
-
|
175
|
-
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.
|
176
|
-
|
177
|
-
=== Parent Helpers
|
178
|
-
|
179
|
-
You also get some helpers for reflecting on your parent.
|
180
|
-
|
181
|
-
parent? # => true/false is there a parent present?
|
182
|
-
parent_type # => :post
|
183
|
-
parent_model # => Post
|
184
|
-
parent_object # => @post
|
185
|
-
|
186
|
-
=== Non-standard resource names
|
187
|
-
|
188
|
-
resource_controller supports overrides for every non-standard configuration of resources.
|
189
|
-
|
190
|
-
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.
|
191
|
-
|
192
|
-
map.resources :tags
|
193
|
-
...
|
194
|
-
class PhotoTag < ActiveRecord::Base
|
195
|
-
...
|
196
|
-
class TagsController < ResourceController::Base
|
197
|
-
private
|
198
|
-
def model_name
|
199
|
-
'photo_tag'
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
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.
|
204
|
-
|
205
|
-
def object_name
|
206
|
-
'photo_tag'
|
207
|
-
end
|
208
|
-
|
209
|
-
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.
|
210
|
-
|
211
|
-
map.resources :tags, :controller => "somethings"
|
212
|
-
...
|
213
|
-
class Tag < ActiveRecord::Base
|
214
|
-
...
|
215
|
-
class SomethingsController < ResourceController::Base
|
216
|
-
private
|
217
|
-
def resource_name
|
218
|
-
'tag'
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
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.
|
223
|
-
|
224
|
-
map.resources :tags, :controller => "taggings"
|
225
|
-
...
|
226
|
-
class Taggings < ActiveRecord::Base
|
227
|
-
...
|
228
|
-
class TaggingsController < ResourceController::Base
|
229
|
-
private
|
230
|
-
def route_name
|
231
|
-
'tag'
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
== Url Helpers
|
236
|
-
|
237
|
-
Thanks to Urligence, you also get some free url helpers.
|
238
|
-
|
239
|
-
No matter what your controller looks like...
|
240
|
-
|
241
|
-
[edit_|new_]object_url # is the equivalent of saying [edit_|new_]post_url(@post)
|
242
|
-
[edit_|new_]object_url(some_other_object) # allows you to specify an object, but still maintain any paths or namespaces that are present
|
243
|
-
|
244
|
-
collection_url # is like saying posts_url
|
245
|
-
|
246
|
-
Url helpers are especially useful when working with polymorphic controllers.
|
247
|
-
|
248
|
-
# /posts/1/comments
|
249
|
-
object_url # => /posts/1/comments/#{@comment.to_param}
|
250
|
-
object_url(comment) # => /posts/1/comments/#{comment.to_param}
|
251
|
-
edit_object_url # => /posts/1/comments/#{@comment.to_param}/edit
|
252
|
-
collection_url # => /posts/1/comments
|
253
|
-
|
254
|
-
# /products/1/comments
|
255
|
-
object_url # => /products/1/comments/#{@comment.to_param}
|
256
|
-
object_url(comment) # => /products/1/comments/#{comment.to_param}
|
257
|
-
edit_object_url # => /products/1/comments/#{@comment.to_param}/edit
|
258
|
-
collection_url # => /products/1/comments
|
259
|
-
|
260
|
-
# /comments
|
261
|
-
object_url # => /comments/#{@comment.to_param}
|
262
|
-
object_url(comment) # => /comments/#{comment.to_param}
|
263
|
-
edit_object_url # => /comments/#{@comment.to_param}/edit
|
264
|
-
collection_url # => /comments
|
265
|
-
|
266
|
-
Or with namespaced, nested controllers...
|
267
|
-
|
268
|
-
# /admin/products/1/options
|
269
|
-
object_url # => /admin/products/1/options/#{@option.to_param}
|
270
|
-
object_url(option) # => /admin/products/1/options/#{option.to_param}
|
271
|
-
edit_object_url # => /admin/products/1/options/#{@option.to_param}/edit
|
272
|
-
collection_url # => /admin/products/1/options
|
273
|
-
|
274
|
-
You get the idea. Everything is automagical! All parameters are inferred.
|
275
|
-
|
276
|
-
== Credits
|
277
|
-
|
278
|
-
resource_controller was created, and is maintained by {James Golick}[http://jamesgolick.com].
|
279
|
-
|
280
|
-
== License
|
281
|
-
|
282
|
-
resource_controller is available under the {MIT License}[http://en.wikipedia.org/wiki/MIT_License]
|
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
|