remote_association 0.0.1 → 0.0.2
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/.gitignore +2 -1
- data/.travis.yml +14 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +3 -10
- data/README.md +3 -0
- data/lib/remote_association/active_record/relation.rb +29 -4
- data/lib/remote_association/belongs_to_remote.rb +67 -0
- data/lib/remote_association/has_one_remote.rb +66 -0
- data/lib/remote_association/version.rb +1 -1
- data/lib/remote_association.rb +5 -60
- data/spec/remote_association/belongs_to_remote_spec.rb +70 -0
- data/spec/remote_association/has_one_remote_spec.rb +67 -0
- data/spec/remote_association/remote_association_spec.rb +7 -52
- data/spec/spec_helper.rb +12 -0
- data/spec/tasks/db_setup.rake +12 -0
- metadata +15 -2
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
remote_association (0.0.
|
4
|
+
remote_association (0.0.2)
|
5
5
|
activerecord (~> 3.2)
|
6
6
|
activeresource (~> 3.2)
|
7
7
|
activesupport (~> 3.2)
|
@@ -25,20 +25,13 @@ GEM
|
|
25
25
|
multi_json (~> 1.0)
|
26
26
|
arel (3.0.2)
|
27
27
|
builder (3.0.0)
|
28
|
-
columnize (0.3.6)
|
29
28
|
database_cleaner (0.8.0)
|
30
|
-
debugger (1.2.0)
|
31
|
-
columnize (>= 0.3.1)
|
32
|
-
debugger-linecache (~> 1.1.1)
|
33
|
-
debugger-ruby_core_source (~> 1.1.3)
|
34
|
-
debugger-linecache (1.1.2)
|
35
|
-
debugger-ruby_core_source (>= 1.1.1)
|
36
|
-
debugger-ruby_core_source (1.1.3)
|
37
29
|
diff-lcs (1.1.3)
|
38
30
|
fakeweb (1.3.0)
|
39
31
|
i18n (0.6.0)
|
40
32
|
multi_json (1.3.6)
|
41
33
|
pg (0.14.0)
|
34
|
+
rake (0.9.2.2)
|
42
35
|
rspec (2.11.0)
|
43
36
|
rspec-core (~> 2.11.0)
|
44
37
|
rspec-expectations (~> 2.11.0)
|
@@ -54,8 +47,8 @@ PLATFORMS
|
|
54
47
|
|
55
48
|
DEPENDENCIES
|
56
49
|
database_cleaner (~> 0.8)
|
57
|
-
debugger
|
58
50
|
fakeweb
|
59
51
|
pg (~> 0.14)
|
52
|
+
rake
|
60
53
|
remote_association!
|
61
54
|
rspec (~> 2.11)
|
data/README.md
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
[](http://travis-ci.org/denyago/remote_association)
|
2
|
+
[](https://codeclimate.com/github/denyago/remote_association)
|
3
|
+
|
1
4
|
# Remote Association
|
2
5
|
|
3
6
|
Add ```has_``` and ```belongs_``` associations to models inherited from ActiveResource::Base
|
@@ -12,8 +12,6 @@ module ActiveRecord
|
|
12
12
|
#
|
13
13
|
# Author.scoped.includes_remote(:profile, :avatar)
|
14
14
|
def includes_remote(*args)
|
15
|
-
keys = self.uniq.pluck(:id)
|
16
|
-
|
17
15
|
args.each do |r|
|
18
16
|
settings = klass.activeresource_relations[r.to_sym]
|
19
17
|
raise RemoteAssociation::SettingsNotFoundError, "Can't find settings for #{r} association" if settings.blank?
|
@@ -22,15 +20,42 @@ module ActiveRecord
|
|
22
20
|
foregin_key = settings[:foreign_key]
|
23
21
|
ar_class = settings[:class_name ].constantize
|
24
22
|
|
23
|
+
fetch_and_join_for_has_one_remote(ar_accessor, foregin_key, ar_class) if settings[:association_type] == :has_one_remote
|
24
|
+
fetch_and_join_for_belongs_to_remote(ar_accessor, foregin_key, ar_class) if settings[:association_type] == :belongs_to_remote
|
25
|
+
end
|
26
|
+
|
27
|
+
set_remote_resources_prefetched
|
28
|
+
|
29
|
+
self.all
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def fetch_and_join_for_has_one_remote(ar_accessor, foregin_key, ar_class)
|
35
|
+
keys = self.uniq.pluck(:id)
|
36
|
+
|
25
37
|
remote_objects = ar_class.find(:all, :params => { foregin_key => keys })
|
26
38
|
|
27
39
|
self.each do |u|
|
28
40
|
u.send("#{ar_accessor}=", remote_objects.select {|s| s.send(foregin_key) == u.id })
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def fetch_and_join_for_belongs_to_remote(ar_accessor, foregin_key, ar_class)
|
45
|
+
keys = self.uniq.pluck(foregin_key.to_sym)
|
46
|
+
|
47
|
+
remote_objects = ar_class.find(:all, :params => { :id => keys })
|
48
|
+
|
49
|
+
self.each do |u|
|
50
|
+
u.send("#{ar_accessor}=", remote_objects.select {|s| u.send(foregin_key) == s.id })
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_remote_resources_prefetched
|
55
|
+
self.each do |u|
|
29
56
|
u.instance_variable_set(:@remote_resources_prefetched, true)
|
30
57
|
end
|
31
58
|
end
|
32
59
|
|
33
|
-
self.all
|
34
|
-
end
|
35
60
|
end
|
36
61
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module RemoteAssociation
|
2
|
+
module BelongsToRemote
|
3
|
+
# Specifies a one-to-one association with another class. This method should only be used
|
4
|
+
# if this class contains the foreign key. If the other class contains the foreign key,
|
5
|
+
# then you should use +has_one_remote+ instead.
|
6
|
+
#
|
7
|
+
# Methods will be added for retrieval and query for a single associated object, for which
|
8
|
+
# this object holds an id:
|
9
|
+
#
|
10
|
+
# [association]
|
11
|
+
# Returns the associated object. +nil+ is returned if none is found.
|
12
|
+
# [association=(associate)]
|
13
|
+
# Just setter, no saves.
|
14
|
+
#
|
15
|
+
# (+association+ is replaced with the symbol passed as the first argument, so
|
16
|
+
# <tt>belongs_to_remote :author</tt> would add among others <tt>author.nil?</tt>.)
|
17
|
+
#
|
18
|
+
# === Example
|
19
|
+
#
|
20
|
+
# A Post class declares <tt>belongs_to_remote :author</tt>, which will add:
|
21
|
+
# * <tt>Post#author</tt> (similar to <tt>Author.find(:first, params: { id: [post.author_id]})</tt>)
|
22
|
+
# * <tt>Post#author=(author)</tt> (will set @author instance variable of Post# to author value)
|
23
|
+
# The declaration can also include an options hash to specialize the behavior of the association.
|
24
|
+
#
|
25
|
+
# === Options
|
26
|
+
#
|
27
|
+
# [:class_name]
|
28
|
+
# Specify the class name of the association. Use it only if that name can't be inferred
|
29
|
+
# from the association name. So <tt>belongs_to_remote :author</tt> will by default be linked to the Author class, but
|
30
|
+
# if the real class name is Person, you'll have to specify it with this option.
|
31
|
+
# [:foreign_key]
|
32
|
+
# Specify the foreign key used for the association. By default this is guessed to be the name
|
33
|
+
# of the association with an "_id" suffix. So a class that defines a <tt>belongs_to_remote :person</tt>
|
34
|
+
# association will use "person_id" as the default <tt>:foreign_key</tt>. Similarly,
|
35
|
+
# <tt>belongs_to_remote :favorite_person, :class_name => "Person"</tt> will use a foreign key
|
36
|
+
# of "favorite_person_id".
|
37
|
+
#
|
38
|
+
# Option examples:
|
39
|
+
# belongs_to :firm, :foreign_key => "client_of"
|
40
|
+
# belongs_to :author, :class_name => "Person", :foreign_key => "author_id"
|
41
|
+
def belongs_to_remote(remote_rel, options ={})
|
42
|
+
rel_options = {
|
43
|
+
class_name: remote_rel.to_s.classify,
|
44
|
+
foreign_key: remote_rel.to_s.foreign_key,
|
45
|
+
association_type: :belongs_to_remote
|
46
|
+
}.merge(options.symbolize_keys)
|
47
|
+
|
48
|
+
add_activeresource_relation(remote_rel.to_sym, rel_options)
|
49
|
+
|
50
|
+
class_eval <<-RUBY, __FILE__, __LINE__+1
|
51
|
+
|
52
|
+
attr_accessor :#{remote_rel}
|
53
|
+
|
54
|
+
def #{remote_rel}
|
55
|
+
if remote_resources_prefetched?
|
56
|
+
@#{remote_rel} ? @#{remote_rel}.first : nil
|
57
|
+
else
|
58
|
+
@#{remote_rel} ||= #{rel_options[:class_name]}.find(:first, params: { id: [self.#{rel_options[:foreign_key]}]})
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
RUBY
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module RemoteAssociation
|
2
|
+
module HasOneRemote
|
3
|
+
# Specifies a one-to-one association with another class. This method should only be used
|
4
|
+
# if this class is a kind of ActiveResource::Base and service for this resource can
|
5
|
+
# return some kind of foreign key.
|
6
|
+
#
|
7
|
+
# Methods will be added for retrieval and query for a single associated object, for which
|
8
|
+
# this object holds an id:
|
9
|
+
#
|
10
|
+
# [association()]
|
11
|
+
# Returns the associated object. +nil+ is returned if none is found.
|
12
|
+
# [association=(associate)]
|
13
|
+
# Just setter, no saves.
|
14
|
+
#
|
15
|
+
# (+association+ is replaced with the symbol passed as the first argument, so
|
16
|
+
# <tt>has_one_remote :author</tt> would add among others <tt>author.nil?</tt>.)
|
17
|
+
#
|
18
|
+
# === Example
|
19
|
+
#
|
20
|
+
# A Author class declares <tt>has_one_remote :profile</tt>, which will add:
|
21
|
+
# * <tt>Authort#profile</tt> (similar to <tt>Profile.find(:first, params: { author_id: [author.id]})</tt>)
|
22
|
+
# * <tt>Author#profile=(profile)</tt> (will set @profile instance variable of Author# to profile value)
|
23
|
+
# The declaration can also include an options hash to specialize the behavior of the association.
|
24
|
+
#
|
25
|
+
# === Options
|
26
|
+
#
|
27
|
+
# [:class_name]
|
28
|
+
# Specify the class name of the association. Use it only if that name can't be inferred
|
29
|
+
# from the association name. So <tt>has_one_remote :profile</tt> will by default be linked to the Profile class, but
|
30
|
+
# if the real class name is SocialProfile, you'll have to specify it with this option.
|
31
|
+
# [:foreign_key]
|
32
|
+
# Specify the foreign key used for searching association on remote service. By default this is guessed to be the name
|
33
|
+
# of the current class with an "_id" suffix. So a class Author that defines a <tt>has_one_remote :profile</tt>
|
34
|
+
# association will use "author_id" as the default <tt>:foreign_key</tt>.
|
35
|
+
# This key will be used in :get request. Example: <tt>GET http://example.com/profiles?author_id[]=1</tt>
|
36
|
+
#
|
37
|
+
# Option examples:
|
38
|
+
# has_one_remote :firm, :foreign_key => "client_of"
|
39
|
+
# has_one_remote :author, :class_name => "Person", :foreign_key => "author_id"
|
40
|
+
def has_one_remote(remote_rel, options ={})
|
41
|
+
rel_options = {
|
42
|
+
class_name: remote_rel.to_s.classify,
|
43
|
+
foreign_key: self.model_name.to_s.foreign_key,
|
44
|
+
association_type: :has_one_remote
|
45
|
+
}.merge(options.symbolize_keys)
|
46
|
+
|
47
|
+
add_activeresource_relation(remote_rel.to_sym, rel_options)
|
48
|
+
|
49
|
+
class_eval <<-RUBY, __FILE__, __LINE__+1
|
50
|
+
|
51
|
+
attr_accessor :#{remote_rel}
|
52
|
+
|
53
|
+
def #{remote_rel}
|
54
|
+
if remote_resources_prefetched?
|
55
|
+
@#{remote_rel} ? @#{remote_rel}.first : nil
|
56
|
+
else
|
57
|
+
@#{remote_rel} ||= #{rel_options[:class_name]}.find(:first, params: { #{rel_options[:foreign_key]}: [self.id]})
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
RUBY
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
data/lib/remote_association.rb
CHANGED
@@ -2,9 +2,12 @@ require "active_record"
|
|
2
2
|
require "active_support"
|
3
3
|
|
4
4
|
require "remote_association/version"
|
5
|
+
require "remote_association/has_one_remote"
|
6
|
+
require "remote_association/belongs_to_remote"
|
5
7
|
require "remote_association/active_record/relation"
|
6
8
|
|
7
9
|
module RemoteAssociation
|
10
|
+
|
8
11
|
# Include this class to hav associations to ActiveResource models
|
9
12
|
#
|
10
13
|
# It will add methods to your class:
|
@@ -21,66 +24,8 @@ module RemoteAssociation
|
|
21
24
|
end
|
22
25
|
|
23
26
|
module ClassMethods
|
24
|
-
|
25
|
-
|
26
|
-
# return some kind of foreign key.
|
27
|
-
#
|
28
|
-
# Methods will be added for retrieval and query for a single associated object, for which
|
29
|
-
# this object holds an id:
|
30
|
-
#
|
31
|
-
# [association()]
|
32
|
-
# Returns the associated object. +nil+ is returned if none is found.
|
33
|
-
# [association=(associate)]
|
34
|
-
# Just setter, no saves.
|
35
|
-
#
|
36
|
-
# (+association+ is replaced with the symbol passed as the first argument, so
|
37
|
-
# <tt>has_one_remote :author</tt> would add among others <tt>author.nil?</tt>.)
|
38
|
-
#
|
39
|
-
# === Example
|
40
|
-
#
|
41
|
-
# A Author class declares <tt>has_one_remote :profile</tt>, which will add:
|
42
|
-
# * <tt>Authort#profile</tt> (similar to <tt>Profile.find(:first, params: { author_id: [author.id]})</tt>)
|
43
|
-
# * <tt>Author#profile=(profile)</tt> (will set @profile instance variable of Author# to profile value)
|
44
|
-
# The declaration can also include an options hash to specialize the behavior of the association.
|
45
|
-
#
|
46
|
-
# === Options
|
47
|
-
#
|
48
|
-
# [:class_name]
|
49
|
-
# Specify the class name of the association. Use it only if that name can't be inferred
|
50
|
-
# from the association name. So <tt>has_one_remote :profile</tt> will by default be linked to the Profile class, but
|
51
|
-
# if the real class name is SocialProfile, you'll have to specify it with this option.
|
52
|
-
# [:foreign_key]
|
53
|
-
# Specify the foreign key used for searching association on remote service. By default this is guessed to be the name
|
54
|
-
# of the current class with an "_id" suffix. So a class Author that defines a <tt>has_one_remote :profile</tt>
|
55
|
-
# association will use "author_id" as the default <tt>:foreign_key</tt>.
|
56
|
-
# This key will be used in :get request. Example: <tt>GET http://example.com/profiles?author_id[]=1</tt>
|
57
|
-
#
|
58
|
-
# Option examples:
|
59
|
-
# has_one_remote :firm, :foreign_key => "client_of"
|
60
|
-
# has_one_remote :author, :class_name => "Person", :foreign_key => "author_id"
|
61
|
-
def has_one_remote(remote_rel, options ={})
|
62
|
-
rel_options = {
|
63
|
-
class_name: remote_rel.to_s.classify,
|
64
|
-
foreign_key: self.model_name.to_s.foreign_key
|
65
|
-
}.merge(options.symbolize_keys)
|
66
|
-
|
67
|
-
add_activeresource_relation(remote_rel.to_sym, rel_options)
|
68
|
-
|
69
|
-
class_eval <<-RUBY, __FILE__, __LINE__+1
|
70
|
-
|
71
|
-
attr_accessor :#{remote_rel}
|
72
|
-
|
73
|
-
def #{remote_rel}
|
74
|
-
if remote_resources_prefetched?
|
75
|
-
@#{remote_rel} ? @#{remote_rel}.first : nil
|
76
|
-
else
|
77
|
-
@#{remote_rel} ||= #{rel_options[:class_name]}.find(:first, params: { #{rel_options[:foreign_key]}: [self.id]})
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
RUBY
|
82
|
-
|
83
|
-
end
|
27
|
+
include RemoteAssociation::HasOneRemote
|
28
|
+
include RemoteAssociation::BelongsToRemote
|
84
29
|
|
85
30
|
# Adds settings of relation to ActiveResource model.
|
86
31
|
#
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RemoteAssociation, "method :belongs_to_remote" do
|
4
|
+
before(:all) do
|
5
|
+
unset_const(:User)
|
6
|
+
class User < ActiveResource::Base
|
7
|
+
self.site = REMOTE_HOST
|
8
|
+
self.element_name = "user"
|
9
|
+
end
|
10
|
+
@body = [{user: {id: 1, name: "User A"}}].to_json
|
11
|
+
@full_body = [
|
12
|
+
{user: {id: 1, name: "User A"}},
|
13
|
+
{user: {id: 2, name: "User B"}}
|
14
|
+
].to_json
|
15
|
+
end
|
16
|
+
|
17
|
+
before(:each) do
|
18
|
+
add_profile(1, 1, "letter A")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "uses it's defaults" do
|
22
|
+
unset_const(:Profile)
|
23
|
+
class Profile < ActiveRecord::Base
|
24
|
+
include RemoteAssociation::Base
|
25
|
+
belongs_to_remote :user
|
26
|
+
end
|
27
|
+
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/users.json?id%5B%5D=1", body: @body )
|
28
|
+
|
29
|
+
Profile.first.user.name.should eq('User A')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should prefetch remote associations of models with defaults (single request)' do
|
33
|
+
add_profile(2, 2, "letter B")
|
34
|
+
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/users.json?id%5B%5D=1&id%5B%5D=2", body: @full_body)
|
35
|
+
|
36
|
+
profiles = Profile.scoped.includes_remote(:user)
|
37
|
+
profiles.first.user.name.should eq('User A')
|
38
|
+
profiles.last.user.name.should eq('User B')
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "has options:" do
|
42
|
+
it ":class_name - able to choose custom class of association" do
|
43
|
+
unset_const(:Profile)
|
44
|
+
unset_const(:CustomUser)
|
45
|
+
class CustomUser < ActiveResource::Base
|
46
|
+
self.site = REMOTE_HOST
|
47
|
+
self.element_name = "user"
|
48
|
+
end
|
49
|
+
class Profile < ActiveRecord::Base
|
50
|
+
include RemoteAssociation::Base
|
51
|
+
belongs_to_remote :user, class_name: "CustomUser"
|
52
|
+
end
|
53
|
+
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/users.json?id%5B%5D=1", body: @body )
|
54
|
+
end
|
55
|
+
it ":foreign_key - can set key to extract from it's model" do
|
56
|
+
unset_const(:Profile)
|
57
|
+
class Profile < ActiveRecord::Base
|
58
|
+
include RemoteAssociation::Base
|
59
|
+
belongs_to_remote :user, foreign_key: :login_id
|
60
|
+
def login_id; user_id; end
|
61
|
+
end
|
62
|
+
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/users.json?id%5B%5D=1", body: @body)
|
63
|
+
end
|
64
|
+
after(:each) do
|
65
|
+
Profile.first.user.name.should eq('User A')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RemoteAssociation, "method :has_one_remote" do
|
4
|
+
before(:all) do
|
5
|
+
@body = [{profile: {id: 1, user_id: 1, like: "letter A"}}].to_json
|
6
|
+
@full_body = [
|
7
|
+
{profile: {id: 1, user_id: 1, like: "letter A"}},
|
8
|
+
{profile: {id: 2, user_id: 2, like: "letter B"}}
|
9
|
+
].to_json
|
10
|
+
end
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
unset_const(:User)
|
14
|
+
unset_const(:Profile)
|
15
|
+
class User < ActiveRecord::Base
|
16
|
+
include RemoteAssociation::Base
|
17
|
+
has_one_remote :profile
|
18
|
+
end
|
19
|
+
class Profile < ActiveResource::Base
|
20
|
+
self.site = REMOTE_HOST
|
21
|
+
end
|
22
|
+
|
23
|
+
add_user(1,"User A")
|
24
|
+
add_user(2,"User B")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "uses it's defaults" do
|
28
|
+
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/profiles.json?user_id%5B%5D=1", body: @body )
|
29
|
+
|
30
|
+
User.first.profile.like.should eq('letter A')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should prefetch remote associations of models with defaults (single request)' do
|
34
|
+
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/profiles.json?user_id%5B%5D=1&user_id%5B%5D=2", body: @full_body)
|
35
|
+
|
36
|
+
users = User.scoped.includes_remote(:profile)
|
37
|
+
users.first.profile.like.should eq('letter A')
|
38
|
+
users.last.profile.like.should eq('letter B')
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "has options:" do
|
42
|
+
it ":class_name - able to choose custom class of association" do
|
43
|
+
unset_const(:User)
|
44
|
+
unset_const(:CustomProfile)
|
45
|
+
class CustomProfile < ActiveResource::Base
|
46
|
+
self.site = REMOTE_HOST
|
47
|
+
self.element_name = "profile"
|
48
|
+
end
|
49
|
+
class User < ActiveRecord::Base
|
50
|
+
include RemoteAssociation::Base
|
51
|
+
has_one_remote :profile, class_name: "CustomProfile"
|
52
|
+
end
|
53
|
+
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/profiles.json?user_id%5B%5D=1", body: @body )
|
54
|
+
end
|
55
|
+
it ":foreign_key - can set uri param for search" do
|
56
|
+
unset_const(:User)
|
57
|
+
class User < ActiveRecord::Base
|
58
|
+
include RemoteAssociation::Base
|
59
|
+
has_one_remote :profile, foreign_key: :login_id
|
60
|
+
end
|
61
|
+
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/profiles.json?login_id%5B%5D=1", body: @body)
|
62
|
+
end
|
63
|
+
after(:each) do
|
64
|
+
User.first.profile.like.should eq('letter A')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -2,14 +2,14 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe RemoteAssociation do
|
4
4
|
before(:all) do
|
5
|
-
|
6
|
-
PROFILES_JSON = [
|
5
|
+
@profiles_json = [
|
7
6
|
{profile: {id: 1, user_id: 1, like: "letter A"}},
|
8
7
|
{profile: {id: 2, user_id: 2, like: "letter B"}}
|
9
8
|
]
|
10
9
|
end
|
11
|
-
|
12
10
|
before(:each) do
|
11
|
+
unset_const(:Profile)
|
12
|
+
unset_const(:User)
|
13
13
|
class Profile < ActiveResource::Base
|
14
14
|
self.site = REMOTE_HOST
|
15
15
|
end
|
@@ -22,19 +22,13 @@ describe RemoteAssociation do
|
|
22
22
|
add_user(2,"User B")
|
23
23
|
end
|
24
24
|
|
25
|
-
it 'should prefetch remote associations of models with defaults (single request)' do
|
26
|
-
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/profiles.json?user_id%5B%5D=1&user_id%5B%5D=2", body: PROFILES_JSON.to_json)
|
27
|
-
|
28
|
-
users = User.scoped.includes_remote(:profile)
|
29
|
-
users.first.profile.like.should eq('letter A')
|
30
|
-
users.last.profile.like.should eq('letter B')
|
31
|
-
end
|
32
|
-
|
33
25
|
it 'should raise error if can\'t find settings for included remote' do
|
34
26
|
lambda{ User.scoped.includes_remote(:whatever) }.should raise_error(RemoteAssociation::SettingsNotFoundError, "Can't find settings for whatever association")
|
35
27
|
end
|
36
28
|
|
37
29
|
it 'should prefetch remote associations of models, passed as args of includes_remote' do
|
30
|
+
unset_const(:OtherProfile)
|
31
|
+
unset_const(:User)
|
38
32
|
class OtherProfile < ActiveResource::Base
|
39
33
|
self.site = REMOTE_HOST
|
40
34
|
self.element_name = "profile"
|
@@ -45,8 +39,8 @@ describe RemoteAssociation do
|
|
45
39
|
has_one_remote :other_profile
|
46
40
|
end
|
47
41
|
|
48
|
-
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/other_profiles.json?user_id%5B%5D=1&user_id%5B%5D=2", body:
|
49
|
-
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/profiles.json?user_id%5B%5D=1&user_id%5B%5D=2", body:
|
42
|
+
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/other_profiles.json?user_id%5B%5D=1&user_id%5B%5D=2", body: @profiles_json.to_json)
|
43
|
+
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/profiles.json?user_id%5B%5D=1&user_id%5B%5D=2", body: @profiles_json.to_json)
|
50
44
|
|
51
45
|
users = User.scoped.includes_remote(:profile, :other_profile)
|
52
46
|
users.first.profile.like.should eq('letter A')
|
@@ -55,43 +49,4 @@ describe RemoteAssociation do
|
|
55
49
|
users.last.other_profile.like.should eq('letter B')
|
56
50
|
end
|
57
51
|
|
58
|
-
it 'should autoload remote associations of each models without prefetching (1+N requiests)' do
|
59
|
-
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/profiles.json?user_id%5B%5D=1", body: [PROFILES_JSON.first].to_json)
|
60
|
-
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/profiles.json?user_id%5B%5D=2", body: [PROFILES_JSON.last].to_json)
|
61
|
-
|
62
|
-
users = User.scoped
|
63
|
-
users.first.profile.like.should eq('letter A')
|
64
|
-
users.last.profile.like.should eq('letter B')
|
65
|
-
end
|
66
|
-
|
67
|
-
describe "method :has_one_remote with options:" do
|
68
|
-
before(:each) do
|
69
|
-
@body = [PROFILES_JSON.first].to_json
|
70
|
-
end
|
71
|
-
it ":class_name - able to choose custom class of association" do
|
72
|
-
class CustomProfile < ActiveResource::Base
|
73
|
-
self.site = REMOTE_HOST
|
74
|
-
self.element_name = "profile"
|
75
|
-
end
|
76
|
-
class User < ActiveRecord::Base
|
77
|
-
include RemoteAssociation::Base
|
78
|
-
has_one_remote :profile, class_name: "CustomProfile"
|
79
|
-
end
|
80
|
-
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/profiles.json?user_id%5B%5D=1", body: @body )
|
81
|
-
end
|
82
|
-
it ":foreign_key - can set uri param for search" do
|
83
|
-
class CustomProfile < ActiveResource::Base
|
84
|
-
self.site = REMOTE_HOST
|
85
|
-
self.element_name = "profile"
|
86
|
-
end
|
87
|
-
class User < ActiveRecord::Base
|
88
|
-
include RemoteAssociation::Base
|
89
|
-
has_one_remote :profile, foreign_key: :login_id
|
90
|
-
end
|
91
|
-
FakeWeb.register_uri(:get, "#{REMOTE_HOST}/profiles.json?login_id%5B%5D=1", body: @body)
|
92
|
-
end
|
93
|
-
after(:each) do
|
94
|
-
User.first.profile.like.should eq('letter A')
|
95
|
-
end
|
96
|
-
end
|
97
52
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -36,3 +36,15 @@ ActiveRecord::Base.establish_connection(db_config)
|
|
36
36
|
def add_user(id, name)
|
37
37
|
ActiveRecord::Base.connection.execute("insert into \"public\".\"users\" (\"id\", \"name\") values ( #{id}, '#{name}');")
|
38
38
|
end
|
39
|
+
|
40
|
+
def add_profile(id, user_id, like)
|
41
|
+
ActiveRecord::Base.connection.execute("insert into \"public\".\"profiles\" (\"id\", \"user_id\", \"like\") values ( #{id}, #{user_id}, '#{like}');")
|
42
|
+
end
|
43
|
+
|
44
|
+
REMOTE_HOST = "http://127.0.0.1:3000"
|
45
|
+
|
46
|
+
def unset_const(const_name)
|
47
|
+
const_name = const_name.to_sym
|
48
|
+
const_owner = Module.constants.select { |c| c.to_s.constantize.constants(false).include?(const_name) rescue false }.first.to_s.constantize
|
49
|
+
!const_owner.send(:remove_const, const_name) rescue true
|
50
|
+
end
|
data/spec/tasks/db_setup.rake
CHANGED
@@ -24,6 +24,18 @@ CREATE TABLE "public"."users" (
|
|
24
24
|
)
|
25
25
|
WITH (OIDS=FALSE);
|
26
26
|
ALTER TABLE "public"."users" OWNER TO "rails";
|
27
|
+
|
28
|
+
DROP TABLE IF EXISTS "public"."profiles";
|
29
|
+
|
30
|
+
CREATE TABLE "public"."profiles" (
|
31
|
+
"id" int4 NOT NULL,
|
32
|
+
"user_id" int4 NOT NULL,
|
33
|
+
"like" varchar(255) NOT NULL,
|
34
|
+
CONSTRAINT "profiles_pkey" PRIMARY KEY ("id") NOT DEFERRABLE INITIALLY IMMEDIATE
|
35
|
+
)
|
36
|
+
WITH (OIDS=FALSE);
|
37
|
+
ALTER TABLE "public"."profiles" OWNER TO "rails";
|
38
|
+
|
27
39
|
SQL
|
28
40
|
)
|
29
41
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: remote_association
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-08-
|
12
|
+
date: 2012-08-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -132,6 +132,7 @@ extra_rdoc_files: []
|
|
132
132
|
files:
|
133
133
|
- .gitignore
|
134
134
|
- .rvmrc
|
135
|
+
- .travis.yml
|
135
136
|
- Gemfile
|
136
137
|
- Gemfile.lock
|
137
138
|
- LICENSE
|
@@ -139,9 +140,13 @@ files:
|
|
139
140
|
- Rakefile
|
140
141
|
- lib/remote_association.rb
|
141
142
|
- lib/remote_association/active_record/relation.rb
|
143
|
+
- lib/remote_association/belongs_to_remote.rb
|
144
|
+
- lib/remote_association/has_one_remote.rb
|
142
145
|
- lib/remote_association/version.rb
|
143
146
|
- remote_association.gemspec
|
144
147
|
- spec/config/database.example.yml
|
148
|
+
- spec/remote_association/belongs_to_remote_spec.rb
|
149
|
+
- spec/remote_association/has_one_remote_spec.rb
|
145
150
|
- spec/remote_association/remote_association_spec.rb
|
146
151
|
- spec/spec_helper.rb
|
147
152
|
- spec/tasks/db_setup.rake
|
@@ -157,12 +162,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
157
162
|
- - ! '>='
|
158
163
|
- !ruby/object:Gem::Version
|
159
164
|
version: '0'
|
165
|
+
segments:
|
166
|
+
- 0
|
167
|
+
hash: 3408694101896139864
|
160
168
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
169
|
none: false
|
162
170
|
requirements:
|
163
171
|
- - ! '>='
|
164
172
|
- !ruby/object:Gem::Version
|
165
173
|
version: '0'
|
174
|
+
segments:
|
175
|
+
- 0
|
176
|
+
hash: 3408694101896139864
|
166
177
|
requirements: []
|
167
178
|
rubyforge_project:
|
168
179
|
rubygems_version: 1.8.24
|
@@ -171,6 +182,8 @@ specification_version: 3
|
|
171
182
|
summary: Adds relations to ActiveResource models
|
172
183
|
test_files:
|
173
184
|
- spec/config/database.example.yml
|
185
|
+
- spec/remote_association/belongs_to_remote_spec.rb
|
186
|
+
- spec/remote_association/has_one_remote_spec.rb
|
174
187
|
- spec/remote_association/remote_association_spec.rb
|
175
188
|
- spec/spec_helper.rb
|
176
189
|
- spec/tasks/db_setup.rake
|