snusnu-merb_resource_controller 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/LICENSE +20 -0
  2. data/README.textile +306 -0
  3. data/Rakefile +81 -0
  4. data/TODO +7 -0
  5. data/lib/merb_resource_controller/action_timeout_support.rb +53 -0
  6. data/lib/merb_resource_controller/actions.rb +169 -0
  7. data/lib/merb_resource_controller/identity_map_support.rb +20 -0
  8. data/lib/merb_resource_controller/resource_controller.rb +160 -0
  9. data/lib/merb_resource_controller/resource_proxy.rb +317 -0
  10. data/lib/merb_resource_controller.rb +29 -0
  11. data/spec/mrc_test_app/Rakefile +52 -0
  12. data/spec/mrc_test_app/app/controllers/application.rb +6 -0
  13. data/spec/mrc_test_app/app/controllers/articles.rb +3 -0
  14. data/spec/mrc_test_app/app/controllers/community/comments.rb +9 -0
  15. data/spec/mrc_test_app/app/controllers/community/ratings.rb +9 -0
  16. data/spec/mrc_test_app/app/controllers/editors.rb +7 -0
  17. data/spec/mrc_test_app/app/models/article.rb +19 -0
  18. data/spec/mrc_test_app/app/models/editor.rb +11 -0
  19. data/spec/mrc_test_app/app/views/articles/edit.html.erb +13 -0
  20. data/spec/mrc_test_app/app/views/articles/index.html.erb +25 -0
  21. data/spec/mrc_test_app/app/views/articles/new.html.erb +12 -0
  22. data/spec/mrc_test_app/app/views/articles/show.html.erb +8 -0
  23. data/spec/mrc_test_app/app/views/community/comments/edit.html.erb +12 -0
  24. data/spec/mrc_test_app/app/views/community/comments/index.html.erb +25 -0
  25. data/spec/mrc_test_app/app/views/community/comments/new.html.erb +3 -0
  26. data/spec/mrc_test_app/app/views/community/comments/show.html.erb +3 -0
  27. data/spec/mrc_test_app/app/views/community/ratings/edit.html.erb +11 -0
  28. data/spec/mrc_test_app/app/views/community/ratings/index.html.erb +25 -0
  29. data/spec/mrc_test_app/app/views/community/ratings/show.html.erb +3 -0
  30. data/spec/mrc_test_app/app/views/editors/edit.html.erb +12 -0
  31. data/spec/mrc_test_app/app/views/editors/new.html.erb +12 -0
  32. data/spec/mrc_test_app/app/views/editors/show.html.erb +7 -0
  33. data/spec/mrc_test_app/config/database.yml +33 -0
  34. data/spec/mrc_test_app/config/environments/development.rb +15 -0
  35. data/spec/mrc_test_app/config/environments/rake.rb +11 -0
  36. data/spec/mrc_test_app/config/environments/test.rb +12 -0
  37. data/spec/mrc_test_app/config/init.rb +36 -0
  38. data/spec/mrc_test_app/config/rack.rb +11 -0
  39. data/spec/mrc_test_app/config/router.rb +50 -0
  40. data/spec/mrc_test_app/spec/lib/resource_proxy_spec.rb +292 -0
  41. data/spec/mrc_test_app/spec/request/article_comments_spec.rb +208 -0
  42. data/spec/mrc_test_app/spec/request/article_editor_spec.rb +202 -0
  43. data/spec/mrc_test_app/spec/request/articles_spec.rb +208 -0
  44. data/spec/mrc_test_app/spec/request/comments_spec.rb +221 -0
  45. data/spec/mrc_test_app/spec/spec.opts +2 -0
  46. data/spec/mrc_test_app/spec/spec_helper.rb +206 -0
  47. metadata +166 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Martin Gamsjaeger
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,306 @@
1
+ h2. merb_resource_controller
2
+
3
+ A merb plugin that provides the default @CRUD@ actions for controllers and allows for easy customization
4
+ of the generated actions. @merb_resource_controller@ only supports @datamapper@ so far. Implementing support
5
+ for @active_record@ would be trivial, but I have no need for it.
6
+
7
+ Currently, @merb_resource_controller@ needs an extra specification inside the controller to define the nesting strategy
8
+ to use. This shouldn't really be necessary, since this information could be provided by the @Merb::Router@.
9
+ I'm planning to have a look into this soon! With that in place, nested resource_controllers could be _3 liners_
10
+ that just do what you would expect them to do.
11
+
12
+ To get you started with @merb_resource_controller@, all you have to do is extend it into your controller.
13
+ Most probably you will want extend it into the @Application@ controller, which will make the @controlling@
14
+ method available to all your application's controllers.
15
+
16
+ <pre>
17
+ <code>
18
+ class Application < Merb::Controller
19
+ extend Merb::ResourceController::Mixin::ClassMethods
20
+ end
21
+ </code>
22
+ </pre>
23
+
24
+ And here is a quick example showing a controller for a standard toplevel resource with all standard @CRUD@ actions.
25
+
26
+ <pre>
27
+ <code>
28
+ class Articles < Application
29
+ controlling :articles
30
+ end
31
+ </code>
32
+ </pre>
33
+
34
+ If you don't want all standard @CRUD@ actions to be generated, give @merb_resource_controller@ the exact list
35
+ of actions you want your controller to have.
36
+
37
+ <pre>
38
+ <code>
39
+ class Articles < Application
40
+ controlling :articles do |a|
41
+ a.action :create
42
+ a.action :update
43
+ end
44
+ end
45
+ </code>
46
+ </pre>
47
+
48
+ Alternatively, you can also add more than one action at once using the @actions@ method available on the @ResourceProxy@
49
+
50
+ <pre>
51
+ <code>
52
+ class Articles < Application
53
+ controlling :articles do |a|
54
+ a.actions :create, :update
55
+ end
56
+ end
57
+ </code>
58
+ </pre>
59
+
60
+
61
+ If you are using models that are nested inside some @module@ (maybe you're developing a @slice@ ?), you need to
62
+ provide the fully qualified class name to the @controlling@ method. Per default, @merb_resource_controller@ assumes
63
+ that you don't want to use the fully qualified name to generate your instance variables and association calls.
64
+
65
+ <pre>
66
+ <code>
67
+ class Ratings < Application
68
+ controlling "Community::Rating"
69
+ end
70
+ </code>
71
+ </pre>
72
+
73
+ This will initialize the instance variable @@ratings@ (or @@rating@ respectively). If this resource is nested below
74
+ another resource (see next section), this also means that the @:ratings@ (or @:rating@ respectively) association will
75
+ be used to navigate from the parent resource down to this resource.
76
+
77
+ If however, you want to use fully qualified names for your instance variables and association calls, you can explicitly
78
+ pass @:fully_qualified => true@ to the @controlling@ method (@false@ is the default).
79
+
80
+ <pre>
81
+ <code>
82
+ class Ratings < Application
83
+ controlling "Community::Rating", :fully_qualified => true
84
+ end
85
+ </code>
86
+ </pre>
87
+
88
+ This will initialize the instance variable @@community_ratings@ (or @@community_rating@ respectively). If this resource
89
+ is nested below another resource (see next section), this also means that the @:community_ratings@ (or
90
+ @:community_rating@ respectively) association will be used to navigate from the parent resource down to this resource.
91
+
92
+ h2. Nested Resources
93
+
94
+ @merb_resource_controller@ will automatically recognize if it is accessed from a toplevel or a nested url, and
95
+ will _adjust_ its actions accordingly. It will also initialize all the instance variables
96
+ you would expect for your chosen nesting strategy. This means, that when you have an URL like
97
+ @/articles/1/comments@, you will have an @@article@ variable pointing to @Article.get(1)@ and a @@comments@ variable
98
+ pointing to @Article.get(1).comments@.
99
+
100
+ It's important to note, that no database operations will be performed more than once!
101
+ So in the case of @/articles/1/comments/1/ratings@, @merb_resource_controller@ will do exactly what you would
102
+ expect it to do: It will issue @Article.get(1).comments.get(1).ratings@, initializing
103
+ @@article@, @@comment@ and @@ratings@ with the intermediate results on it's way down the association chain.
104
+
105
+ Speaking of an _association chain_, it is worth mentioning that it is by no means necessary that your
106
+ underlying models are connected via _real datamapper associations_ (like @has n, ...@ or @belongs_to@).
107
+ The only requirement is, that the object returned from a call to the nested _collection_ @respond_to?(:get)@
108
+ (in most cases it will be a @DataMapper::Collection@ anyway).
109
+
110
+
111
+ <pre>
112
+ </code>
113
+ class Comments < Application
114
+ controlling :comments do |c|
115
+ c.belongs_to :article
116
+ end
117
+ end
118
+
119
+ class Ratings < Application
120
+ controlling :ratings do |r|
121
+ r.belongs_to [ :article, :comment ]
122
+ end
123
+ end
124
+ </code>
125
+ </pre>
126
+
127
+ h2. Nested Singleton Resources
128
+
129
+ First of all, singleton resources (currently) must always be nested below at least one parent resource.
130
+
131
+ This is mostly because I somehow can't really imagine a usecase for a real toplevel singleton resource? I mean, there
132
+ must be _some_ information on _how_ to load that _one_ resource. Since we're mostly dealing with database backends here,
133
+ we should probably need some kind of _key_ to identify exactly _one_ dataset, but we don't get that _key_ from a resource
134
+ like @/profile@ (_where_ is the @:id@ param here?). So my guess is, that most of the toplevel singleton resources that
135
+ _are_ actually used, really are nested below some kind of resource that's stored in the @session@, most probably the
136
+ authenticated @user@ object. If this is the case, it would be perfectly valid, to just _really nest_ those singletons
137
+ below their real parent, and probably add a route alias to keep up the disguise. If you can come up with a usecase
138
+ where you have a real toplevel singleton resource that needs _no key_ to be loaded, just don't use
139
+ @merb_resource_controller@. Really, it's that simple! If however, I'm completely on the wrong track here, I would be glad
140
+ to be informed about it, so that I can fix things up.
141
+
142
+ The example code below behaves almost exactly like described in the section on _Nested Resources_ above. The only
143
+ two differences are, that 1) @no index action@ will be generated and that 2) the initialized instance variables will be
144
+ named @@article@ and @@editor@ if you have a singleton resource nested like @/articles/1/editor@. Just like you would
145
+ expect, no?
146
+
147
+ <pre>
148
+ <code>
149
+ class Editors < Application
150
+
151
+ controlling :editor, :singleton => true do |e|
152
+ e.belongs_to :article
153
+ end
154
+
155
+ end
156
+ </code>
157
+ </pre>
158
+
159
+ h2. DataMapper's Identity Map
160
+
161
+ Including @Merb::ResourceController::DM::IdentityMapSupport@ into any of your controller will wrap all actions
162
+ inside a dm repository block in order to be able to use DM's identitiy map feature. For more information on that topic,
163
+ have a look at "DataMapper's Identity Map":http://datamapper.org/doku.php?id=docs:identity_map
164
+
165
+ Feel free to include this module into _single_ controllers instead of including it into @Application@ controller, which
166
+ enables identity maps for _every_ controller action in your app.
167
+
168
+ <pre>
169
+ <code>
170
+ class Application < Merb::Controller
171
+ include Merb::ResourceController::DM::IdentityMapSupport
172
+ end
173
+ </code>
174
+ </pre>
175
+
176
+ h2. Action Timeouts
177
+
178
+ Extending @Merb::ResourceController::ActionTimeout@ into any of your controllers, will give you the @set_action_timeout@
179
+ method. If you specify an action_timeout greater or equal to @1@ and you have the @system_timer@ gem installed, the
180
+ action will timeout after the given amount of seconds. For a more detailed explanation on the topic have a look at
181
+ "Battling Wedged Mongrels with a Request Timeout":http://adam.blog.heroku.com/past/2008/6/17/battling_wedged_mongrels_with_a/
182
+
183
+ Feel free to set action timeouts for _single_ controllers instead of doing so in @Application@ controller, which sets
184
+ the same action timeout for _every_ controller action in your app.
185
+
186
+ <pre>
187
+ <code>
188
+ class Application < Merb::Controller
189
+ extend Merb::ResourceController::ActionTimeout
190
+ set_action_timeout 1
191
+ end
192
+ </code>
193
+ </pre>
194
+
195
+ h2. Defined Actions
196
+
197
+ All the above controllers will have the following actions defined. Feel free to override them, to customize
198
+ how the controllers behave. Of course you are also free to override all the methods used by these defined actions.
199
+
200
+ <pre>
201
+ <code>
202
+ def index
203
+ load_resource
204
+ display requested_resource
205
+ end
206
+
207
+ def show
208
+ load_resource
209
+ raise Merb::ControllerExceptions::NotFound unless requested_resource
210
+ display requested_resource
211
+ end
212
+
213
+ def new
214
+ only_provides :html
215
+ load_resource
216
+ set_member(new_member)
217
+ display member
218
+ end
219
+
220
+ def edit
221
+ only_provides :html
222
+ load_resource
223
+ raise Merb::ControllerExceptions::NotFound unless requested_resource
224
+ display requested_resource
225
+ end
226
+
227
+ def create
228
+ load_resource
229
+ set_member(new_member(params[member_name]))
230
+ if member.save
231
+ options = flash_supported? ? { :message => successful_create_messages } : {}
232
+ redirect redirect_on_successful_create, options
233
+ else
234
+ message.merge!(failed_create_messages) if flash_supported?
235
+ render :new
236
+ end
237
+ end
238
+
239
+ def update
240
+ load_resource
241
+ raise Merb::ControllerExceptions::NotFound unless requested_resource
242
+ if requested_resource.update_attributes(params[member_name])
243
+ options = flash_supported? ? { :message => successful_update_messages } : {}
244
+ redirect redirect_on_successful_update, options
245
+ else
246
+ message.merge!(failed_update_messages) if flash_supported?
247
+ display requested_resource, :edit
248
+ end
249
+ end
250
+
251
+ def destroy
252
+ load_resource
253
+ raise Merb::ControllerExceptions::NotFound unless requested_resource
254
+ if requested_resource.destroy
255
+ options = flash_supported? ? { :message => successful_destroy_messages } : {}
256
+ redirect redirect_on_successful_destroy, options
257
+ else
258
+ raise Merb::ControllerExceptions::InternalServerError
259
+ end
260
+ end
261
+ </code>
262
+ </pre>
263
+
264
+ h2. Additional Helper Methods
265
+
266
+ In addition to the actions and the methods they are using, you will probably want to override the redirection targets
267
+ These are the default method implementations you can override to this effect:
268
+
269
+ <pre>
270
+ <code>
271
+ def redirect_on_successful_create
272
+ target = singleton_controller? ? member_name : member
273
+ resource(*(has_parent? ? parents + [ target ] : [ target ]))
274
+ end
275
+
276
+ def redirect_on_successful_update
277
+ target = singleton_controller? ? member_name : member
278
+ resource(*(has_parent? ? parents + [ target ] : [ target ]))
279
+ end
280
+
281
+ def redirect_on_successful_destroy
282
+ if singleton_controller?
283
+ has_parent? ? resource(parent) : '/'
284
+ else
285
+ resource(*(has_parent? ? parents + [ collection_name ] : [ collection_name ]))
286
+ end
287
+ end
288
+ </code>
289
+ </pre>
290
+
291
+ h2. More Information
292
+
293
+ Have a look at @Merb::ResourceController::Actions@, @Merb::ResourceController::Mixin::InstanceMethods@ and
294
+ @Merb::ResourceController::Mixin::FlashSupport@ inside @lib/merb_resource_controller/actions.rb@ and
295
+ @lib/merb_resource_controller/resource_controller.rb@ to see what methods will be available inside your controllers.
296
+ If you want to see where the _real work gets done_, have a look at @lib/merb_resource_controller/resource_proxy.rb@
297
+
298
+ Of course, you should also have a look at the specs, to get a more concrete idea of how @merb_resource_controller@
299
+ behaves under the given circumstances.
300
+
301
+ h2. TODO
302
+
303
+ # Infer route nesting strategy from @Merb::Router@
304
+ # Customizable support for @provides@ and @only_provides@
305
+ # Support for user stamps (aka created_by and updated_by)
306
+ # Support for pagination once an _official_ merb pagination solution exists
data/Rakefile ADDED
@@ -0,0 +1,81 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+
4
+ require 'merb-core'
5
+ require 'merb-core/tasks/merb'
6
+ require "spec/rake/spectask"
7
+
8
+ GEM_NAME = "merb_resource_controller"
9
+ GEM_VERSION = "0.1.0"
10
+ AUTHOR = "Martin Gamsjaeger"
11
+ EMAIL = "gamsnjaga@gmail.com"
12
+ HOMEPAGE = "http://merbivore.com/"
13
+ SUMMARY = "A merb plugin that provides the default restful actions for controllers."
14
+
15
+ spec = Gem::Specification.new do |s|
16
+
17
+ s.rubyforge_project = 'merb_resource_controller'
18
+ s.name = GEM_NAME
19
+ s.version = GEM_VERSION
20
+ s.platform = Gem::Platform::RUBY
21
+ s.has_rdoc = false
22
+ s.extra_rdoc_files = [ "LICENSE", 'TODO']
23
+ s.summary = SUMMARY
24
+ s.description = s.summary
25
+ s.author = AUTHOR
26
+ s.email = EMAIL
27
+ s.homepage = HOMEPAGE
28
+ s.require_path = 'lib'
29
+
30
+ # be extra picky so that no coverage info and such gets included
31
+ s.files = %w(LICENSE README.textile Rakefile TODO) +
32
+ Dir.glob("{lib,spec}/**/*.rb") +
33
+ Dir.glob("{spec}/**") +
34
+ Dir.glob("{spec}/**/*.rb") +
35
+ Dir.glob("{spec}/**/*.yml") +
36
+ Dir.glob("{spec}/**/*.opts") +
37
+ Dir.glob("{spec}/**/*.html.erb") +
38
+ [ "spec/mrc_test_app/Rakefile"]
39
+
40
+ # runtime dependencies
41
+ s.add_dependency('merb-core', '~> 1.0')
42
+
43
+ # development dependencies
44
+ # if these are desired, install with:
45
+ # gem install merb_resource_controller --development
46
+ s.add_development_dependency('merb-assets', '~>1.0')
47
+ s.add_development_dependency('merb-helpers', '~>1.0')
48
+ s.add_development_dependency('dm-core', '~>0.9.8')
49
+ s.add_development_dependency('dm-validations', '~>0.9.8')
50
+ s.add_development_dependency('dm-serializer', '~>0.9.8')
51
+ s.add_development_dependency('dm-constraints', '~>0.9.8')
52
+
53
+ end
54
+
55
+ Rake::GemPackageTask.new(spec) do |pkg|
56
+ pkg.gem_spec = spec
57
+ end
58
+
59
+ desc "install the plugin as a gem"
60
+ task :install do
61
+ Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
62
+ end
63
+
64
+ desc "Uninstall the gem"
65
+ task :uninstall do
66
+ Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
67
+ end
68
+
69
+ desc "Create a gemspec file"
70
+ task :gemspec do
71
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
72
+ file.puts spec.to_ruby
73
+ end
74
+ end
75
+
76
+ desc 'Default: run spec examples'
77
+ task :spec do
78
+ puts "!!! README !!! Run 'rake spec' from the './spec/mrc_test_app' directory to run all specs for merb_resource_controller."
79
+ end
80
+
81
+ task :default => 'spec'
data/TODO ADDED
@@ -0,0 +1,7 @@
1
+ TODO
2
+ ====
3
+
4
+ # Infer route nesting strategy from @Merb::Router@
5
+ # Customizable support for @provides@ and @only_provides@
6
+ # Support for user stamps (aka created_by and updated_by)
7
+ # Support for pagination once an _official_ merb pagination solution exists
@@ -0,0 +1,53 @@
1
+ require 'system_timer'
2
+
3
+ module Merb
4
+ module ResourceController
5
+
6
+ # To be extended into controllers
7
+ module ActionTimeout
8
+
9
+ def self.for?(controller)
10
+ self.for(controller) > 0
11
+ end
12
+
13
+ def self.for(controller)
14
+ (@controllers ||= {})[Application] || @controllers[controller] || 0
15
+ end
16
+
17
+ def self.register(controller, seconds)
18
+ (@controllers ||= {})[controller] = seconds
19
+ end
20
+
21
+
22
+ def set_action_timeout(seconds)
23
+ if seconds >= 1
24
+ ActionTimeout.register(self, seconds)
25
+ include InstanceMethods
26
+ end
27
+ end
28
+
29
+ module InstanceMethods
30
+
31
+ # taken from:
32
+ # http://datamapper.org/doku.php?id=docs:identity_map
33
+ def _call_action(*args)
34
+ if Merb::Plugins.config[:merb_resource_controller][:action_timeout]
35
+ return super unless ActionTimeout.for?(self.class)
36
+ timeout = ActionTimeout.for(self.class)
37
+ Merb.logger.info "SystemTimer.timeout for #{args[0]}: #{timeout} seconds"
38
+ # more information on system_timer:
39
+ # http://adam.blog.heroku.com/past/2008/6/17/battling_wedged_mongrels_with_a/
40
+ SystemTimer.timeout(timeout) do
41
+ super
42
+ end
43
+ else
44
+ super
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,169 @@
1
+ module Merb
2
+ module ResourceController
3
+
4
+ module Actions
5
+
6
+ module Index
7
+
8
+ # def index
9
+ # @articles = Article.all
10
+ # display @articles
11
+ # end
12
+
13
+ def index
14
+ load_resource
15
+ display requested_resource
16
+ end
17
+
18
+ end
19
+
20
+ module Show
21
+
22
+ # def show(id)
23
+ # @article = Article.get(id)
24
+ # raise NotFound unless @article
25
+ # display @article
26
+ # end
27
+
28
+ def show
29
+ load_resource
30
+ raise Merb::ControllerExceptions::NotFound unless requested_resource
31
+ display requested_resource
32
+ end
33
+
34
+ end
35
+
36
+ module New
37
+
38
+ # def new
39
+ # only_provides :html
40
+ # @article = Article.new
41
+ # display @article
42
+ # end
43
+
44
+ def new
45
+ only_provides :html
46
+ load_resource
47
+ set_member(new_member)
48
+ display member
49
+ end
50
+
51
+ end
52
+
53
+ module Edit
54
+
55
+ # def edit(id)
56
+ # only_provides :html
57
+ # @article = Article.get(id)
58
+ # raise NotFound unless @article
59
+ # display @article
60
+ # end
61
+
62
+ def edit
63
+ only_provides :html
64
+ load_resource
65
+ raise Merb::ControllerExceptions::NotFound unless requested_resource
66
+ display requested_resource
67
+ end
68
+
69
+ end
70
+
71
+ module Create
72
+
73
+ # def create(article)
74
+ # @article = Article.new(article)
75
+ # if @article.save
76
+ # redirect resource(@article), :message => { :notice => "Article was successfully created" }
77
+ # else
78
+ # message[:error] = "Article failed to be created"
79
+ # render :new
80
+ # end
81
+ # end
82
+
83
+ def create
84
+ load_resource
85
+ set_member(new_member)
86
+ if member.save
87
+ options = flash_supported? ? { :message => successful_create_messages } : {}
88
+ redirect redirect_on_successful_create, options
89
+ else
90
+ message.merge!(failed_create_messages) if flash_supported?
91
+ render :new, :status => 406
92
+ end
93
+ end
94
+
95
+ def redirect_on_successful_create
96
+ target = singleton_controller? ? member_name : member
97
+ resource(*(has_parent? ? parents + [ target ] : [ target ]))
98
+ end
99
+
100
+ end
101
+
102
+ module Update
103
+
104
+ # def update(id, article)
105
+ # @article = Article.get(id)
106
+ # raise NotFound unless @article
107
+ # if @article.update_attributes(article)
108
+ # redirect resource(@article), :message => { :notice => "Article was successfully updated" }
109
+ # else
110
+ # display @article, :edit
111
+ # end
112
+ # end
113
+
114
+ def update
115
+ load_resource
116
+ raise Merb::ControllerExceptions::NotFound unless requested_resource
117
+ if requested_resource.update_attributes(params[member_name])
118
+ options = flash_supported? ? { :message => successful_update_messages } : {}
119
+ redirect redirect_on_successful_update, options
120
+ else
121
+ message.merge!(failed_update_messages) if flash_supported?
122
+ display requested_resource, :edit, :status => 406
123
+ end
124
+ end
125
+
126
+ def redirect_on_successful_update
127
+ target = singleton_controller? ? member_name : member
128
+ resource(*(has_parent? ? parents + [ target ] : [ target ]))
129
+ end
130
+
131
+ end
132
+
133
+ module Destroy
134
+
135
+ # def destroy(id)
136
+ # @article = Article.get(id)
137
+ # raise NotFound unless @article
138
+ # if @article.destroy
139
+ # redirect resource(:articles)
140
+ # else
141
+ # raise InternalServerError
142
+ # end
143
+ # end
144
+
145
+ def destroy
146
+ load_resource
147
+ raise Merb::ControllerExceptions::NotFound unless requested_resource
148
+ if requested_resource.destroy
149
+ options = flash_supported? ? { :message => successful_destroy_messages } : {}
150
+ redirect redirect_on_successful_destroy, options
151
+ else
152
+ raise Merb::ControllerExceptions::InternalServerError
153
+ end
154
+ end
155
+
156
+ def redirect_on_successful_destroy
157
+ if singleton_controller?
158
+ has_parent? ? resource(parent) : '/'
159
+ else
160
+ resource(*(has_parent? ? parents + [ collection_name ] : [ collection_name ]))
161
+ end
162
+ end
163
+
164
+ end
165
+
166
+ end
167
+
168
+ end
169
+ end
@@ -0,0 +1,20 @@
1
+ module Merb
2
+ module ResourceController
3
+ module DM
4
+
5
+ # include this into controllers
6
+ module IdentityMapSupport
7
+
8
+ # taken from:
9
+ # http://datamapper.org/doku.php?id=docs:identity_map
10
+ def _call_action(*)
11
+ repository do |r| # enable identity_map
12
+ Merb.logger.info "Using DM Identity map inside #{r.name} repository block"
13
+ super
14
+ end
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end