remotable 0.0.1 → 0.1.1

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/Rakefile CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'bundler/gem_tasks'
2
-
3
2
  require 'rake/testtask'
4
3
 
5
4
  Rake::TestTask.new(:test) do |t|
data/lib/remotable.rb CHANGED
@@ -1,7 +1,4 @@
1
1
  require "remotable/version"
2
- require "remotable/core_ext"
3
- require "remotable/active_resource_fixes"
4
- require "active_support/concern"
5
2
 
6
3
 
7
4
  # Remotable keeps a locally-stored ActiveRecord
@@ -31,268 +28,23 @@ require "active_support/concern"
31
28
  #
32
29
  #
33
30
  module Remotable
34
- extend ActiveSupport::Concern
35
31
 
36
32
 
37
33
 
38
- included do
39
- before_update :update_remote_resource, :unless => :nosync?
40
- before_create :create_remote_resource, :unless => :nosync?
41
- before_destroy :destroy_remote_resource, :unless => :nosync?
42
-
43
- before_validation :reset_expiration_date, :on => :create, :unless => :nosync?
44
-
45
- validates_presence_of :expires_at
46
-
47
- default_remote_attributes = column_names - ["id", "created_at", "updated_at", "expires_at"]
48
- @remote_model_name = "#{self.name}::Remote#{self.name}"
49
- @remote_attribute_map = default_remote_attributes.map_to_self
50
- @expires_after = 1.day
51
- end
52
-
53
-
54
-
55
- module ClassMethods
56
-
57
- def remote_model_name(name)
58
- @remote_model = nil
59
- @remote_model_name = name
60
- end
61
-
62
- def attr_remote(*attrs)
63
- map = attrs.extract_options!
64
- map = attrs.map_to_self(map)
65
- @remote_attribute_map = map
66
- end
67
-
68
- def fetch_with(local_key)
69
- @local_key = local_key
70
- @remote_key = remote_attribute_name(local_key)
71
-
72
- class_eval <<-RUBY
73
- def self.find_by_#{local_key}(value)
74
- local_resource = where(:#{local_key} => value).first
75
- local_resource || fetch_new_from_remote(value)
76
- end
77
-
78
- def self.find_by_#{local_key}!(value)
79
- find_by_#{local_key}(value) || raise(ActiveRecord::RecordNotFound)
80
- end
81
- RUBY
82
- end
83
-
84
- def expires_after(val)
85
- @expires_after = val
86
- end
87
-
88
-
89
-
90
- attr_reader :local_key,
91
- :remote_key,
92
- :expires_after,
93
- :remote_attribute_map
94
-
95
- def remote_model
96
- @remote_model ||= @remote_model_name.constantize
97
- end
98
-
99
- def remote_attribute_names
100
- remote_attribute_map.keys
101
- end
102
-
103
- def local_attribute_names
104
- remote_attribute_map.values
105
- end
106
-
107
- def remote_attribute_name(local_attr)
108
- remote_attribute_map.key(local_attr) || local_attr
109
- end
110
-
111
- def local_attribute_name(remote_attr)
112
- remote_attribute_map[remote_attr] || remote_attr
113
- end
114
-
115
-
116
-
117
- # !nb: this method is called when associations are loaded
118
- # so you can use the remoted record in associations.
119
- def instantiate(*args)
120
- record = super
121
- record.pull_remote_data! if record.expired?
122
- record = nil if record.destroyed?
123
- record
124
- end
125
-
126
-
127
-
128
- private
129
-
130
-
131
-
132
- def fetch_new_from_remote(value)
133
- record = self.new
134
- record.send("#{local_key}=", value) # {local_key => value} not passed to :new so local_key can be protected
135
- if record.remote_resource
136
- record.pull_remote_data!
137
- else
138
- nil
139
- end
140
- end
141
-
142
- end
143
-
144
-
145
-
146
- delegate :local_key,
147
- :remote_key,
148
- :remote_model,
149
- :remote_attribute_map,
150
- :remote_attribute_names,
151
- :remote_attribute_name,
152
- :local_attribute_names,
153
- :local_attribute_name,
154
- :expires_after,
155
- :to => "self.class"
156
-
157
- def expired?
158
- expires_at.nil? || expires_at < Time.now
159
- end
160
-
161
- def expired!
162
- update_attribute(:expires_at, 1.day.ago)
163
- end
164
-
165
-
166
-
167
- def pull_remote_data!
168
- merge_remote_data!(remote_resource)
169
- end
170
-
171
-
172
-
173
- def remote_resource
174
- @remote_resource ||= fetch_remote_resource
175
- end
176
-
177
- def any_remote_changes?
178
- (changed.map(&:to_sym) & local_attribute_names).any?
179
- end
180
-
181
-
182
-
183
- def nosync!
184
- @nosync = true
185
- end
186
-
187
- def nosync
188
- value = @nosync
189
- @nosync = true
190
- yield
191
- ensure
192
- @nosync = value
193
- end
194
-
195
- def nosync=(val)
196
- @nosync = (val == true)
197
- end
198
-
199
- def nosync?
200
- @nosync == true
201
- end
202
-
203
-
204
-
205
- private
206
-
207
- def fetch_remote_resource
208
- fetch_value = self[local_key]
209
- if remote_key == :id
210
- remote_model.find(fetch_value)
211
- else
212
- remote_model.send("find_by_#{remote_key}", fetch_value)
213
- end
214
- end
215
-
216
- def merge_remote_data!(remote_resource)
217
- if remote_resource.nil?
218
- nosync { destroy }
219
-
220
- else
221
- merge_remote_data(remote_resource)
222
- reset_expiration_date
223
- nosync { save! }
224
- end
225
-
226
- self
227
- end
228
-
229
-
230
-
231
- def update_remote_resource
232
- if any_remote_changes?
233
- merge_local_data(remote_resource, true)
234
- unless remote_resource.save
235
- merge_remote_errors(remote_resource.errors)
236
- raise ActiveRecord::RecordInvalid.new(self)
237
- end
238
- end
239
- end
240
-
241
- def create_remote_resource
242
- @remote_resource = remote_model.new
243
- merge_local_data(@remote_resource)
244
-
245
- if @remote_resource.save
34
+ def remote_model(*args)
35
+ if args.any?
36
+ @remote_model = args.first
246
37
 
247
- # This line is especially crucial if the primary key
248
- # of the remote resource needs to be stored locally.
249
- merge_remote_data(@remote_resource)
38
+ require "remotable/active_record_extender"
39
+ include Remotable::ActiveRecordExtender
250
40
  else
251
-
252
- merge_remote_errors(remote_resource.errors)
253
- raise ActiveRecord::RecordInvalid.new(self)
41
+ @remote_model
254
42
  end
255
43
  end
256
44
 
257
- def destroy_remote_resource
258
- remote_resource && remote_resource.destroy
259
- end
260
-
261
-
262
-
263
- def reset_expiration_date
264
- self.expires_at = expires_after.from_now
265
- end
266
-
267
-
268
-
269
- protected
270
-
271
- def merge_remote_errors(errors)
272
- errors.each do |attribute, message|
273
- self.errors[local_attribute_name(attribute)] = message
274
- end
275
- self
276
- end
277
-
278
- def merge_remote_data(remote_resource)
279
- remote_attribute_map.each do |remote_attr, local_attr|
280
- if remote_resource.respond_to?(remote_attr)
281
- send("#{local_attr}=", remote_resource.send(remote_attr))
282
- end
283
- end
284
- self
285
- end
286
-
287
- def merge_local_data(remote_resource, changes_only=false)
288
- remote_attribute_map.each do |remote_attr, local_attr|
289
- if !changes_only || changed.member?(local_attr.to_s)
290
- remote_resource.send("#{remote_attr}=", send(local_attr))
291
- end
292
- end
293
- self
294
- end
295
-
296
45
 
297
46
 
298
47
  end
48
+
49
+
50
+ ActiveRecord::Base.extend(Remotable) if defined?(ActiveRecord::Base)
@@ -0,0 +1,343 @@
1
+ require "remotable/core_ext"
2
+ require "active_support/concern"
3
+
4
+
5
+ module Remotable
6
+ module ActiveRecordExtender
7
+ extend ActiveSupport::Concern
8
+
9
+
10
+
11
+ included do
12
+ before_update :update_remote_resource, :unless => :nosync?
13
+ before_create :create_remote_resource, :unless => :nosync?
14
+ before_destroy :destroy_remote_resource, :unless => :nosync?
15
+
16
+ before_validation :reset_expiration_date, :on => :create, :unless => :nosync?
17
+
18
+ validates_presence_of :expires_at
19
+
20
+ default_remote_attributes = column_names - %w{id created_at updated_at expires_at}
21
+ @remote_attribute_map = default_remote_attributes.map_to_self
22
+ @remote_attribute_routes = {}
23
+ @expires_after = 1.day
24
+
25
+ extend_remote_model
26
+ end
27
+
28
+
29
+
30
+ module ClassMethods
31
+
32
+ def remote_key(*args)
33
+ if args.any?
34
+ remote_key = args.first
35
+ raise("#{remote_key} is not the name of a remote attribute") unless remote_attribute_names.member?(remote_key)
36
+ @remote_key = remote_key
37
+ fetch_with(remote_key)
38
+ remote_key
39
+ else
40
+ @remote_key || generate_default_remote_key
41
+ end
42
+ end
43
+
44
+ def expires_after(*args)
45
+ if args.any?
46
+ @expires_after = args.first
47
+ else
48
+ @expires_after
49
+ end
50
+ end
51
+
52
+ def attr_remote(*attrs)
53
+ map = attrs.extract_options!
54
+ map = attrs.map_to_self(map)
55
+ @remote_attribute_map = map
56
+ end
57
+
58
+ def fetch_with(*args)
59
+ keys_and_routes = extract_keys_and_routes(*args)
60
+ @remote_attribute_routes.merge!(keys_and_routes)
61
+ end
62
+ alias :find_by :fetch_with
63
+
64
+
65
+
66
+ attr_reader :remote_attribute_map,
67
+ :remote_attribute_routes
68
+
69
+ def local_key
70
+ local_attribute_name(remote_key)
71
+ end
72
+
73
+ def remote_attribute_names
74
+ remote_attribute_map.keys
75
+ end
76
+
77
+ def local_attribute_names
78
+ remote_attribute_map.values
79
+ end
80
+
81
+ def remote_attribute_name(local_attr)
82
+ remote_attribute_map.key(local_attr) || local_attr
83
+ end
84
+
85
+ def local_attribute_name(remote_attr)
86
+ remote_attribute_map[remote_attr] || remote_attr
87
+ end
88
+
89
+ def route_for(local_key)
90
+ remote_key = remote_attribute_name(local_key)
91
+ remote_attribute_routes[remote_key] || default_route_for(local_key, remote_key)
92
+ end
93
+
94
+ def default_route_for(local_key, remote_key=nil)
95
+ remote_key ||= remote_attribute_name(local_key)
96
+ "by_#{remote_key}/:#{local_key}.json"
97
+ end
98
+
99
+
100
+
101
+ # !nb: this method is called when associations are loaded
102
+ # so you can use the remoted record in associations.
103
+ def instantiate(*args)
104
+ record = super
105
+ record.pull_remote_data! if record.expired?
106
+ record = nil if record.destroyed?
107
+ record
108
+ end
109
+
110
+
111
+
112
+ def method_missing(method_sym, *args, &block)
113
+ method_name = method_sym.to_s
114
+
115
+ if method_name =~ /find_by_(.*)(!?)/
116
+ local_attr, bang, value = $1.to_sym, !$2.blank?, args.first
117
+ remote_attr = remote_attribute_name(local_attr)
118
+
119
+ remote_key # Make sure we've figured out the remote
120
+ # primary key if we're evaluating a finder
121
+
122
+ if remote_attribute_routes.key?(remote_attr)
123
+ local_resource = where(local_attr => value).first
124
+ unless local_resource
125
+ remote_resource = remote_model.find_by(remote_attr, value)
126
+ local_resource = new_from_remote(remote_resource) if remote_resource
127
+ end
128
+
129
+ raise ActiveRecord::RecordNotFound if local_resource.nil? && bang
130
+ return local_resource
131
+ end
132
+ end
133
+
134
+ super(method_sym, *args, &block)
135
+ end
136
+
137
+
138
+
139
+ private
140
+
141
+
142
+
143
+ def extend_remote_model
144
+ if remote_model < ActiveResource::Base
145
+ require "remotable/adapters/active_resource"
146
+ remote_model.send(:include, Remotable::Adapters::ActiveResource)
147
+ remote_model.local_model = self
148
+
149
+ # !todo
150
+ # Adapters for other API consumers can be implemented here
151
+ #
152
+
153
+ else
154
+ raise("#{remote_model} is not a recognized remote resource")
155
+ end
156
+ end
157
+
158
+
159
+ def extract_keys_and_routes(*local_keys)
160
+ keys_and_routes = local_keys.extract_options!
161
+ {}.tap do |hash|
162
+ local_keys.each {|local_key| hash[remote_attribute_name(local_key)] = nil}
163
+ keys_and_routes.each {|local_key, value| hash[remote_attribute_name(local_key)] = value}
164
+ end
165
+ end
166
+
167
+
168
+ def generate_default_remote_key
169
+ raise("No remote key supplied and :id is not a remote attribute") unless remote_attribute_names.member?(:id)
170
+ remote_key(:id)
171
+ end
172
+
173
+
174
+ def new_from_remote(remote_resource)
175
+ record = self.new
176
+ record.instance_variable_set(:@remote_resource, remote_resource)
177
+ record.pull_remote_data!
178
+ end
179
+
180
+
181
+
182
+ end
183
+
184
+
185
+
186
+ delegate :local_key,
187
+ :remote_key,
188
+ :remote_model,
189
+ :remote_attribute_map,
190
+ :remote_attribute_names,
191
+ :remote_attribute_name,
192
+ :local_attribute_names,
193
+ :local_attribute_name,
194
+ :expires_after,
195
+ :to => "self.class"
196
+
197
+ def expired?
198
+ expires_at.nil? || expires_at < Time.now
199
+ end
200
+
201
+ def expired!
202
+ update_attribute(:expires_at, 1.day.ago)
203
+ end
204
+
205
+
206
+
207
+ def pull_remote_data!
208
+ merge_remote_data!(remote_resource)
209
+ end
210
+
211
+
212
+
213
+ def remote_resource
214
+ @remote_resource ||= fetch_remote_resource
215
+ end
216
+
217
+ def any_remote_changes?
218
+ (changed.map(&:to_sym) & local_attribute_names).any?
219
+ end
220
+
221
+
222
+
223
+ def nosync!
224
+ @nosync = true
225
+ end
226
+
227
+ def nosync
228
+ value = @nosync
229
+ @nosync = true
230
+ yield
231
+ ensure
232
+ @nosync = value
233
+ end
234
+
235
+ def nosync=(val)
236
+ @nosync = (val == true)
237
+ end
238
+
239
+ def nosync?
240
+ @nosync == true
241
+ end
242
+
243
+
244
+
245
+ private
246
+
247
+ def fetch_remote_resource
248
+ fetch_value = self[local_key]
249
+ remote_model.find_by(remote_key, fetch_value)
250
+ end
251
+
252
+ def merge_remote_data!(remote_resource)
253
+ if remote_resource.nil?
254
+ nosync { destroy }
255
+
256
+ else
257
+ merge_remote_data(remote_resource)
258
+ reset_expiration_date
259
+ nosync { save! }
260
+ end
261
+
262
+ self
263
+ end
264
+
265
+
266
+
267
+ def update_remote_resource
268
+ if any_remote_changes?
269
+ merge_local_data(remote_resource, true)
270
+ unless remote_resource.save
271
+ merge_remote_errors(remote_resource.errors)
272
+ raise ActiveRecord::RecordInvalid.new(self)
273
+ end
274
+ end
275
+ end
276
+
277
+ def create_remote_resource
278
+ @remote_resource = remote_model.new
279
+ merge_local_data(@remote_resource)
280
+
281
+ if @remote_resource.save
282
+
283
+ # This line is especially crucial if the primary key
284
+ # of the remote resource needs to be stored locally.
285
+ merge_remote_data(@remote_resource)
286
+ else
287
+
288
+ merge_remote_errors(remote_resource.errors)
289
+ raise ActiveRecord::RecordInvalid.new(self)
290
+ end
291
+ end
292
+
293
+ def destroy_remote_resource
294
+ remote_resource && remote_resource.destroy
295
+ end
296
+
297
+
298
+
299
+ def reset_expiration_date
300
+ self.expires_at = expires_after.from_now
301
+ end
302
+
303
+
304
+
305
+ def local_attribute_changed?(name)
306
+ changed.member?(name.to_s)
307
+ end
308
+
309
+
310
+
311
+ protected
312
+
313
+
314
+
315
+ def merge_remote_errors(errors)
316
+ errors.each do |attribute, message|
317
+ self.errors[local_attribute_name(attribute)] = message
318
+ end
319
+ self
320
+ end
321
+
322
+ def merge_remote_data(remote_resource)
323
+ remote_attribute_map.each do |remote_attr, local_attr|
324
+ if remote_resource.respond_to?(remote_attr)
325
+ send("#{local_attr}=", remote_resource.send(remote_attr))
326
+ end
327
+ end
328
+ self
329
+ end
330
+
331
+ def merge_local_data(remote_resource, changes_only=false)
332
+ remote_attribute_map.each do |remote_attr, local_attr|
333
+ if !changes_only || local_attribute_changed?(local_attr)
334
+ remote_resource.send("#{remote_attr}=", send(local_attr))
335
+ end
336
+ end
337
+ self
338
+ end
339
+
340
+
341
+
342
+ end
343
+ end
@@ -1,4 +1,4 @@
1
- require 'active_resource'
1
+ require "active_resource"
2
2
 
3
3
 
4
4
  module ActiveResourceFixes
@@ -0,0 +1,68 @@
1
+ require "remotable/active_resource_fixes"
2
+ require "active_support/concern"
3
+
4
+
5
+ module Remotable
6
+ module Adapters
7
+ module ActiveResource
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+
12
+
13
+ attr_accessor :local_model
14
+
15
+ delegate :local_attribute_name,
16
+ :route_for,
17
+ :to => :local_model
18
+
19
+
20
+
21
+ def find_by!(key, value)
22
+ if key == :id
23
+ find(value)
24
+ else
25
+ find(:one, :from => path_for(key, value))
26
+ end
27
+ end
28
+
29
+ def find_by(key, value)
30
+ find_by!(key, value)
31
+ rescue ::ActiveResource::ResourceNotFound
32
+ nil
33
+ end
34
+
35
+
36
+
37
+ def path_for(remote_key, value)
38
+ local_key = local_attribute_name(remote_key)
39
+ route = route_for(local_key)
40
+ path = route.gsub(/:#{local_key}/, value.to_s)
41
+ if relative_path?(path)
42
+ path
43
+ else
44
+ join_url_segments(prefix, collection_name, path)
45
+ end
46
+ end
47
+
48
+
49
+
50
+ private
51
+
52
+
53
+
54
+ def relative_path?(path)
55
+ path.start_with?("/") || path["://"]
56
+ end
57
+
58
+ def join_url_segments(*segments)
59
+ segments.flatten.join("/").gsub(/\/+/, "/")
60
+ end
61
+
62
+
63
+
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -1,3 +1,3 @@
1
1
  module Remotable
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -1,8 +1,7 @@
1
1
  Factory.define :tenant do |f|
2
2
  f.sequence(:slug) { |n| "test#{n}" }
3
3
  f.name "Test"
4
-
5
- f.active true
4
+ f.sequence(:remote_id)
6
5
  f.expires_at 100.years.from_now
7
6
  f.nosync true
8
7
  end
@@ -1,29 +1,88 @@
1
- require 'test_helper'
2
- require 'remotable'
3
- require 'support/active_resource'
4
- require 'active_resource_simulator'
1
+ require "test_helper"
2
+ require "remotable"
3
+ require "support/active_resource"
4
+ require "active_resource_simulator"
5
5
 
6
6
 
7
7
  class RemotableTest < ActiveSupport::TestCase
8
8
 
9
9
 
10
- test "should create a record locally when fetching a new remote resource" do
10
+
11
+ test "should consider :id to be the remote key if none is specified" do
12
+ assert_equal :id, RemoteWithoutKey.remote_key
13
+ assert_equal :remote_id, RemoteWithoutKey.local_key
14
+ end
15
+
16
+ test "should use a different remote_key if one is supplied" do
17
+ assert_equal :slug, RemoteWithKey.remote_key
18
+ assert_equal :slug, RemoteWithKey.local_key
19
+ end
20
+
21
+ test "should be able to generate paths for with different attributes" do
22
+ assert_equal "/api/accounts/by_slug/value.json", RemoteTenant.path_for(:slug, "value")
23
+ assert_equal "/api/accounts/by_nombre/value.json", RemoteTenant.path_for(:name, "value")
24
+ end
25
+
26
+
27
+
28
+ test "should be able to find resources by different attributes" do
11
29
  new_tenant_slug = "not_found"
12
30
 
13
31
  assert_equal 0, Tenant.where(:slug => new_tenant_slug).count,
14
- "There's not supposed to be a Tenant with the subdomain #{new_tenant_slug}."
32
+ "There's not supposed to be a Tenant with the slug #{new_tenant_slug}."
15
33
 
16
34
  assert_difference "Tenant.count", +1 do
17
- Tenant::RemoteTenant.run_simulation do |s|
18
- attrs = {
19
- :id => 1,
20
- :slug => "not_found",
35
+ RemoteTenant.run_simulation do |s|
36
+ s.show(nil, {
37
+ :id => 46,
38
+ :slug => new_tenant_slug,
21
39
  :church_name => "Not Found"
22
- }
40
+ }, :path => "/api/accounts/by_slug/#{new_tenant_slug}.json")
23
41
 
24
- s.show(nil, attrs, :path => "/api/accounts/by_slug/#{attrs[:slug]}.json")
42
+ new_tenant = Tenant.find_by_slug(new_tenant_slug)
43
+ assert_not_nil new_tenant, "A remote tenant was not found with the slug #{new_tenant_slug.inspect}"
44
+ end
45
+ end
46
+ end
47
+
48
+ test "should be able to find resources by different attributes and specify a path" do
49
+ new_tenant_name = "JohnnyG"
50
+
51
+ assert_equal 0, Tenant.where(:name => new_tenant_name).count,
52
+ "There's not supposed to be a Tenant with the name #{new_tenant_name}."
53
+
54
+ assert_difference "Tenant.count", +1 do
55
+ RemoteTenant.run_simulation do |s|
56
+ s.show(nil, {
57
+ :id => 46,
58
+ :slug => "not_found",
59
+ :church_name => new_tenant_name
60
+ }, :path => "/api/accounts/by_nombre/#{new_tenant_name}.json")
61
+
62
+ new_tenant = Tenant.find_by_name(new_tenant_name)
63
+ assert_not_nil new_tenant, "A remote tenant was not found with the name #{new_tenant_name.inspect}"
64
+ end
65
+ end
66
+ end
67
+
68
+
69
+
70
+ test "should create a record locally when fetching a new remote resource" do
71
+ new_tenant_id = 17
72
+
73
+ assert_equal 0, Tenant.where(:remote_id => new_tenant_id).count,
74
+ "There's not supposed to be a Tenant with the id #{new_tenant_id}."
75
+
76
+ assert_difference "Tenant.count", +1 do
77
+ RemoteTenant.run_simulation do |s|
78
+ s.show(new_tenant_id, {
79
+ :id => new_tenant_id,
80
+ :slug => "not_found",
81
+ :church_name => "Not Found"
82
+ })
25
83
 
26
- Tenant.find_by_slug(new_tenant_slug)
84
+ new_tenant = Tenant.find_by_remote_id(new_tenant_id)
85
+ assert_not_nil new_tenant, "A remote tenant was not found with the id #{new_tenant_id.inspect}"
27
86
  end
28
87
  end
29
88
  end
@@ -34,16 +93,14 @@ class RemotableTest < ActiveSupport::TestCase
34
93
  tenant = Factory(:tenant, :expires_at => 100.years.from_now)
35
94
  unexpected_name = "Totally Wonky"
36
95
 
37
- Tenant::RemoteTenant.run_simulation do |s|
38
- attrs = {
39
- :id => tenant.id,
96
+ RemoteTenant.run_simulation do |s|
97
+ s.show(tenant.remote_id, {
98
+ :id => tenant.remote_id,
40
99
  :slug => tenant.slug,
41
100
  :church_name => unexpected_name
42
- }
43
-
44
- s.show(nil, attrs, :path => "/api/accounts/by_slug/#{attrs[:slug]}.json")
101
+ })
45
102
 
46
- tenant = Tenant.find_by_slug(tenant.slug)
103
+ tenant = Tenant.find_by_remote_id(tenant.remote_id)
47
104
  assert_not_equal unexpected_name, tenant.name
48
105
  end
49
106
  end
@@ -54,16 +111,14 @@ class RemotableTest < ActiveSupport::TestCase
54
111
  tenant = Factory(:tenant, :expires_at => 1.year.ago)
55
112
  unexpected_name = "Totally Wonky"
56
113
 
57
- Tenant::RemoteTenant.run_simulation do |s|
58
- attrs = {
59
- :id => tenant.id,
114
+ RemoteTenant.run_simulation do |s|
115
+ s.show(tenant.remote_id, {
116
+ :id => tenant.remote_id,
60
117
  :slug => tenant.slug,
61
118
  :church_name => unexpected_name
62
- }
63
-
64
- s.show(nil, attrs, :path => "/api/accounts/by_slug/#{attrs[:slug]}.json")
119
+ })
65
120
 
66
- tenant = Tenant.find_by_slug(tenant.slug)
121
+ tenant = Tenant.find_by_remote_id(tenant.remote_id)
67
122
  assert_equal unexpected_name, tenant.name
68
123
  end
69
124
  end
@@ -74,11 +129,10 @@ class RemotableTest < ActiveSupport::TestCase
74
129
  tenant = Factory(:tenant, :expires_at => 1.year.ago)
75
130
 
76
131
  assert_difference "Tenant.count", -1 do
77
- Tenant::RemoteTenant.run_simulation do |s|
78
-
79
- s.show(nil, nil, :path => "/api/accounts/by_slug/#{tenant.slug}.json", :status => 404)
132
+ RemoteTenant.run_simulation do |s|
133
+ s.show(tenant.remote_id, nil, :status => 404)
80
134
 
81
- tenant = Tenant.find_by_slug(tenant.slug)
135
+ tenant = Tenant.find_by_remote_id(tenant.remote_id)
82
136
  assert_equal nil, tenant
83
137
  end
84
138
  end
@@ -90,14 +144,13 @@ class RemotableTest < ActiveSupport::TestCase
90
144
  tenant = Factory(:tenant)
91
145
  new_name = "Totally Wonky"
92
146
 
93
- Tenant::RemoteTenant.run_simulation do |s|
94
- s.show(nil, {
95
- :id => tenant.id,
147
+ RemoteTenant.run_simulation do |s|
148
+ s.show(tenant.remote_id, {
149
+ :id => tenant.remote_id,
96
150
  :slug => tenant.slug,
97
151
  :church_name => tenant.name
98
- }, :path => "/api/accounts/by_slug/#{tenant.slug}.json")
99
-
100
- s.update(tenant.id)
152
+ })
153
+ s.update(tenant.remote_id)
101
154
 
102
155
  tenant.nosync = false
103
156
  tenant.name = "Totally Wonky"
@@ -113,14 +166,13 @@ class RemotableTest < ActiveSupport::TestCase
113
166
  tenant = Factory(:tenant)
114
167
  new_name = "Totally Wonky"
115
168
 
116
- Tenant::RemoteTenant.run_simulation do |s|
117
- s.show(nil, {
118
- :id => tenant.id,
119
- :slug => tenant.slug,
120
- :church_name => tenant.name
121
- }, :path => "/api/accounts/by_slug/#{tenant.slug}.json")
122
-
123
- s.update(tenant.id, :status => 422, :body => {
169
+ RemoteTenant.run_simulation do |s|
170
+ s.show(tenant.remote_id, {
171
+ :id => tenant.remote_id,
172
+ :slug => tenant.slug,
173
+ :church_name => tenant.name
174
+ })
175
+ s.update(tenant.remote_id, :status => 422, :body => {
124
176
  :errors => {:church_name => ["is already taken"]}
125
177
  })
126
178
 
@@ -141,7 +193,7 @@ class RemotableTest < ActiveSupport::TestCase
141
193
  :name => "Brand New"
142
194
  })
143
195
 
144
- Tenant::RemoteTenant.run_simulation do |s|
196
+ RemoteTenant.run_simulation do |s|
145
197
  s.create({
146
198
  :id => 143,
147
199
  :slug => tenant.slug,
@@ -160,7 +212,7 @@ class RemotableTest < ActiveSupport::TestCase
160
212
  :name => "Brand New"
161
213
  })
162
214
 
163
- Tenant::RemoteTenant.run_simulation do |s|
215
+ RemoteTenant.run_simulation do |s|
164
216
  s.create({
165
217
  :errors => {
166
218
  :what => ["ever"],
@@ -180,14 +232,13 @@ class RemotableTest < ActiveSupport::TestCase
180
232
  test "should destroy a record remotely when destroying one locally" do
181
233
  tenant = Factory(:tenant)
182
234
 
183
- Tenant::RemoteTenant.run_simulation do |s|
184
- s.show(nil, {
185
- :id => tenant.id,
186
- :slug => tenant.slug,
187
- :church_name => tenant.name
188
- }, :path => "/api/accounts/by_slug/#{tenant.slug}.json")
189
-
190
- s.destroy(tenant.id)
235
+ RemoteTenant.run_simulation do |s|
236
+ s.show(tenant.remote_id, {
237
+ :id => tenant.remote_id,
238
+ :slug => tenant.slug,
239
+ :church_name => tenant.name
240
+ })
241
+ s.destroy(tenant.remote_id)
191
242
 
192
243
  tenant.nosync = false
193
244
  tenant.destroy
@@ -199,14 +250,14 @@ class RemotableTest < ActiveSupport::TestCase
199
250
  test "should fail to destroy a record locally when failing to destroy one remotely" do
200
251
  tenant = Factory(:tenant)
201
252
 
202
- Tenant::RemoteTenant.run_simulation do |s|
203
- s.show(nil, {
204
- :id => tenant.id,
205
- :slug => tenant.slug,
206
- :church_name => tenant.name
207
- }, :path => "/api/accounts/by_slug/#{tenant.slug}.json")
253
+ RemoteTenant.run_simulation do |s|
254
+ s.show(tenant.remote_id, {
255
+ :id => tenant.remote_id,
256
+ :slug => tenant.slug,
257
+ :church_name => tenant.name
258
+ })
208
259
 
209
- s.destroy(tenant.id, :status => 500)
260
+ s.destroy(tenant.remote_id, :status => 500)
210
261
 
211
262
  tenant.nosync = false
212
263
  assert_raises(ActiveResource::ServerError) do
@@ -1,32 +1,43 @@
1
- require 'active_record'
2
- require 'active_resource'
1
+ require "active_record"
2
+ require "active_resource"
3
+
4
+
5
+ class RemoteTenant < ActiveResource::Base
6
+ self.site = "http://example.com/api/"
7
+ self.element_name = "account"
8
+ self.format = :json
9
+ self.include_root_in_json = false
10
+ self.user = "username"
11
+ self.password = "password"
12
+ end
3
13
 
4
14
  class Tenant < ActiveRecord::Base
5
- include Remotable
15
+ remote_model RemoteTenant
16
+ attr_remote :slug, :church_name => :name, :id => :remote_id
17
+ find_by :slug
18
+ find_by :name => "by_nombre/:name.json"
19
+ end
20
+
21
+
22
+
23
+ class RemoteTenant2 < ActiveResource::Base
24
+ end
25
+
26
+ class RemoteWithoutKey < ActiveRecord::Base
27
+ set_table_name "tenants"
6
28
 
7
- attr_remote :slug, :church_name => :name, :active_unite_account => :active
8
- fetch_with :slug
29
+ remote_model RemoteTenant2
30
+ attr_remote :id => :remote_id
31
+ end
32
+
33
+
34
+ class RemoteTenant3 < ActiveResource::Base
35
+ end
36
+
37
+ class RemoteWithKey < ActiveRecord::Base
38
+ set_table_name "tenants"
9
39
 
10
- class RemoteTenant < ActiveResource::Base
11
-
12
- self.site = "http://example.com/api/"
13
- self.element_name = "account"
14
- self.format = :json
15
- self.include_root_in_json = false
16
- self.user = "username"
17
- self.password = "password"
18
-
19
- class << self
20
- def find_by_slug!(slug)
21
- find(:one, :from => "/api/accounts/by_slug/#{slug}.json")
22
- end
23
-
24
- def find_by_slug(slug)
25
- find_by_slug!(slug)
26
- rescue ActiveResource::ResourceNotFound
27
- nil
28
- end
29
- end
30
-
31
- end
40
+ remote_model RemoteTenant3
41
+ attr_remote :slug
42
+ remote_key :slug
32
43
  end
@@ -13,12 +13,12 @@
13
13
  ActiveRecord::Schema.define(:version => 20110507152635) do
14
14
 
15
15
  create_table "tenants", :force => true do |t|
16
- t.string "slug", :null => false
17
- t.string "name", :null => false
18
- t.boolean "active"
16
+ t.string "slug"
17
+ t.string "name"
18
+ t.integer "remote_id"
19
19
  t.datetime "created_at"
20
20
  t.datetime "updated_at"
21
- t.datetime "expires_at"
21
+ t.datetime "expires_at", :null => false
22
22
  end
23
23
 
24
24
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: remotable
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.1.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Robert Lail
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-08-18 00:00:00 -05:00
13
+ date: 2011-08-26 00:00:00 -05:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -115,7 +115,9 @@ files:
115
115
  - Gemfile
116
116
  - Rakefile
117
117
  - lib/remotable.rb
118
+ - lib/remotable/active_record_extender.rb
118
119
  - lib/remotable/active_resource_fixes.rb
120
+ - lib/remotable/adapters/active_resource.rb
119
121
  - lib/remotable/core_ext.rb
120
122
  - lib/remotable/core_ext/enumerable.rb
121
123
  - lib/remotable/version.rb