HasRemote 0.1.7 → 0.2.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/.rspec +2 -0
- data/.yardopts +1 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +93 -0
- data/HasRemote.gemspec +33 -28
- data/MIT-LICENSE +1 -1
- data/README.rdoc +21 -18
- data/Rakefile +9 -26
- data/TODO +3 -3
- data/VERSION +1 -1
- data/lib/generators/has_remote/migration_generator.rb +20 -0
- data/{generators/has_remote_migration/templates/create_has_remote_synchronizations.erb → lib/generators/has_remote/templates/create_has_remote_synchronizations.rb} +0 -0
- data/lib/has_remote.rb +46 -37
- data/lib/has_remote/railtie.rb +21 -0
- data/lib/has_remote/synchronizable.rb +31 -30
- data/lib/has_remote/synchronization.rb +10 -1
- data/lib/{has_remote/tasks.rb → tasks/has_remote.rake} +0 -0
- data/shoulda_macros/has_remote_macros.rb +16 -14
- data/spec/caching_spec.rb +8 -11
- data/spec/has_remote_spec.rb +16 -16
- data/spec/spec_helper.rb +13 -28
- data/spec/support/book.rb +5 -0
- data/spec/support/cheese.rb +11 -0
- data/spec/support/product.rb +7 -0
- data/spec/support/user.rb +9 -0
- data/spec/synchronization_spec.rb +2 -1
- metadata +91 -62
- data/generators/has_remote_migration/has_remote_migration_generator.rb +0 -7
- data/init.rb +0 -1
- data/rails/init.rb +0 -1
- data/spec/has_remote_spec/book.rb +0 -7
- data/spec/has_remote_spec/cheese.rb +0 -10
- data/spec/has_remote_spec/product.rb +0 -9
- data/spec/has_remote_spec/user.rb +0 -11
- data/tasks/rails.rake +0 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'rails'
|
|
2
|
+
|
|
3
|
+
module HasRemote
|
|
4
|
+
# @private
|
|
5
|
+
class Railtie < Rails::Railtie #:nodoc:
|
|
6
|
+
initializer 'has_remote.load' do
|
|
7
|
+
ActiveSupport.on_load(:active_record) do
|
|
8
|
+
HasRemote::Railtie.load!
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
rake_tasks do
|
|
13
|
+
load 'tasks/has_remote.rake'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.load!
|
|
17
|
+
ActiveRecord::Base.send :include, HasRemote
|
|
18
|
+
ActiveSupport.run_load_hooks(:has_remote)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
module HasRemote
|
|
2
2
|
|
|
3
|
-
# Contains class methods regarding synchronization of changed, added and deleted
|
|
3
|
+
# Contains class methods regarding synchronization of changed, added and deleted remote data.
|
|
4
4
|
#
|
|
5
|
-
#
|
|
5
|
+
# ==== Synchronization examples:
|
|
6
6
|
#
|
|
7
7
|
# Update all cached attributes, destroy deleted records and add new records for all models that have a remote:
|
|
8
8
|
# HasRemote.synchronize!
|
|
@@ -17,12 +17,15 @@ module HasRemote
|
|
|
17
17
|
# @user.update_cached_attributes!
|
|
18
18
|
#
|
|
19
19
|
# You can make your application call these methods whenever you need to be sure
|
|
20
|
-
# your cache is up to date
|
|
21
|
-
# from the command line.
|
|
20
|
+
# your cache is up to date.
|
|
22
21
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
22
|
+
# You can also use a rake task to synchronize from the command line:
|
|
23
|
+
# rake hr:sync
|
|
24
|
+
#
|
|
25
|
+
# See the {file:README.rdoc README} for more rake options.
|
|
26
|
+
#
|
|
27
|
+
# @note All remote resources need to have an <tt>updated_at</tt> field in order for synchronization to work. Optionally, records will
|
|
28
|
+
# be destroyed if their remote has a <tt>deleted_at</tt> field and its time lies before the time of synchronization.
|
|
26
29
|
#
|
|
27
30
|
module Synchronizable
|
|
28
31
|
|
|
@@ -32,44 +35,40 @@ module HasRemote
|
|
|
32
35
|
@cached_attributes ||= []
|
|
33
36
|
end
|
|
34
37
|
|
|
35
|
-
# Returns all remote objects that have been changed since the
|
|
36
|
-
# time is given. This may include new and optionally deleted (tagged by a
|
|
37
|
-
#
|
|
38
|
-
# This is used by the <tt>synchronize!</tt> class method. By default
|
|
39
|
-
# it queries '/updated?since=<time>&last_record_id=<id>' on your resources URL, where 'time' is
|
|
40
|
-
# the updated_at value of the last processed remote object and 'last_record_id' is its id.
|
|
41
|
-
#
|
|
42
|
-
# *Options*
|
|
38
|
+
# Returns all remote objects that have been changed since the last synchornization _(or since ever if no
|
|
39
|
+
# time is given)_. This may include new and optionally deleted (tagged by a <tt>deleted_at</tt> attribute) resources.
|
|
43
40
|
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
41
|
+
# This method is called from the {#synchronize!} class method. By default
|
|
42
|
+
# it queries <tt>/updated?since=[time]&last_record_id=[id]</tt> on your resources URL, where <tt>time</tt> is
|
|
43
|
+
# the updated_at value of the last processed remote object and <tt>last_record_id</tt> is its ID.
|
|
46
44
|
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
45
|
+
# *Important:* If you are using synchronization you'll probably need to override this method in your model to match
|
|
46
|
+
# your host's REST API; here's an example of another implementation:
|
|
49
47
|
#
|
|
50
48
|
# def self.updated_remotes(options = nil)
|
|
51
49
|
# time = last_synchronization.try(:last_record_updated_at) || 12.hours.ago
|
|
52
50
|
# User::Remote.find :all, :from => :search, :params => { :updated_since => time.to_s(:db) }
|
|
53
51
|
# end
|
|
54
52
|
#
|
|
55
|
-
|
|
53
|
+
# @param [Hash] parameters The parameter options passed in to {#synchronize!} will be passed through to this method.
|
|
54
|
+
# They are used as request parameters for remotely requesting the updated records.
|
|
55
|
+
#
|
|
56
|
+
def updated_remotes( parameters = {} )
|
|
56
57
|
time = last_synchronization.try(:last_record_updated_at) || DateTime.parse("Jan 1 1970")
|
|
57
|
-
remote_class.find :all, :from => :updated, :params => { :since => time.to_s, :last_record_id => last_synchronization.try(:last_record_id) }.merge(
|
|
58
|
+
remote_class.find :all, :from => :updated, :params => { :since => time.to_s, :last_record_id => last_synchronization.try(:last_record_id) }.merge( parameters )
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
# Will update all records that have been created, updated or deleted on the remote host
|
|
61
62
|
# since the last successful synchronization.
|
|
62
63
|
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
# Options are passed through to <tt>updated_remotes</tt> which is called in order to fetch the updated records.
|
|
66
|
-
# Use this if you want to override its default options.
|
|
64
|
+
# @param [Hash] parameters Parameter options are passed through to {#updated_remotes}. There they are used
|
|
65
|
+
# as request parameters for remotely requesting the updated records.
|
|
67
66
|
#
|
|
68
|
-
def synchronize!(
|
|
67
|
+
def synchronize!(parameters = {})
|
|
69
68
|
logger.info( "*** Start synchronizing #{table_name} at #{Time.now.to_s :long} ***\n" )
|
|
70
69
|
@sync_count = 0
|
|
71
70
|
begin
|
|
72
|
-
changed_objects = updated_remotes(
|
|
71
|
+
changed_objects = updated_remotes( parameters )
|
|
73
72
|
if changed_objects.any?
|
|
74
73
|
# Do everything within transaction to prevent ending up in half-synchronized situation if an exception is raised.
|
|
75
74
|
transaction { sync_all_records_for(changed_objects) }
|
|
@@ -90,7 +89,9 @@ module HasRemote
|
|
|
90
89
|
end
|
|
91
90
|
end
|
|
92
91
|
|
|
93
|
-
#
|
|
92
|
+
# Returns the record for last successful synchronization for this model.
|
|
93
|
+
#
|
|
94
|
+
# @return [Synchronization]
|
|
94
95
|
#
|
|
95
96
|
def last_synchronization
|
|
96
97
|
HasRemote::Synchronization.for(self.name).last
|
|
@@ -142,11 +143,11 @@ module HasRemote
|
|
|
142
143
|
update_and_save_record_for_resource(new(remote_foreign_key => resource.send(remote_primary_key)), resource)
|
|
143
144
|
end
|
|
144
145
|
|
|
145
|
-
def time_updated(resource)
|
|
146
|
+
def time_updated(resource) #:nodoc:
|
|
146
147
|
(resource.respond_to?(:deleted_at) && resource.deleted_at) ? resource.deleted_at : resource.updated_at
|
|
147
148
|
end
|
|
148
149
|
|
|
149
|
-
def deleted?(resource)
|
|
150
|
+
def deleted?(resource) #:nodoc:
|
|
150
151
|
resource.respond_to?(:deleted_at) && resource.deleted_at && resource.deleted_at <= Time.now
|
|
151
152
|
end
|
|
152
153
|
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
module HasRemote
|
|
2
2
|
|
|
3
|
+
# This model represents a synchronization performed by HasRemote.
|
|
4
|
+
#
|
|
5
|
+
# ==== Attributes:
|
|
6
|
+
#
|
|
7
|
+
# [model_name] (String) Name of the model that was synchronized.
|
|
8
|
+
# [last_record_updated_at] (Time) Timestamp representing the <tt>updated_at</tt> of the last record that was synchronized during this synchronization.
|
|
9
|
+
# [last_record_id] (Integer) ID of the last record that was synchronized during this synchronization.
|
|
10
|
+
# [created_at] (Time) time when this synchronization finished.
|
|
11
|
+
#
|
|
3
12
|
class Synchronization < ActiveRecord::Base #:nodoc:
|
|
4
13
|
set_table_name 'has_remote_synchronizations'
|
|
5
14
|
|
|
6
|
-
|
|
15
|
+
scope :for, lambda { |model_name| where(:model_name => model_name.to_s.classify) }
|
|
7
16
|
|
|
8
17
|
validates_presence_of :model_name, :last_record_updated_at, :last_record_id
|
|
9
18
|
end
|
|
File without changes
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
module
|
|
1
|
+
module HasRemote
|
|
2
|
+
module ShouldaMacros
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
def should_have_remote
|
|
5
|
+
klass = model_class
|
|
6
|
+
should "have remote resources" do
|
|
7
|
+
assert HasRemote.models.include?(klass)
|
|
8
|
+
end
|
|
7
9
|
end
|
|
8
|
-
end
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
def should_have_remote_attribute(attr_name, options = {})
|
|
12
|
+
klass = model_class
|
|
13
|
+
should "have remote attribute #{attr_name}" do
|
|
14
|
+
assert klass.remote_attributes.include?(attr_name)
|
|
15
|
+
assert klass.cached_attributes.include?(attr_name) if options[:local_cache]
|
|
16
|
+
assert klass.new.respond_to?(options[:as] || attr_name)
|
|
17
|
+
end
|
|
16
18
|
end
|
|
17
|
-
end
|
|
18
19
|
|
|
20
|
+
end
|
|
19
21
|
end
|
|
20
22
|
|
|
21
|
-
Test::Unit::TestCase.extend
|
|
23
|
+
Test::Unit::TestCase.extend HasRemote::ShouldaMacros
|
data/spec/caching_spec.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
describe "Given existing remote resources" do
|
|
4
4
|
|
|
5
5
|
before(:each) do
|
|
6
6
|
User.delete_all
|
|
@@ -27,7 +27,7 @@ context "Given existing remote resources" do
|
|
|
27
27
|
it "should find last synchronization" do
|
|
28
28
|
times = []
|
|
29
29
|
3.downto(1) do |i|
|
|
30
|
-
HasRemote::Synchronization.create(:model_name => '
|
|
30
|
+
HasRemote::Synchronization.create!(:model_name => 'User', :last_record_updated_at => i.days.ago, :last_record_id => i)
|
|
31
31
|
end
|
|
32
32
|
User.should respond_to(:last_synchronization)
|
|
33
33
|
sync = User.last_synchronization
|
|
@@ -62,16 +62,14 @@ context "Given existing remote resources" do
|
|
|
62
62
|
describe "with updated and deleted remotes" do
|
|
63
63
|
|
|
64
64
|
before(:each) do
|
|
65
|
-
@yesterday =
|
|
66
|
-
@
|
|
67
|
-
@user_1, @user_2, @user_3 = User.create!(:remote_id => @last_id), User.create!(:remote_id => 1), User.create!(:remote_id => 2)
|
|
65
|
+
@yesterday = 1.day.ago
|
|
66
|
+
@user_1, @user_2 = User.create!(:remote_id => 1), User.create!(:remote_id => 2)
|
|
68
67
|
|
|
69
68
|
resources = [
|
|
70
69
|
mock(:user, :id => 1, :email => "altered@foo.bar", :updated_at => 2.days.ago, :deleted_at => nil),
|
|
71
70
|
mock(:user, :id => 2, :email => "deleted@foo.bar", :updated_at => 2.days.ago, :deleted_at => 2.days.ago),
|
|
72
71
|
mock(:user, :id => 3, :email => "new-deleted@foo.bar", :updated_at => 2.days.ago, :deleted_at => 2.days.ago),
|
|
73
72
|
mock(:user, :id => 4, :email => "new@foo.bar", :updated_at => @yesterday),
|
|
74
|
-
mock(:user, :id => @last_id, :email => "changed@foo.bar", :updated_at => @yesterday)
|
|
75
73
|
]
|
|
76
74
|
User.stub!(:updated_remotes).and_return(resources)
|
|
77
75
|
|
|
@@ -79,19 +77,18 @@ context "Given existing remote resources" do
|
|
|
79
77
|
end
|
|
80
78
|
|
|
81
79
|
it "should keep track of the last synchronized record" do
|
|
82
|
-
sync = HasRemote::Synchronization.for("
|
|
80
|
+
sync = HasRemote::Synchronization.for("User").last
|
|
83
81
|
|
|
84
82
|
sync.last_record_updated_at.should == @yesterday
|
|
85
|
-
sync.last_record_id.should ==
|
|
83
|
+
sync.last_record_id.should == 4
|
|
86
84
|
end
|
|
87
85
|
|
|
88
86
|
it "should update changed users" do
|
|
89
|
-
@user_1.reload[:email].should == "
|
|
90
|
-
@user_2.reload[:email].should == "altered@foo.bar"
|
|
87
|
+
@user_1.reload[:email].should == "altered@foo.bar"
|
|
91
88
|
end
|
|
92
89
|
|
|
93
90
|
it "should destroy deleted users" do
|
|
94
|
-
User.exists?(@
|
|
91
|
+
User.exists?(@user_2).should be_false
|
|
95
92
|
end
|
|
96
93
|
|
|
97
94
|
it "should create added users" do
|
data/spec/has_remote_spec.rb
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
2
|
|
|
3
3
|
describe HasRemote do
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
it "should know about registered models" do
|
|
6
6
|
HasRemote.should respond_to(:models)
|
|
7
7
|
HasRemote.models.should include(User, Book)
|
|
8
8
|
end
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
describe User do
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
it "should respond to 'remote_class' and 'remote_foreign_key'" do
|
|
15
15
|
User.should respond_to(:remote_class, :remote_foreign_key)
|
|
16
16
|
User.remote_class.should == User::Remote
|
|
17
17
|
User.remote_foreign_key.should == :remote_id
|
|
18
18
|
end
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
it "should set remote class' configuration" do
|
|
21
21
|
User.remote_class.site.should_not be_nil
|
|
22
22
|
User.remote_class.element_name.should == "user"
|
|
23
23
|
end
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
it "should return remote attributes" do
|
|
26
26
|
User.remote_attributes.should include(:name, :email)
|
|
27
27
|
end
|
|
@@ -54,7 +54,7 @@ describe User do
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
context "without a remote" do
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
before(:each) do
|
|
59
59
|
@user.remote_id = nil
|
|
60
60
|
end
|
|
@@ -68,41 +68,41 @@ describe User do
|
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
describe Book do
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
it "should use a custom remote key" do
|
|
73
73
|
Book.remote_foreign_key.should == :custom_remote_id
|
|
74
74
|
end
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
describe "instances" do
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
it "should have a custom remote" do
|
|
79
79
|
@book = Book.new
|
|
80
80
|
@book.custom_remote_id = 1
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
RemoteBook.should_receive(:find).twice.with(1).and_return( mock(:resource, :title => "Ruby for Rails") )
|
|
83
83
|
|
|
84
84
|
@book.should respond_to(:remote)
|
|
85
85
|
@book.remote.should respond_to(:title)
|
|
86
86
|
@book.has_remote?.should be_true
|
|
87
|
-
end
|
|
87
|
+
end
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
describe Product do
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
it "should have a custom finder" do
|
|
94
94
|
Product.should respond_to(:remote_finder)
|
|
95
95
|
Product.remote_finder.should be_a(Proc)
|
|
96
96
|
end
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
describe "instances" do
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
it "should use a custom finder" do
|
|
101
101
|
@product = Product.new :remote_id => 1
|
|
102
102
|
Product::Remote.should_receive(:find).once.with(:one, :from => "/special/place/products/1.xml").and_return("resource")
|
|
103
|
-
|
|
103
|
+
|
|
104
104
|
@product.remote.should == "resource"
|
|
105
105
|
end
|
|
106
106
|
end
|
|
107
|
-
|
|
107
|
+
|
|
108
108
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,38 +1,23 @@
|
|
|
1
|
-
# Fake Rails constants
|
|
2
|
-
RAILS_ENV = ENV["RAILS_ENV"] ||= 'test'
|
|
3
|
-
RAILS_ROOT = File.dirname(__FILE__)
|
|
4
|
-
|
|
5
|
-
# Include required libraries
|
|
6
1
|
require 'rubygems'
|
|
7
|
-
require '
|
|
8
|
-
require 'active_resource'
|
|
9
|
-
require 'shoulda/active_record/matchers'
|
|
10
|
-
include Shoulda::ActiveRecord::Matchers
|
|
11
|
-
|
|
12
|
-
# Include plugin's files
|
|
13
|
-
require File.dirname(__FILE__) + '/../lib/has_remote'
|
|
14
|
-
require File.dirname(__FILE__) + '/../lib/has_remote/synchronizable'
|
|
15
|
-
require File.dirname(__FILE__) + '/../lib/has_remote/synchronization'
|
|
2
|
+
require 'bundler/setup'
|
|
16
3
|
|
|
17
4
|
# Initialize plugin
|
|
18
|
-
require "
|
|
5
|
+
require "rails"
|
|
6
|
+
Rails.env = ENV["RAILS_ENV"] ||= 'test'
|
|
7
|
+
require "shoulda-matchers"
|
|
8
|
+
require "active_record"
|
|
9
|
+
require "active_resource"
|
|
10
|
+
require "has_remote"
|
|
11
|
+
require "has_remote/railtie"
|
|
12
|
+
HasRemote::Railtie.load!
|
|
19
13
|
|
|
20
14
|
# Create logger
|
|
21
|
-
ActiveRecord::Base.logger =
|
|
15
|
+
ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(File.dirname(__FILE__) + "/debug.log")
|
|
22
16
|
|
|
23
17
|
# Setup database connection and structure
|
|
24
18
|
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
|
25
|
-
ActiveRecord::Base.establish_connection(config[
|
|
19
|
+
ActiveRecord::Base.establish_connection(config[Rails.env])
|
|
26
20
|
load(File.dirname(__FILE__) + "/schema.rb")
|
|
27
21
|
|
|
28
|
-
# Require models
|
|
29
|
-
|
|
30
|
-
require File.dirname(__FILE__) + '/has_remote_spec/book'
|
|
31
|
-
require File.dirname(__FILE__) + '/has_remote_spec/product'
|
|
32
|
-
require File.dirname(__FILE__) + '/has_remote_spec/cheese'
|
|
33
|
-
|
|
34
|
-
# Create schortcuts
|
|
35
|
-
User = HasRemoteSpec::User
|
|
36
|
-
Book = HasRemoteSpec::Book
|
|
37
|
-
Product = HasRemoteSpec::Product
|
|
38
|
-
Cheese = HasRemoteSpec::Cheese
|
|
22
|
+
# Require test models
|
|
23
|
+
Dir[File.join(File.dirname(__FILE__), "support", "**/*.rb")].each { |file| require file }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class Cheese < ActiveRecord::Base
|
|
2
|
+
validates_presence_of :maturity, :smell
|
|
3
|
+
has_remote :site => "http://dummy.local"
|
|
4
|
+
before_validation :set_smell, :on => :create
|
|
5
|
+
|
|
6
|
+
protected
|
|
7
|
+
|
|
8
|
+
def set_smell
|
|
9
|
+
self.smell = self.maturity * 10 if self.smell.nil?
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -10,10 +10,11 @@ describe HasRemote::Synchronization do
|
|
|
10
10
|
|
|
11
11
|
describe "named scope 'for'" do
|
|
12
12
|
before do
|
|
13
|
+
HasRemote::Synchronization.delete_all
|
|
13
14
|
@user_synchronization = HasRemote::Synchronization.create! :model_name => 'User', :last_record_updated_at => 1.day.ago, :last_record_id => 1
|
|
14
15
|
@book_synchronization = HasRemote::Synchronization.create! :model_name => 'Book', :last_record_updated_at => 1.day.ago, :last_record_id => 2
|
|
15
16
|
end
|
|
16
|
-
|
|
17
|
+
|
|
17
18
|
it "should return synchronization records scoped by model_name" do
|
|
18
19
|
HasRemote::Synchronization.for('User').should == [@user_synchronization]
|
|
19
20
|
end
|