hookercookerman-merb-resource-scope 0.1.0
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.
- data/LICENSE +20 -0
- data/README.textile +297 -0
- data/Rakefile +82 -0
- data/TODO +3 -0
- data/lib/dependencies.rb +1 -0
- data/lib/merb-resource-scope.rb +25 -0
- data/lib/merb-resource-scope/controller/actions.rb +67 -0
- data/lib/merb-resource-scope/controller/helpers.rb +252 -0
- data/lib/merb-resource-scope/controller/scoped_resource_mixin.rb +300 -0
- data/lib/merb-resource-scope/controller/singleton_actions.rb +25 -0
- data/lib/merb-resource-scope/merbtasks.rb +6 -0
- data/lib/merb-resource-scope/router/resource_specification.rb +144 -0
- data/lib/merb-resource-scope/specification.rb +36 -0
- data/spec/app.rb +7 -0
- data/spec/controller/_build_enclosing_scope_spec.rb +107 -0
- data/spec/controller/scope_resource_mixin_spec.rb +0 -0
- data/spec/integration/admin_posts_controller_spec.rb +158 -0
- data/spec/integration/campaign_post_comments_controller_spec.rb +158 -0
- data/spec/integration/campaign_posts_controller_spec.rb +73 -0
- data/spec/integration/campaigns_controller_spec.rb +43 -0
- data/spec/integration/images_spec.rb +17 -0
- data/spec/integration/myhome_controller_spec.rb +29 -0
- data/spec/integration/myhome_posts_comment_controller_spec.rb +44 -0
- data/spec/integration/myhome_posts_controller_spec.rb +55 -0
- data/spec/integration/profile_images_controller_spec.rb +61 -0
- data/spec/integration/tags_controller_spec.rb +34 -0
- data/spec/integration/user_posts_controller_spec.rb +71 -0
- data/spec/request_with_controller.rb +103 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/specification_spec.rb +1 -0
- metadata +88 -0
@@ -0,0 +1,252 @@
|
|
1
|
+
module MerbResourceScope
|
2
|
+
module Controller
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
class UrlGenerator
|
6
|
+
attr_accessor :resources, :name_prefixes, :resources_with_specs, :named_route
|
7
|
+
|
8
|
+
def initialize(name_prefixes, resources_with_specs, &block)
|
9
|
+
@resources = []
|
10
|
+
@name_prefixes, @resources_with_specs = name_prefixes, resources_with_specs
|
11
|
+
yield self if block_given?
|
12
|
+
@named_route = generate_named_route
|
13
|
+
end
|
14
|
+
|
15
|
+
# this is so we can extend out current name_route
|
16
|
+
# will be used in congunction of the url helpers
|
17
|
+
# enclosing_resource_url{|route| route.add(:comments)}
|
18
|
+
#
|
19
|
+
# @param args<VarArgs> : this takes 3 parameter really, first one
|
20
|
+
# is a symbol of the named_route you want to add, so lets
|
21
|
+
# say we had enclosing_resource_url of /users/1/
|
22
|
+
# and we wanted to add tags on to this url we can simple
|
23
|
+
# enclosing_resource_url{|route| route.add(:tags)}
|
24
|
+
# and this will be /users/1/tags
|
25
|
+
# You can also add custom routes as well then as well
|
26
|
+
# add(:tags, :pending)
|
27
|
+
# Also add a resource as well, add(:tag, @tag)
|
28
|
+
# Also do a new this way as well add(:tag, :new)
|
29
|
+
# And finally add(:tag, :edit, @tag) Where the @tag
|
30
|
+
# has to be the last option
|
31
|
+
#
|
32
|
+
# @examples
|
33
|
+
# enclosing_resource_url{|route| route.add(:comments)}
|
34
|
+
# resource_url(current_resource){|route| route.add(:tag, @tag)}
|
35
|
+
# enclosing_resource_url{|route| route.add(:post, :edit, @post)}
|
36
|
+
#
|
37
|
+
#
|
38
|
+
def add(*args)
|
39
|
+
name_prefixes.flatten!
|
40
|
+
name_prefixes << args.shift
|
41
|
+
args.each do |arg|
|
42
|
+
if arg.is_a?(Symbol)
|
43
|
+
name_prefixes.unshift(arg.to_s)
|
44
|
+
else
|
45
|
+
resources << arg
|
46
|
+
end
|
47
|
+
end
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
alias_method :with, :add
|
52
|
+
|
53
|
+
def generate_named_route
|
54
|
+
if resources_with_specs
|
55
|
+
none_singletons = resources_with_specs.reject{|rs| rs[1].singleton}
|
56
|
+
resources << none_singletons.map{|rs| rs[0]}
|
57
|
+
end
|
58
|
+
generated_named_route = name_prefixes.flatten.compact.join('_').intern
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# TODO tidy refactor these methods pretty please
|
63
|
+
# if you want the current resources url then use this method its the way forward
|
64
|
+
# url is generated from building up a named route and then parsing the named
|
65
|
+
# route to the url method, so remember this url is buit using named routes!!
|
66
|
+
#
|
67
|
+
# so if we have a path of /users/1/posts/2
|
68
|
+
# the current_resources_url would be /users/1/posts
|
69
|
+
# remeber the url generated will be already scoped
|
70
|
+
# You can pass a custom route to generate a custom route
|
71
|
+
# and the params just like the url method
|
72
|
+
#
|
73
|
+
# @example
|
74
|
+
# current_resources_url(:pending, {:q => "cool"})
|
75
|
+
# current_resources_url(:notpending, {:lots => "yes", :lot => "ofparams"})
|
76
|
+
# current_resources_url
|
77
|
+
#
|
78
|
+
#
|
79
|
+
# @param<*args> : pass in a list of custom named routes, and param hash
|
80
|
+
#
|
81
|
+
# @return<String> : the generate url
|
82
|
+
def current_resources_url(*args, &block)
|
83
|
+
options = extract_options_from_args!(args) || {}
|
84
|
+
name_prefixes = []
|
85
|
+
name_prefixes << _current_specification.name_prefix
|
86
|
+
name_prefixes << Extlib::Inflection.pluralize(_current_specification.resource_name)
|
87
|
+
name_prefixes.unshift(args)
|
88
|
+
generator = UrlGenerator.new(name_prefixes, _enclosing_resources_with_spec, &block)
|
89
|
+
url(generator.named_route, *[generator.resources, options].flatten)
|
90
|
+
end
|
91
|
+
alias_method :resources_url, :current_resources_url
|
92
|
+
|
93
|
+
|
94
|
+
# generates a new resource url that is automatically scoped where you are
|
95
|
+
#
|
96
|
+
#
|
97
|
+
# lets just say we were at this url users/1/posts
|
98
|
+
# by using new_current_resource_url we would basically generate
|
99
|
+
# new_user_post named route
|
100
|
+
# which inturn would generate /users/1/posts/new
|
101
|
+
#
|
102
|
+
#
|
103
|
+
# @example
|
104
|
+
# new_current_resource_url({:awantaparam=> "yesyoucan"})
|
105
|
+
# new_current_resource_url
|
106
|
+
#
|
107
|
+
#
|
108
|
+
# @param options<Hash> : Pass in a hash of params
|
109
|
+
#
|
110
|
+
# @return<String> : the generate url
|
111
|
+
def new_current_resource_url(options = {}, &block)
|
112
|
+
name_prefixes = []
|
113
|
+
name_prefixes << _current_specification.name_prefix
|
114
|
+
name_prefixes << _current_specification.resource_name
|
115
|
+
name_prefixes.unshift("new")
|
116
|
+
generator = UrlGenerator.new(name_prefixes, _enclosing_resources_with_spec, &block)
|
117
|
+
url(generator.named_route, *[generator.resources, options].flatten)
|
118
|
+
end
|
119
|
+
alias_method :new_resource_url, :new_current_resource_url
|
120
|
+
|
121
|
+
|
122
|
+
# generates the current_resource_url cool
|
123
|
+
#
|
124
|
+
#
|
125
|
+
# lets just say we were at this url users/1/posts/1
|
126
|
+
# then via to using the current_resource_url we would do
|
127
|
+
# current_resource_url(@post) for singleton resources
|
128
|
+
# just pass in the resource_name ie. for /myhome/proile_image
|
129
|
+
# we would have current_resource_url(:myhome)
|
130
|
+
#
|
131
|
+
#
|
132
|
+
# @example
|
133
|
+
# current_resource_url(@post)
|
134
|
+
# current_resource_url(@post, :my => "params")
|
135
|
+
# current_resource_url(:myhome)
|
136
|
+
#
|
137
|
+
# @param options<Hash> : Pass in a hash of params
|
138
|
+
#
|
139
|
+
# @return<String> : the generate url
|
140
|
+
def current_resource_url(current_resource, *args, &block)
|
141
|
+
name_prefixes = []
|
142
|
+
options = extract_options_from_args!(args) || {}
|
143
|
+
resource_specs = _resources_with_specs.dup
|
144
|
+
name_prefixes << _current_specification.name_prefix
|
145
|
+
unless current_resource.is_a?(Symbol) && _current_specification.singleton
|
146
|
+
resource_specs << [current_resource, _current_specification]
|
147
|
+
name_prefixes << _current_specification.resource_name
|
148
|
+
else
|
149
|
+
name_prefixes << current_resource
|
150
|
+
end
|
151
|
+
name_prefixes.unshift(args)
|
152
|
+
generator = UrlGenerator.new(name_prefixes, resource_specs, &block)
|
153
|
+
url(generator.named_route, *[generator.resources, options].flatten)
|
154
|
+
end
|
155
|
+
alias_method :resource_url, :current_resource_url
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
# generates the enclosing_resource_url cool
|
160
|
+
#
|
161
|
+
#
|
162
|
+
# lets just say we were at this url users/1/posts/1
|
163
|
+
# then via to using the current_resource_url we would do
|
164
|
+
# current_resource_url(@post) for singleton resources
|
165
|
+
# just pass in the resource_name ie. for /myhome/proile_image
|
166
|
+
# we would have current_resource_url(:myhome)
|
167
|
+
#
|
168
|
+
#
|
169
|
+
# @example
|
170
|
+
# enclosing_resource_url(:edit)
|
171
|
+
# enclosing_resource_url(:edit, :my => "param")
|
172
|
+
# enclosing_resource_url(:whatever)
|
173
|
+
# enclosing_resource_url(:my => "params")
|
174
|
+
# enclosing_resource_url(:myhome)
|
175
|
+
#
|
176
|
+
# @param args<Var> : Pass in custom route, then params basically
|
177
|
+
#
|
178
|
+
# @return<String> : the generate url
|
179
|
+
def enclosing_resource_url(*args, &block)
|
180
|
+
if _enclosing_specification
|
181
|
+
options = extract_options_from_args!(args) || {}
|
182
|
+
name_prefixes = []
|
183
|
+
name_prefixes << _enclosing_specification.name_prefix
|
184
|
+
name_prefixes << _enclosing_specification.resource_name
|
185
|
+
name_prefixes.unshift(args)
|
186
|
+
generator = UrlGenerator.new(name_prefixes, _resources_with_specs, &block)
|
187
|
+
url(generator.named_route, *[generator.resources, options].flatten)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
# generates the enclosing_resources_url cool
|
193
|
+
#
|
194
|
+
#
|
195
|
+
# lets just say we were at this url users/1/posts/1
|
196
|
+
# then via to using the enclosing_resources_url
|
197
|
+
# we would get the url of /users
|
198
|
+
# which inturn would be using :users named_route
|
199
|
+
#
|
200
|
+
#
|
201
|
+
# @example
|
202
|
+
# enclosing_resources_url
|
203
|
+
# enclosing_resources_url(:pending)
|
204
|
+
# enclosing_resources_url(:pending, :my => "param")
|
205
|
+
# @param args<Var> : Pass in custom route, then params basically
|
206
|
+
#
|
207
|
+
# @return<String> : the generate url
|
208
|
+
def enclosing_resources_url(*args, &block)
|
209
|
+
if _enclosing_specification
|
210
|
+
options = extract_options_from_args!(args) || {}
|
211
|
+
name_prefixes = []
|
212
|
+
name_prefixes << _enclosing_specification.name_prefix
|
213
|
+
name_prefixes << Extlib::Inflection.pluralize(_enclosing_specification.resource_name)
|
214
|
+
name_prefixes.unshift(args)
|
215
|
+
generator = UrlGenerator.new(name_prefixes, _enclosing_resources_with_spec, &block)
|
216
|
+
url(generator.named_route, *[generator.resources, options].flatten)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# generates the new_enclosing_resource_url cool
|
221
|
+
#
|
222
|
+
#
|
223
|
+
# lets just say we were at this url users/1/posts/1
|
224
|
+
# then via to using the new_enclosing_resource_url
|
225
|
+
# we would get the url of /users/new
|
226
|
+
# which inturn would be using :new_user named_route
|
227
|
+
#
|
228
|
+
#
|
229
|
+
# @example
|
230
|
+
# new_enclosing_resource_url(:edit)
|
231
|
+
# new_enclosing_resource_url(:edit, :my => "param")
|
232
|
+
# new_enclosing_resource_url(:whatever)
|
233
|
+
# new_enclosing_resource_url(:my => "params")
|
234
|
+
# new_enclosing_resource_url(:myhome)
|
235
|
+
#
|
236
|
+
# @param args<Var> : Pass in custom route, then params basically
|
237
|
+
#
|
238
|
+
# @return<String> : the generate url
|
239
|
+
def new_enclosing_resource_url(options = {}, &block)
|
240
|
+
if _enclosing_specification
|
241
|
+
name_prefixes = []
|
242
|
+
name_prefixes << _enclosing_specification.name_prefix
|
243
|
+
name_prefixes << _enclosing_specification.resource_name
|
244
|
+
name_prefixes.unshift("new")
|
245
|
+
generator = UrlGenerator.new(name_prefixes, _enclosing_resources_with_spec, &block)
|
246
|
+
url(generator.named_route, *[generator.resources, options].flatten)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
@@ -0,0 +1,300 @@
|
|
1
|
+
module MerbResourceScope
|
2
|
+
module Controller
|
3
|
+
|
4
|
+
module ScopedResourceMixin
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
attr_accessor :_enclosing_scope, :_enclosing_specifications, :_resources_with_specs, :_enclosing_resources_with_spec, :_current_specification, :_enclosing_specification
|
8
|
+
attr_accessor :current_resources, :current_resource, :resource_scope
|
9
|
+
extend ScopedResourceMixin::ClassMethods
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def build_resource_scope(options = {})
|
15
|
+
include InstanceMethods
|
16
|
+
options.only(:build_scope, :singleton, :actions)
|
17
|
+
filter_options = options.delete(:build_scope)
|
18
|
+
add_filter(_before_filters, :_build_resource_scope, filter_options || {})
|
19
|
+
|
20
|
+
unless options[:actions] == false
|
21
|
+
actions ||= options[:singleton] ? Merb::Plugins.config[:merb_resource_scope][:singleton_actions] : Merb::Plugins.config[:merb_resource_scope][:actions]
|
22
|
+
include_actions actions, options.delete(:actions) || {}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
# we only want to include actions that we want!
|
28
|
+
def include_actions(mixin, options = {})
|
29
|
+
mixin = mixin.dup
|
30
|
+
if only = options[:only]
|
31
|
+
only = Array(options[:only])
|
32
|
+
mixin.instance_methods.each {|m| mixin.send(:undef_method, m) unless only.include?(m.intern)}
|
33
|
+
elsif except = options[:exclude]
|
34
|
+
except = Array(options[:exclude])
|
35
|
+
mixin.instance_methods.each {|m| mixin.send(:undef_method, m) if except.include?(m.intern)}
|
36
|
+
end
|
37
|
+
include mixin
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Proxy class to provide a consistent API for resource_scope. passing all method calls
|
42
|
+
# to the current_scope
|
43
|
+
class ResourceScope
|
44
|
+
instance_methods.each { |m| undef_method m unless %w[ __id__ __send__ class kind_of? respond_to? should should_not instance_variable_set instance_variable_get instance_eval].include?(m) }
|
45
|
+
attr_reader :controller
|
46
|
+
|
47
|
+
def initialize(controller)
|
48
|
+
@controller = controller
|
49
|
+
end
|
50
|
+
|
51
|
+
def _enclosing_resource
|
52
|
+
@_enclosing_resource ||= controller.enclosing_resource
|
53
|
+
end
|
54
|
+
|
55
|
+
def _current_specification
|
56
|
+
@_current_specification ||= controller._current_specification
|
57
|
+
end
|
58
|
+
|
59
|
+
def respond_to?(method)
|
60
|
+
super || current_scope.respond_to?(method)
|
61
|
+
end
|
62
|
+
|
63
|
+
def current_scope
|
64
|
+
@current_scope ||= _enclosing_resource ? _enclosing_resource.send(_current_specification.association_method) : _current_specification.klass
|
65
|
+
end
|
66
|
+
|
67
|
+
def method_missing(method, *args, &block)
|
68
|
+
if current_scope.respond_to?(method)
|
69
|
+
current_scope.send(method, *args, &block)
|
70
|
+
else
|
71
|
+
super
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module InstanceMethods
|
77
|
+
|
78
|
+
# the before filter, when this before filter is run; it will build the resource_scope
|
79
|
+
def _build_resource_scope
|
80
|
+
if specifications = request.resource_specifications
|
81
|
+
@_current_specification = specifications.pop
|
82
|
+
@_enclosing_specifications = specifications
|
83
|
+
@_resources_with_specs = []
|
84
|
+
|
85
|
+
# if we dont want to load all the enclosing resource and resources
|
86
|
+
# we can specify a depth to which build the the scope from
|
87
|
+
if scope_depth = @_current_specification.scope_depth
|
88
|
+
@_enclosing_specifications.slice!(0..scope_depth-1)
|
89
|
+
end
|
90
|
+
|
91
|
+
_generate_enclosing_scope
|
92
|
+
@resource_scope ||= MerbResourceScope::Controller::ScopedResourceMixin::ResourceScope.new(self)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def enclosing_resource
|
97
|
+
return nil if @_enclosing_specifications.size == 0
|
98
|
+
if @_resources_with_specs.size == @_enclosing_specifications.size+1
|
99
|
+
@_resources_with_specs.slice(-2)[0]
|
100
|
+
else
|
101
|
+
@_resources_with_specs.last && @_resources_with_specs.last[0]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# When we find the current_resource we want its resource with its specification
|
106
|
+
# to be added; essentially so we can know what the correct enclosing resource is
|
107
|
+
# but we dont want to add it if its a new_record as its not a resource just yet
|
108
|
+
# TODO need looking AT basically!! as create and destroy actions show not hold
|
109
|
+
# the resource OR put into the resource as they are essentiall not correct
|
110
|
+
# as it should be current_resource_url(@new_resource) Basically YEAH!
|
111
|
+
|
112
|
+
# if you want to find resources in another way just override this in your
|
113
|
+
# controller;
|
114
|
+
#
|
115
|
+
# @example
|
116
|
+
# def find_resources
|
117
|
+
# @resource_scope.all :conditions => {:pending => true}
|
118
|
+
# end
|
119
|
+
#
|
120
|
+
# @api overwritable
|
121
|
+
def find_resources
|
122
|
+
@resource_scope.all
|
123
|
+
end
|
124
|
+
|
125
|
+
# if you want to find a resource in another then this default way
|
126
|
+
# then you can override in the controller,
|
127
|
+
#
|
128
|
+
# @example
|
129
|
+
# def find_resource
|
130
|
+
# @resource_scope.first :conditions => {:user_id => 1, :pending => false}
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# @param id<String>|<Integer> the params to use to find a resource could be permalink
|
134
|
+
#
|
135
|
+
# @api overwritable
|
136
|
+
def find_resource(id = params[@_current_specification.permalink])
|
137
|
+
if find_method = @_current_specification.find_method
|
138
|
+
find_method.is_a?(Proc) ? self.instance_eval(&find_method) : self.send(find_method)
|
139
|
+
else
|
140
|
+
@_current_specification.singleton ? @resource_scope : @resource_scope.first(:conditions => {@_current_specification.permalink => id})
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# if you have other requirments on how you would like to create a new resource
|
145
|
+
# then you can override this at the controller level, using the @resource_scope
|
146
|
+
# Also if you wish to have different attributes set you can just add them as well
|
147
|
+
# dont really want to go into it but I cannot use the proxy here as a send then a
|
148
|
+
# method call basically stops the dependent attributes from being set! strange but
|
149
|
+
# true
|
150
|
+
# @example
|
151
|
+
# def new_resource
|
152
|
+
# @resource_scope.different_new {:whatever => :egg}
|
153
|
+
# end
|
154
|
+
#
|
155
|
+
# @api overwritable
|
156
|
+
def new_resource(attributes = (params[@_current_specification.resource_name] || {}))
|
157
|
+
if enclosing_resource
|
158
|
+
if @_current_specification.singleton
|
159
|
+
return @_current_specification.klass.new attributes.merge!(_enclosing_specification.association_method.to_sym => enclosing_resource)
|
160
|
+
end
|
161
|
+
enclosing_resource.send(@_current_specification.association_method).build attributes
|
162
|
+
else
|
163
|
+
@_current_specification.klass.new attributes
|
164
|
+
end
|
165
|
+
end
|
166
|
+
#
|
167
|
+
# we set the current_resource to have the current specification resource_name method
|
168
|
+
def current_resource=(resource)
|
169
|
+
instance_variable_set("@#{@_current_specification.resource_name}", resource)
|
170
|
+
@current_resource = resource
|
171
|
+
end
|
172
|
+
|
173
|
+
# we set the current_resource to have the current specification resource_name method
|
174
|
+
def current_resources=(resources)
|
175
|
+
instance_variable_set("@#{@_current_specification.association_method}", resources)
|
176
|
+
@current_resources = resources
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
# this is the work horse of how the enclosing_scope is built,
|
181
|
+
# it will use all the enclosing enclosing_specifications to work out what the
|
182
|
+
# enclosing scope is.
|
183
|
+
#
|
184
|
+
# On its first run it will determine whether
|
185
|
+
# it should just use the singleton method or the find_method of the specification,
|
186
|
+
# or just go with the standand User.get(params[:id])
|
187
|
+
#
|
188
|
+
# Futher iterations will just try to find the resource via method calls
|
189
|
+
# and if the key of the specification is in the params then that resource
|
190
|
+
# will also be found
|
191
|
+
#
|
192
|
+
# so for a typical url say users/1/posts/1/comments
|
193
|
+
# it would go something like this, setting the enclosing_scope as it goes
|
194
|
+
# 1. enclosing_scope = User - via enclosing_specifications.first.klass_name
|
195
|
+
# 2. enclosing_scope = User.get(params[:user_id]) - via collect_resource_via_params(@enclosing_scope, specification)
|
196
|
+
# 3. enclosing_scope = User.get(params[:user_id]).posts.get(params[:post_id]) - via collect_resource_via_params(@enclosing_scope, specification)
|
197
|
+
# 4. thats it! now our enclosing_scope is where we want it
|
198
|
+
#
|
199
|
+
# This will also handle enclosing depth witch can default to the number of
|
200
|
+
# enclosing specification but can get it from current
|
201
|
+
# specification and if its been set to say 1 then my inclosing_specifications
|
202
|
+
# will only be set to just that COOL
|
203
|
+
def _generate_enclosing_scope
|
204
|
+
@_enclosing_specifications.each_with_index do |specification, index|
|
205
|
+
if specification.singleton || specification.find_method
|
206
|
+
@_enclosing_scope = _collect_resource_via_method(@_enclosing_scope, specification)
|
207
|
+
else
|
208
|
+
@_enclosing_scope = _collect_resource_via_params(@_enclosing_scope, specification)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# collect a resource either with the specification.find_method or the association method
|
214
|
+
# we also want to store the found resource or resources along with the specification
|
215
|
+
# that was used to find them for later use; mainly in route generation
|
216
|
+
#
|
217
|
+
# @param enclosing_scope<Object>|<Objects> aka ur orm object
|
218
|
+
# @param specification<Specification>
|
219
|
+
#
|
220
|
+
# @return <Object>|<Objects> aka ur orm object
|
221
|
+
def _collect_resource_via_method(enclosing_scope, specification)
|
222
|
+
if specification.find_method
|
223
|
+
return _collect_resource_via_find_method(specification)
|
224
|
+
else
|
225
|
+
resource_or_resources = enclosing_scope.send(specification.association_method)
|
226
|
+
@_resources_with_specs << [resource_or_resources, specification]
|
227
|
+
instance_variable_set("@#{specification.association_method}", resource_or_resources)
|
228
|
+
end
|
229
|
+
resource_or_resources
|
230
|
+
end
|
231
|
+
|
232
|
+
|
233
|
+
# collect a resource either with the specification.find_method
|
234
|
+
# we also want to store the found resource or resources along with the specification
|
235
|
+
# that was used to find them for later use; mainly in route generation and to find
|
236
|
+
# enclosing resources or resource
|
237
|
+
#
|
238
|
+
# @param specification<Specification>
|
239
|
+
#
|
240
|
+
# @return <Object>|<Objects> aka ur orm object
|
241
|
+
def _collect_resource_via_find_method(specification)
|
242
|
+
resource_or_resources = if specification.find_method.is_a?(Proc)
|
243
|
+
self.instance_eval(&specification.find_method)
|
244
|
+
else
|
245
|
+
self.send(specification.find_method)
|
246
|
+
end
|
247
|
+
|
248
|
+
unless _resource_is_a_collection?(specification, resource_or_resources)
|
249
|
+
@_resources_with_specs << [resource_or_resources, specification]
|
250
|
+
instance_variable_set("@#{specification.resource_name}", resource_or_resources)
|
251
|
+
end
|
252
|
+
|
253
|
+
resource_or_resources
|
254
|
+
end
|
255
|
+
|
256
|
+
# collect a resource with the specification using the params and the resource_name
|
257
|
+
# we also want to store the found resource along with the specification
|
258
|
+
#
|
259
|
+
# @param enclosing_scope<Object>|<Objects> aka ur orm object
|
260
|
+
# @param specification<Specification>
|
261
|
+
#
|
262
|
+
# @return <Object>|<Objects>|enclosing_scope aka ur orm object
|
263
|
+
def _collect_resource_via_params(enclosing_scope, specification)
|
264
|
+
if !params.keys.include?(specification.foreign_key.to_s)
|
265
|
+
return enclosing_scope
|
266
|
+
else
|
267
|
+
|
268
|
+
resource = if enclosing_scope
|
269
|
+
enclosing_scope.send(specification.association_method).first(:conditions => {specification.permalink => params[specification.foreign_key]})
|
270
|
+
else
|
271
|
+
specification.klass.first(:conditions => {specification.permalink => params[specification.foreign_key]})
|
272
|
+
end
|
273
|
+
|
274
|
+
@_resources_with_specs << [resource, specification]
|
275
|
+
instance_variable_set("@#{specification.resource_name}", resource)
|
276
|
+
resource
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
# This is by default set to use datamapper
|
281
|
+
# You can override this at the application controller level
|
282
|
+
# then it will use this for all controllers; or if you have
|
283
|
+
# specific requirement on a controller;then just change it in there
|
284
|
+
#
|
285
|
+
# @api overwritable
|
286
|
+
def _resource_is_a_collection?(specification, resource_or_resources)
|
287
|
+
resource_or_resources.kind_of?(::DataMapper::Collection)
|
288
|
+
end
|
289
|
+
|
290
|
+
def _enclosing_resources_with_specs
|
291
|
+
@_resources_with_specs.slice(0..-2)
|
292
|
+
end
|
293
|
+
|
294
|
+
def _enclosing_specification
|
295
|
+
@_enclosing_specifications.last
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|