Module: Remotable::ActiveRecordExtender::ClassMethods
- Includes:
- Nosync
- Defined in:
- lib/remotable/active_record_extender.rb
Instance Attribute Summary collapse
Instance Method Summary
collapse
-
#attr_remote(*attrs) ⇒ Object
-
#default_route_for(local_key, remote_key = nil) ⇒ Object
-
#expire_all! ⇒ Object
-
#expires_after(*args) ⇒ Object
-
#fetch_by(remote_attr, *values) ⇒ Object
Looks the resource up remotely, by the given attribute If the resource is found, wraps it in a new local resource and returns that.
-
#fetch_with(local_key, options = {}) ⇒ Object
(also: #find_by)
-
#find_remote_resource_by(remote_attr, *values) ⇒ Object
Looks the resource up remotely; Returns the remote resource.
-
#instantiate(*args) ⇒ Object
!nb: this method is called when associations are loaded so you can use the remoted record in associations.
-
#local_attribute_name(remote_attr) ⇒ Object
-
#local_attribute_names ⇒ Object
-
#local_key(remote_key = nil) ⇒ Object
-
#method_missing(method_sym, *args, &block) ⇒ Object
-
#nosync? ⇒ Boolean
-
#recognize_remote_finder_method(method_sym) ⇒ Object
If the missing method IS a Remotable finder method, returns the remote key (may be a composite key).
-
#remote_attribute_name(local_attr) ⇒ Object
-
#remote_attribute_names ⇒ Object
-
#remote_key(*args) ⇒ Object
Sets the key with which a resource is identified remotely.
-
#remote_path_for(remote_key, *values) ⇒ Object
-
#remote_path_for_composite_key(route, local_key, values) ⇒ Object
-
#remote_path_for_simple_key(route, local_key, value) ⇒ Object
-
#respond_to?(method_sym, include_private = false) ⇒ Boolean
-
#route_for(remote_key) ⇒ Object
Methods included from Nosync
#nosync, #nosync!, #nosync=
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_sym, *args, &block) ⇒ Object
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
# File 'lib/remotable/active_record_extender.rb', line 161
def method_missing(method_sym, *args, &block)
method_details = recognize_remote_finder_method(method_sym)
if method_details
local_attributes = method_details[:local_attributes]
values = args
unless values.length == local_attributes.length
raise ArgumentError, "#{method_sym} was called with #{values.length} but #{local_attributes.length} was expected"
end
local_resource = ((0...local_attributes.length).inject(scoped) do |scope, i|
scope.where(local_attributes[i] => values[i])
end).first || fetch_by(method_details[:remote_key], *values)
raise ActiveRecord::RecordNotFound if local_resource.nil? && (method_sym =~ /!$/)
local_resource
else
super(method_sym, *args, &block)
end
end
|
Instance Attribute Details
#local_attribute_routes ⇒ Object
Returns the value of attribute local_attribute_routes.
98
99
100
|
# File 'lib/remotable/active_record_extender.rb', line 98
def local_attribute_routes
@local_attribute_routes
end
|
#remote_attribute_map ⇒ Object
Returns the value of attribute remote_attribute_map.
98
99
100
|
# File 'lib/remotable/active_record_extender.rb', line 98
def remote_attribute_map
@remote_attribute_map
end
|
Instance Method Details
#attr_remote(*attrs) ⇒ Object
80
81
82
83
84
85
86
87
88
89
|
# File 'lib/remotable/active_record_extender.rb', line 80
def attr_remote(*attrs)
map = attrs.
map = attrs.map_to_self.merge(map)
@remote_attribute_map = map
assert_that_remote_resource_responds_to_remote_attributes!(remote_model) if Remotable.validate_models?
@local_attribute_routes = {}
end
|
#default_route_for(local_key, remote_key = nil) ⇒ Object
131
132
133
134
135
136
137
138
139
|
# File 'lib/remotable/active_record_extender.rb', line 131
def default_route_for(local_key, remote_key=nil)
puts "local_key: #{local_key}; remote_key: #{remote_key}"
remote_key ||= remote_attribute_name(local_key)
if remote_key.to_s == primary_key
":#{local_key}"
else
"by_#{local_key}/:#{local_key}"
end
end
|
#expire_all! ⇒ Object
209
210
211
|
# File 'lib/remotable/active_record_extender.rb', line 209
def expire_all!
update_all(["expires_at=?", 1.day.ago])
end
|
#expires_after(*args) ⇒ Object
75
76
77
78
|
# File 'lib/remotable/active_record_extender.rb', line 75
def expires_after(*args)
@expires_after = args.first if args.any?
@expires_after
end
|
#fetch_by(remote_attr, *values) ⇒ Object
Looks the resource up remotely, by the given attribute If the resource is found, wraps it in a new local resource and returns that.
218
219
220
221
|
# File 'lib/remotable/active_record_extender.rb', line 218
def fetch_by(remote_attr, *values)
remote_resource = find_remote_resource_by(remote_attr, *values)
remote_resource && new_from_remote(remote_resource)
end
|
#fetch_with(local_key, options = {}) ⇒ Object
Also known as:
find_by
91
92
93
|
# File 'lib/remotable/active_record_extender.rb', line 91
def fetch_with(local_key, options={})
@local_attribute_routes.merge!(local_key => options[:path])
end
|
#find_remote_resource_by(remote_attr, *values) ⇒ Object
Looks the resource up remotely; Returns the remote resource.
225
226
227
228
229
230
231
232
233
|
# File 'lib/remotable/active_record_extender.rb', line 225
def find_remote_resource_by(remote_attr, *values)
find_by = remote_model.method(:find_by)
case find_by.arity
when 1; find_by.call(remote_path_for(remote_attr, *values))
when 2; find_by.call(remote_attr, *values)
else
raise InvalidRemoteModel, "#{remote_model}.find_by should take either 1 or 2 parameters"
end
end
|
#instantiate(*args) ⇒ Object
!nb: this method is called when associations are loaded so you can use the remoted record in associations.
145
146
147
148
149
150
151
152
|
# File 'lib/remotable/active_record_extender.rb', line 145
def instantiate(*args)
record = super
if record.expired? && !Remotable.nosync?
record.pull_remote_data!
record = nil if record.destroyed?
end
record
end
|
#local_attribute_name(remote_attr) ⇒ Object
122
123
124
|
# File 'lib/remotable/active_record_extender.rb', line 122
def local_attribute_name(remote_attr)
remote_attribute_map[remote_attr] || remote_attr
end
|
#local_attribute_names ⇒ Object
114
115
116
|
# File 'lib/remotable/active_record_extender.rb', line 114
def local_attribute_names
remote_attribute_map.values
end
|
#local_key(remote_key = nil) ⇒ Object
101
102
103
104
105
106
107
108
|
# File 'lib/remotable/active_record_extender.rb', line 101
def local_key(remote_key=nil)
remote_key ||= self.remote_key
if remote_key.is_a?(Array)
remote_key.map(&method(:local_attribute_name))
else
local_attribute_name(remote_key)
end
end
|
#nosync? ⇒ Boolean
36
37
38
|
# File 'lib/remotable/active_record_extender.rb', line 36
def nosync?
Remotable.nosync? || super
end
|
#recognize_remote_finder_method(method_sym) ⇒ Object
If the missing method IS a Remotable finder method, returns the remote key (may be a composite key). Otherwise, returns false.
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
# File 'lib/remotable/active_record_extender.rb', line 185
def recognize_remote_finder_method(method_sym)
method_name = method_sym.to_s
return false unless method_name =~ /find_by_([^!]*)(!?)/
local_attributes = $1.split("_and_").map(&:to_sym)
remote_attributes = local_attributes.map(&method(:remote_attribute_name))
local_key, remote_key = if local_attributes.length == 1
[local_attributes[0], remote_attributes[0]]
else
[local_attributes, remote_attributes]
end
generate_default_remote_key
return false unless local_attribute_routes.key?(local_key)
{ :local_attributes => local_attributes,
:remote_key => remote_key }
end
|
#remote_attribute_name(local_attr) ⇒ Object
118
119
120
|
# File 'lib/remotable/active_record_extender.rb', line 118
def remote_attribute_name(local_attr)
remote_attribute_map.key(local_attr) || local_attr
end
|
#remote_attribute_names ⇒ Object
110
111
112
|
# File 'lib/remotable/active_record_extender.rb', line 110
def remote_attribute_names
remote_attribute_map.keys
end
|
#remote_key(*args) ⇒ Object
Sets the key with which a resource is identified remotely. If no remote key is set, the remote key is assumed to be :id. Which could be explicitly set like this:
remote_key :id
It can can be a composite key:
remote_key [:calendar_id, :id]
You can also supply a path for the remote key which will be passed to fetch_with
:
remote_key [:calendar_id, :id], :path => "calendars/:calendar_id/events/:id"
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
# File 'lib/remotable/active_record_extender.rb', line 55
def remote_key(*args)
if args.any?
remote_key = args.shift
options = args.shift || {}
Array.wrap(remote_key).each do |attribute|
raise(":#{attribute} is not the name of a remote attribute") unless remote_attribute_names.member?(attribute)
end
fetch_with(local_key(remote_key), options)
@remote_key = remote_key
else
@remote_key || generate_default_remote_key
end
end
|
#remote_path_for(remote_key, *values) ⇒ Object
235
236
237
238
239
240
241
242
243
244
|
# File 'lib/remotable/active_record_extender.rb', line 235
def remote_path_for(remote_key, *values)
route = route_for(remote_key)
local_key = self.local_key(remote_key)
if remote_key.is_a?(Array)
remote_path_for_composite_key(route, local_key, values)
else
remote_path_for_simple_key(route, local_key, values.first)
end
end
|
#remote_path_for_composite_key(route, local_key, values) ⇒ Object
250
251
252
253
254
255
256
257
258
|
# File 'lib/remotable/active_record_extender.rb', line 250
def remote_path_for_composite_key(route, local_key, values)
unless values.length == local_key.length
raise ArgumentError, "local_key has #{local_key.length} attributes but values has #{values.length}"
end
(0...values.length).inject(route) do |route, i|
route.gsub(/:#{local_key[i]}/, values[i].to_s)
end
end
|
#remote_path_for_simple_key(route, local_key, value) ⇒ Object
246
247
248
|
# File 'lib/remotable/active_record_extender.rb', line 246
def remote_path_for_simple_key(route, local_key, value)
route.gsub(/:#{local_key}/, value.to_s)
end
|
#respond_to?(method_sym, include_private = false) ⇒ Boolean
156
157
158
159
|
# File 'lib/remotable/active_record_extender.rb', line 156
def respond_to?(method_sym, include_private=false)
return true if recognize_remote_finder_method(method_sym)
super(method_sym, include_private)
end
|
#route_for(remote_key) ⇒ Object
126
127
128
129
|
# File 'lib/remotable/active_record_extender.rb', line 126
def route_for(remote_key)
local_key = self.local_key(remote_key)
local_attribute_routes[local_key] || default_route_for(local_key, remote_key)
end
|