poly_belongs_to 0.1.3 → 0.1.4
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.
- checksums.yaml +4 -4
- data/README.md +86 -16
- data/lib/poly_belongs_to.rb +57 -52
- data/lib/poly_belongs_to/dup.rb +43 -0
- data/lib/poly_belongs_to/hierarchy.rb +23 -0
- data/lib/poly_belongs_to/poly_belongs_to.rb +66 -0
- data/lib/poly_belongs_to/version.rb +1 -1
- data/test/dummy/Rakefile +1 -1
- data/test/dummy/app/models/address.rb +3 -0
- data/test/dummy/app/models/contact.rb +5 -0
- data/test/dummy/app/models/photo.rb +3 -0
- data/test/dummy/app/models/profile.rb +7 -0
- data/test/dummy/app/models/ssn.rb +3 -0
- data/test/dummy/app/models/user.rb +3 -1
- data/test/dummy/config.ru +1 -1
- data/test/dummy/config/application.rb +11 -1
- data/test/dummy/config/boot.rb +1 -0
- data/test/dummy/config/environment.rb +3 -3
- data/test/dummy/config/environments/development.rb +1 -1
- data/test/dummy/config/environments/production.rb +1 -1
- data/test/dummy/config/environments/test.rb +1 -1
- data/test/dummy/config/initializers/assets.rb +3 -3
- data/test/dummy/config/initializers/cookies_serializer.rb +1 -1
- data/test/dummy/config/initializers/filter_parameter_logging.rb +1 -1
- data/test/dummy/config/initializers/session_store.rb +1 -1
- data/test/dummy/config/routes.rb +1 -1
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20150211224139_create_users.rb +1 -0
- data/test/dummy/db/migrate/20150211224157_create_tags.rb +1 -0
- data/test/dummy/db/migrate/20150211224225_create_phones.rb +1 -0
- data/test/dummy/db/migrate/20150216092218_create_addresses.rb +10 -0
- data/test/dummy/db/migrate/20150216092338_create_profiles.rb +10 -0
- data/test/dummy/db/migrate/20150216092411_create_photos.rb +10 -0
- data/test/dummy/db/migrate/20150216092449_create_contacts.rb +11 -0
- data/test/dummy/db/migrate/20150216092519_create_ssns.rb +11 -0
- data/test/dummy/db/schema.rb +56 -5
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +50 -51
- data/test/dummy/log/test.log +49835 -1884
- data/test/dup_test.rb +39 -0
- data/test/fixtures/addresses.yml +18 -0
- data/test/fixtures/phones.yml +12 -3
- data/test/fixtures/photos.yml +16 -0
- data/test/fixtures/profiles.yml +15 -0
- data/test/fixtures/ssns.yml +14 -0
- data/test/fixtures/tags.yml +9 -2
- data/test/fixtures/users.yml +3 -1
- data/test/pbt_test.rb +61 -0
- data/test/poly_belongs_to_test.rb +75 -48
- data/test/test_helper.rb +13 -7
- metadata +58 -47
- data/test/dummy/app/assets/javascripts/application.js +0 -13
- data/test/dummy/app/assets/stylesheets/application.css +0 -15
- data/test/dummy/test/models/phone_test.rb +0 -7
- data/test/dummy/test/models/tag_test.rb +0 -7
- data/test/dummy/test/models/user_test.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 295e7bd5fc23bc91323e6bf9d8650e1e4b6f59ab
|
4
|
+
data.tar.gz: 9cfbad7a6779856a5950b7410737ee524b8ef29c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3421897cbce5956b73d3ff9339c2ec3755d36ed03c830eef435dce662e83f2ece03604b9bfa50357023267c66d7fb82dba76a0ac7845712dcaa76a1b8634b93
|
7
|
+
data.tar.gz: babae7be384227bb9ee4b181f08598d97b3963d926bae0da03a80d89ccb2758fccfbabdd07a1ca95b223a2c7bdb11e2a1cc705d7828fb0f9e1f1e2ad645a17c8
|
data/README.md
CHANGED
@@ -3,28 +3,15 @@
|
|
3
3
|
[](https://codeclimate.com/github/danielpclark/PolyBelongsTo)
|
4
4
|
[](https://travis-ci.org/danielpclark/PolyBelongsTo)
|
5
5
|
|
6
|
-
|
7
|
-
meta-programatically friendly way.
|
6
|
+
A standard way to check belongs_to relations on any belongs_to Object and let you check your DB Objects polymorphism in a more across-the-board meta-programatically friendly way.
|
8
7
|
|
9
8
|
#Installation
|
10
9
|
|
11
|
-
### Gem
|
12
|
-
|
13
10
|
Just include it in your Gemfile and then run bundle:
|
14
11
|
```ruby
|
15
12
|
gem 'poly_belongs_to'
|
16
13
|
```
|
17
14
|
|
18
|
-
###Merge via git
|
19
|
-
Be in your Rails project directory. Make sure you git is up to date with all your latest changes. Then:
|
20
|
-
|
21
|
-
```shell
|
22
|
-
git fetch git@github.com:danielpclark/PolyBelongsTo.git install:pbt
|
23
|
-
git merge pbt
|
24
|
-
```
|
25
|
-
|
26
|
-
And then enter a description for this merge into your project. Save the message, exit, and you're done!
|
27
|
-
|
28
15
|
##Recommended Usage
|
29
16
|
|
30
17
|
#####On model class
|
@@ -47,7 +34,6 @@ MyObject.pbt_params_name
|
|
47
34
|
MyObject.pbt_params_name(false)
|
48
35
|
# => :my_object
|
49
36
|
User.pbt_params_name
|
50
|
-
User.pbt_params_name
|
51
37
|
# => :user
|
52
38
|
|
53
39
|
# Polymorphic DB field names
|
@@ -101,8 +87,92 @@ MyObject.new.pbt_type_sym # nil for non polymorphic Objects
|
|
101
87
|
# => :my_objectable_type
|
102
88
|
```
|
103
89
|
|
90
|
+
##Internal Methods Available
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
# For cleaning attributs for use with build
|
94
|
+
PolyBelongsTo::Pbt::AttrSanitizer[ obj ]
|
95
|
+
|
96
|
+
# Returns string of either 'child.build' or 'build_child'
|
97
|
+
PolyBelongsTo::Pbt::BuildCmd[ obj, child ]
|
98
|
+
|
99
|
+
# Returns has_one and has_many relationships for obj as an Array of symbols
|
100
|
+
PolyBelongsTo::Pbt::Reflects[ obj ]
|
101
|
+
|
102
|
+
# Returns Class Ojects for each has_one and has_many child associations
|
103
|
+
PolyBelongsTo::Pbt::ReflectsAsClasses[ obj ]
|
104
|
+
|
105
|
+
# Boolean of whether child object/class is a has(one/many) relationship to obj
|
106
|
+
PolyBelongsTo::Pbt::IsReflected[ obj, child ]
|
107
|
+
|
108
|
+
# Returns :singular if obj->child is has_one and :plural if obj->child is has_many
|
109
|
+
PolyBelongsTo::Pbt::SingularOrPlural[ obj, child ]
|
110
|
+
|
111
|
+
# Returns true if obj->child relationship is has_one
|
112
|
+
PolyBelongsTo::Pbt::IsSingular[ obj, child ]
|
113
|
+
|
114
|
+
# Returns true if obj->child relationship is has_many
|
115
|
+
PolyBelongsTo::Pbt::IsPlural[ obj, child ]
|
116
|
+
|
117
|
+
# Returns the simbol for the CollectionProxy the child belongs to in relation to obj
|
118
|
+
PolyBelongsTo::Pbt::CollectionProxy[ obj, child ]
|
119
|
+
|
120
|
+
```
|
121
|
+
##Record Duplication
|
122
|
+
|
123
|
+
**This gives you the advantage of duplicating records regardless of polymorphic associations or
|
124
|
+
otherwise**. You can duplicate a record, or use a self recursive command **pbt_deep_dup_build**
|
125
|
+
to duplicate a record and all of it's has_one/has_many children records at once. Afterwards
|
126
|
+
be sure to use the save method.
|
127
|
+
|
128
|
+
> NOTE: This will need to be included manually. The reason for this is because you need to
|
129
|
+
know what's involved when using this. It's purposefully done this way to lead to reading
|
130
|
+
the documentation for PolyBelongsTo's duplication methods.
|
131
|
+
|
132
|
+
####Known Issues
|
133
|
+
- Carrierwave records won't duplicate. To ensure other records to still save and prevent
|
134
|
+
rollback use .save(validate: false) ... I'm considering possible options to remedy this and
|
135
|
+
other scenarios.
|
136
|
+
- For deep duplication you need to be very aware of the potential for infinite loops with
|
137
|
+
your records if there are any circular references.
|
138
|
+
|
139
|
+
###How To Use
|
140
|
+
|
141
|
+
Include it into ActiveRecord::Base in an initializer /config/initializers/poly_belongs_to.rb
|
142
|
+
```ruby
|
143
|
+
ActiveRecord::Base.send(:include, PolyBelongsTo::Dup)
|
144
|
+
```
|
145
|
+
Then use the dup/build methods as follows
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
# If you were to create a new contact for example
|
149
|
+
contact = User.first.contacts.new
|
150
|
+
|
151
|
+
# This is just like contact.profile.build( { ... user's profile attributes ... } )
|
152
|
+
contact.pbt_dup_build( User.last.profile )
|
153
|
+
|
154
|
+
# Save it!
|
155
|
+
contact.save
|
156
|
+
|
157
|
+
|
158
|
+
# For a fully recursive copy do the same with pbt_deep_dup_build
|
159
|
+
# Keep in mind this is vulnerable to infinite loops!
|
160
|
+
contact.pbt_deep_dup_build( User.last.profile )
|
161
|
+
|
162
|
+
# Remeber to save!
|
163
|
+
contact.save
|
164
|
+
```
|
165
|
+
|
166
|
+
##Planning
|
167
|
+
|
168
|
+
I'm in the process of planning mapping out record hierarchy. Also with this
|
169
|
+
it will add recognition for circular references.
|
170
|
+
|
171
|
+
##Contributing
|
172
|
+
|
173
|
+
Feel free to fork and make pull requests. Please bring up an issue before a pull
|
174
|
+
request if it's a non-fix change. Thank you!
|
104
175
|
|
105
|
-
And that's that!
|
106
176
|
|
107
177
|
#License
|
108
178
|
|
data/lib/poly_belongs_to.rb
CHANGED
@@ -3,79 +3,84 @@
|
|
3
3
|
# Copyright (C) 2015 by Daniel P. Clark
|
4
4
|
$: << File.join(File.dirname(__FILE__), "/poly_belongs_to")
|
5
5
|
require 'poly_belongs_to/version'
|
6
|
+
require 'poly_belongs_to/dup'
|
7
|
+
require 'poly_belongs_to/hierarchy'
|
8
|
+
require 'poly_belongs_to/poly_belongs_to'
|
6
9
|
require 'active_support/concern'
|
7
10
|
|
8
11
|
module PolyBelongsTo
|
9
|
-
|
12
|
+
module Core
|
13
|
+
extend ActiveSupport::Concern
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
|
15
|
+
included do
|
16
|
+
def self.pbt
|
17
|
+
reflect_on_all_associations(:belongs_to).first.try(:name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.poly?
|
21
|
+
!!reflect_on_all_associations(:belongs_to).first.try {|i| i.options[:polymorphic] }
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.pbt_params_name(allow_as_nested = true)
|
25
|
+
if poly?
|
26
|
+
allow_as_nested ? "#{table_name}_attributes".to_sym : name.downcase.to_sym
|
27
|
+
else
|
28
|
+
name.downcase.to_sym
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.pbt_id_sym
|
33
|
+
val = pbt
|
34
|
+
val ? "#{val}_id".to_sym : nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.pbt_type_sym
|
38
|
+
poly? ? "#{pbt}_type".to_sym : nil
|
39
|
+
end
|
14
40
|
end
|
15
41
|
|
16
|
-
def
|
17
|
-
|
42
|
+
def pbt
|
43
|
+
self.class.pbt
|
18
44
|
end
|
19
45
|
|
20
|
-
def
|
21
|
-
|
22
|
-
allow_as_nested ? "#{table_name}_attributes".to_sym : name.downcase.to_sym
|
23
|
-
else
|
24
|
-
name.downcase.to_sym
|
25
|
-
end
|
46
|
+
def poly?
|
47
|
+
self.class.poly?
|
26
48
|
end
|
27
49
|
|
28
|
-
def
|
50
|
+
def pbt_id
|
29
51
|
val = pbt
|
30
|
-
val ? "
|
52
|
+
val ? eval("self.#{val}_id") : nil
|
31
53
|
end
|
32
54
|
|
33
|
-
def
|
34
|
-
poly? ? "
|
55
|
+
def pbt_type
|
56
|
+
poly? ? eval("self.#{pbt}_type") : nil
|
35
57
|
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def pbt
|
39
|
-
self.class.pbt
|
40
|
-
end
|
41
58
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
def pbt_type
|
52
|
-
poly? ? eval("self.#{pbt}_type") : nil
|
53
|
-
end
|
54
|
-
|
55
|
-
def pbt_parent
|
56
|
-
val = pbt
|
57
|
-
if pbt
|
58
|
-
if poly?
|
59
|
-
eval "#{pbt_type}.find(#{pbt_id})"
|
59
|
+
def pbt_parent
|
60
|
+
val = pbt
|
61
|
+
if val
|
62
|
+
if poly?
|
63
|
+
eval "#{pbt_type}.find(#{pbt_id})"
|
64
|
+
else
|
65
|
+
eval "#{val.capitalize.to_s}.find(#{pbt_id})"
|
66
|
+
end
|
60
67
|
else
|
61
|
-
|
68
|
+
nil
|
62
69
|
end
|
63
|
-
else
|
64
|
-
nil
|
65
70
|
end
|
66
|
-
end
|
67
71
|
|
68
|
-
|
69
|
-
|
70
|
-
|
72
|
+
def pbt_id_sym
|
73
|
+
self.class.pbt_id_sym
|
74
|
+
end
|
71
75
|
|
72
|
-
|
73
|
-
|
74
|
-
|
76
|
+
def pbt_type_sym
|
77
|
+
self.class.pbt_type_sym
|
78
|
+
end
|
75
79
|
|
76
|
-
|
77
|
-
|
80
|
+
def pbt_params_name(allow_as_nested = true)
|
81
|
+
self.class.pbt_params_name(allow_as_nested)
|
82
|
+
end
|
78
83
|
end
|
79
84
|
end
|
80
85
|
|
81
|
-
ActiveRecord::Base.send(:include, PolyBelongsTo)
|
86
|
+
ActiveRecord::Base.send(:include, PolyBelongsTo::Core)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module PolyBelongsTo
|
2
|
+
module Dup
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
def self.pbt_dup_build(item_to_build_on, item_to_duplicate)
|
7
|
+
if PolyBelongsTo::Pbt::IsReflected[item_to_build_on, item_to_duplicate]
|
8
|
+
build_cmd = PolyBelongsTo::Pbt::BuildCmd[item_to_build_on, item_to_duplicate]
|
9
|
+
dup_attrs = PolyBelongsTo::Pbt::AttrSanitizer[item_to_duplicate]
|
10
|
+
|
11
|
+
build_cmd ? eval("item_to_build_on.#{build_cmd}(#{dup_attrs})") : nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.pbt_deep_dup_build(item_to_build_on, item_to_duplicate)
|
16
|
+
pbt_dup_build(item_to_build_on, item_to_duplicate)
|
17
|
+
PolyBelongsTo::Pbt::Reflects[item_to_duplicate].each do |ref|
|
18
|
+
child = eval("item_to_duplicate.#{ref}")
|
19
|
+
if child.respond_to?(:build)
|
20
|
+
child.each do |obj|
|
21
|
+
eval("item_to_build_on.#{PolyBelongsTo::Pbt::CollectionProxy[item_to_build_on, item_to_duplicate]}").
|
22
|
+
pbt_deep_dup_build(obj)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
eval("item_to_build_on.#{PolyBelongsTo::Pbt::CollectionProxy[item_to_build_on, item_to_duplicate]}").
|
26
|
+
pbt_deep_dup_build(child)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
item_to_build_on
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def pbt_dup_build(item_to_duplicate)
|
35
|
+
self.class.pbt_dup_build(self, item_to_duplicate)
|
36
|
+
end
|
37
|
+
|
38
|
+
def pbt_deep_dup_build(item_to_duplicate)
|
39
|
+
self.class.pbt_deep_dup_build(self, item_to_duplicate)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module PolyBelongsTo
|
2
|
+
module Hierarchy
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
def self.pbt_offspring(obj)
|
7
|
+
# planning phase
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.pbt_children(obj, kind)
|
11
|
+
# planning phase
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def pbt_offspring
|
16
|
+
self.class.pbt_offspring(self)
|
17
|
+
end
|
18
|
+
|
19
|
+
def pbt_children(kind)
|
20
|
+
self.class.pbt_children(self, kind)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module PolyBelongsTo
|
2
|
+
module Pbt
|
3
|
+
AttrSanitizer = lambda {|obj|
|
4
|
+
return {} unless obj
|
5
|
+
obj.dup.attributes.delete_if {|ky,vl|
|
6
|
+
[:created_at, :updated_at, :deleted_at, obj.pbt_id_sym, obj.pbt_type_sym].include? ky.to_sym
|
7
|
+
}
|
8
|
+
}
|
9
|
+
|
10
|
+
BuildCmd = lambda {|obj, child|
|
11
|
+
dup_name = "#{CollectionProxy[obj,child]}"
|
12
|
+
IsSingular[obj, child] ? "build_#{dup_name}" : IsPlural[obj, child] ? "#{dup_name}.build" : nil
|
13
|
+
}
|
14
|
+
|
15
|
+
Reflects = lambda {|obj|
|
16
|
+
[:has_one, :has_many].map { |has|
|
17
|
+
eval(obj.class.name).reflect_on_all_associations(has).map(&:name).map(&:to_sym)
|
18
|
+
}.flatten
|
19
|
+
}
|
20
|
+
|
21
|
+
ReflectsAsClasses = lambda {|obj|
|
22
|
+
Reflects[obj].map {|ref|
|
23
|
+
eval (eval("obj.#{ref}").try(:klass) || eval("obj.#{ref}").class).name
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
IsReflected = lambda {|obj,child|
|
28
|
+
!!SingularOrPlural[obj, child]
|
29
|
+
}
|
30
|
+
|
31
|
+
SingularOrPlural = lambda {|obj, child|
|
32
|
+
reflects = Reflects[obj]
|
33
|
+
if reflects.include?(ActiveModel::Naming.singular(child).to_sym)
|
34
|
+
:singular
|
35
|
+
elsif reflects.include?(ActiveModel::Naming.plural(child).to_sym)
|
36
|
+
:plural
|
37
|
+
else
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
}
|
41
|
+
|
42
|
+
IsSingular = lambda {|obj, child|
|
43
|
+
eval(obj.class.name).reflect_on_all_associations(:has_one).
|
44
|
+
map(&:name).map(&:to_sym).include? ActiveModel::Naming.singular(child).to_sym
|
45
|
+
}
|
46
|
+
|
47
|
+
IsPlural = lambda {|obj,child|
|
48
|
+
eval(obj.class.name).reflect_on_all_associations(:has_many).
|
49
|
+
map(&:name).map(&:to_sym).include? ActiveModel::Naming.plural(child).to_sym
|
50
|
+
}
|
51
|
+
|
52
|
+
CollectionProxy = lambda {|obj, child|
|
53
|
+
reflects = Reflects[obj]
|
54
|
+
proxy = ActiveModel::Naming.singular(child).to_sym
|
55
|
+
if reflects.include? proxy
|
56
|
+
return proxy
|
57
|
+
end
|
58
|
+
proxy = ActiveModel::Naming.plural(child).to_sym
|
59
|
+
if reflects.include? proxy
|
60
|
+
proxy
|
61
|
+
else
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
data/test/dummy/Rakefile
CHANGED