acts_has_many 0.3.0 → 0.3.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 899f42f7868ed45b0eb22bdd0e56d3cf4a2385af
4
+ data.tar.gz: 95a0effdaf788f947e92fabea3dec9e7a51e219d
5
+ SHA512:
6
+ metadata.gz: 724009b91d5dee328d7eca99829c8212a31a778f29132cad80aa0f6aebbf4bb3e501e204213faffdcf7cd05ffd12658ee94345d8c60bf1debc24b597dbd29436
7
+ data.tar.gz: bb297b2056cd2f77a74ef544daf0bea950fd4781a3b49b92cc27b858812f15728ff303d251b98fd4e07a4d1763a4874f851687689fda06e3a82aee2d2e4cfd5b
data/README.md CHANGED
@@ -12,7 +12,7 @@ Add this line to your application's Gemfile:
12
12
 
13
13
  And then execute:
14
14
 
15
- $ bundle
15
+ $ bundle install
16
16
 
17
17
  Or install it yourself as:
18
18
 
@@ -25,54 +25,74 @@ Or install it yourself as:
25
25
 
26
26
  4. If only `acts_has_many` is used:
27
27
  ```ruby
28
- class User < ActiveRecord::Base
29
- belongs_to :company, dependent: :destroy
28
+ class Posting < ActiveRecord::Base
29
+ belongs_to :tag, dependent: :destroy
30
30
  end
31
31
 
32
- class Company < ActiveRecord::Base
33
- has_many :users
32
+ class Tag < ActiveRecord::Base
33
+ has_many :postings
34
34
 
35
- acts_has_many :users
35
+ acts_has_many :postings
36
36
  end
37
37
  ```
38
38
  In this case you have `has_many_update` method:
39
39
  ```ruby
40
- Company.first.has_many_update {title: 'Google'}
40
+ new_record, delete_record = Tag.first.has_many_update {title: 'ruby'}
41
41
  ```
42
- if you use `acts_has_many` with `through: true` paramters:
42
+ if you use `acts_has_many` with `through: true` parameters:
43
43
  ```ruby
44
- new_records, delete_ids = Company.has_many_through_update(update: data, new: date)
44
+ new_records, delete_ids = Tag.has_many_through_update(update: data, new: date)
45
45
  ```
46
46
 
47
47
  5. If you use `acts_has_many` with `acts_has_many_for`
48
48
  ```ruby
49
- class User < ActiveRecord::Base
50
- belongs_to :company, dependent: :destroy
49
+ class Posting < ActiveRecord::Base
50
+ belongs_to :tag, dependent: :destroy
51
51
 
52
- acts_has_many_for :company
52
+ acts_has_many_for :tag
53
53
  end
54
54
 
55
- class Company < ActiveRecord::Base
56
- has_many :users
55
+ class Tag < ActiveRecord::Base
56
+ has_many :postings
57
57
 
58
- acts_has_many :users
58
+ acts_has_many :postings
59
59
  end
60
60
  ```
61
61
  In this case you can use the same that is in 4-th point and also:
62
62
  ```ruby
63
- User.first.company_attributes = {title: 'Google'}
63
+ Posting.first.tag_attributes = {title: 'ruby'}
64
64
  ```
65
- if you use `acts_has_many` with `through: true` paramters
65
+ if you use `acts_has_many` with `through: true` parameters
66
66
  ```ruby
67
- User.first.companies_collection = [{title: 'Google'}, {title: 'Apple'}]
67
+ Posting.first.tags_collection = [{title: 'ruby'}, {title: 'python'}]
68
68
  ```
69
69
 
70
+ New in v0.3.2
71
+ --------------
72
+ Use `block` to change condition, default search is `where :compare => :value`
73
+ ```ruby
74
+ class Tag < ActiveRecord::Base
75
+ has_many :postings
76
+
77
+ acts_has_many :postings do |params|
78
+ where arel_table[:title].matches(params[:title])
79
+ end
80
+ end
81
+ ```
82
+ Replace `compare` method to `condition`
83
+
84
+ Notice, if block is defined:
85
+ >* `:compare` argument will be ignored
86
+ >* auto `validates :compare, uniqueness: true` is off
87
+
88
+
70
89
  More
71
90
  ----
72
91
  `acts_has_many` options:
73
92
  >* list relations or after necessary relations
74
93
  >* :compare( string or symbol; default: :title) - name column with unique elements in table
75
94
  >* :through( boolean; default: false) - if you use has_many :through
95
+ >* &block(should return ActiveRecord::Relation; default: `where compare: params[:compare]`) - change condition
76
96
 
77
97
  `acts_has_many_for` options:
78
98
  >* list necessary relations
@@ -90,13 +110,99 @@ More
90
110
  `<relation>_collection` options:
91
111
  >* data - Array (Records, Hash, Empty)
92
112
 
93
- additionl
113
+ Additional
94
114
  >* `depend_relations` - show depend relations(Array)
95
115
  >* `actual?` - check actuality(Boolean)
96
- >* `compare` - return compare column(String)
116
+ >* `condition` - call block(in: params, out: ActiveRecord::Relation)
97
117
  >* `destroy!` - standart destroy
98
118
  >* `destroy` - destroy with cheking actuality record
99
119
 
120
+ Examples
121
+ --------
122
+ Use with `has_manay`:
123
+ ```ruby
124
+ class Posting < ActiveRecord::Base
125
+ belongs_to :tag, dependent: :destroy
126
+
127
+ acts_has_many_for :tag
128
+ end
129
+
130
+ class Tag < ActiveRecord::Base
131
+ has_many :postings
132
+
133
+ acts_has_many :postings, compare: :name
134
+ end
135
+
136
+ posting = Posting.create title: 'First posting',
137
+ tag_attributes: {name: 'ruby'}
138
+
139
+ posting.tag # => #<Tag id: 1, title: "ruby">
140
+ Tag.all # => [#<Tag id: 1, title: "ruby">]
141
+
142
+ posting = Posting.create title: 'Second posting',
143
+ tag_attributes: {name: 'ruby'}
144
+
145
+ posting.tag # => #<Tag id: 1, title: "ruby">
146
+ Tag.all # => [#<Tag id: 1, title: "ruby">]
147
+
148
+ posting.update_attributes tag_attributes: {name: 'python'}
149
+
150
+ posting.tag # => #<Tag id: 2, title: "python">
151
+ Tag.all # => [#<Tag id: 1, title: "ruby">, #<Tag id: 2, title: "python">]
152
+
153
+ posting.tag_attributes = Tag.first
154
+ posting.save
155
+
156
+ Tag.all # => [#<Tag id: 1, title: "ruby">]
157
+ ```
158
+ Use with `has_many :through`
159
+ ```ruby
160
+ class Posting < ActiveRecord::Base
161
+ has_many :posting_tags, dependent: :destroy
162
+ has_many :tags, through: :posting_tags
163
+
164
+ acts_has_many_for :tags
165
+ end
166
+
167
+ class PostingTag < ActiveRecord::Base
168
+ belongs_to :posting
169
+ belongs_to :tag
170
+ end
171
+
172
+ class Tag < ActiveRecord::Base
173
+ has_many :postings, through: :posting_tags
174
+ has_many :posting_tags
175
+
176
+ acts_has_many :postings, through: true
177
+ end
178
+
179
+ posting = Posting.create title: 'First posting',
180
+ tags_collection: [{name: 'ruby'}, {name: 'python'}]
181
+
182
+ posting.tags
183
+ # => [#<Tag id: 1, title: "ruby">, #<Tag id: 2, title: "python">]
184
+ Tag.all
185
+ # => [#<Tag id: 1, title: "ruby">, #<Tag id: 2, title: "python">]
186
+
187
+ posting = Posting.create title: 'Second posting',
188
+ tags_collection: [{name: 'ruby'}, {name: 'java'}]
189
+
190
+ posting.tags
191
+ # => [#<Tag id: 1, title: "ruby">, #<Tag id: 3, title: "java">]
192
+ Tag.all
193
+ # => [#<Tag id: 1, title: "ruby">, #<Tag id: 2, title: "python">, #<Tag id: 3, title: "java">]
194
+
195
+ posting.update_attributes tags_collection: [Tag.first]
196
+
197
+ posting.tags # => [#<Tag id: 2, title: "ruby">]
198
+ Tag.all
199
+ # => [#<Tag id: 1, title: "ruby">, #<Tag id: 2, title: "python">]
200
+
201
+ Posting.first.destroy
202
+
203
+ Tag.all # => [#<Tag id: 1, title: "ruby">]
204
+ ```
205
+
100
206
  Contributing
101
207
  ------------
102
208
  You can help improve this project.
@@ -107,7 +213,7 @@ Here are some ways *you* can contribute:
107
213
  * by suggesting new features
108
214
  * by writing or editing documentation
109
215
  * by writing specifications
110
- * by writing code (**no patch is too small**: fix typos, add comments, clean up inconsistent whitespace)
216
+ * by writing code
111
217
  * by refactoring code
112
218
  * by closing [issues](https://github.com/igor04/acts_has_many/issues)
113
219
  * by reviewing patches
@@ -1,40 +1,32 @@
1
1
  module ActiveRecord
2
2
  module ActsHasMany
3
-
4
- # Class methods:
5
- # <tt>has_many_through_update</tt>
6
- #
7
- # Instance methods:
8
- # <tt>has_many_update</tt>
9
- # <tt>actual?</tt>
10
- # <tt>destroy</tt>
11
- # <tt>destroy!</tt>
12
3
  module Child
13
-
14
- # <tt>has_many_update</tt> (return: array) - [new_record, delete_record]
15
- # options: data (type: hash) - data for updte
16
4
  def has_many_update data
17
- data = { model.compare => ''}.merge data
5
+ current = self
6
+ condition = current.class.condition(data.symbolize_keys)
18
7
 
19
- has_many_cleaner data.symbolize_keys
8
+ if actual? || current.new_record?
9
+ [condition.first_or_create(data), nil]
10
+ elsif exists = condition.first
11
+ [exists, (current == exists ? nil : current)]
12
+ else
13
+ update_attributes data
14
+ [current, nil]
15
+ end
20
16
  end
21
17
 
22
- # destroy with check actuality
23
18
  def destroy
24
19
  return false if actual? false
25
20
  super
26
21
  end
27
22
 
28
- # original destroy
29
23
  def destroy!
30
24
  self.class.superclass.instance_method(:destroy).bind(self).call
31
25
  end
32
26
 
33
- # <tt>actual?</tt> - check the acutuality of element in has_many table
34
- # options: exclude (boolean, default: true) - ignore one record or no
35
27
  def actual? exclude = true
36
28
  actual = 0
37
- model.dependent_relations.each do |dependent_relation|
29
+ self.class.dependent_relations.each do |dependent_relation|
38
30
  tmp = self.send dependent_relation
39
31
  actual += tmp.all.size
40
32
  end
@@ -43,46 +35,7 @@ module ActiveRecord
43
35
  end
44
36
  end
45
37
 
46
- private
47
-
48
- # <tt>has_many_cleaner</tt> - base mothod
49
- def has_many_cleaner data
50
- compare = { model.compare => data[model.compare] }
51
-
52
- new_record = self
53
- del_record = nil
54
-
55
- if actual?
56
- new_record = model.where(compare).first_or_create data
57
- else
58
- object_tmp = model.where(compare).first
59
- if object_tmp.nil?
60
- if new_record.id.nil?
61
- new_record = model.where(compare).first_or_create data
62
- else
63
- if data[model.compare].blank?
64
- del_record, new_record = new_record, nil
65
- else
66
- update_attributes data
67
- end
68
- end
69
- else
70
- del_record = (new_record.id == object_tmp.id) ? nil : new_record
71
- new_record = object_tmp
72
- end
73
- end
74
- [new_record, del_record]
75
- end
76
-
77
-
78
38
  module ChildThrough
79
-
80
- # <tt>has_many_through_update</tt> (return array) [ 1 - array new records, 2 - array delete records ]
81
- # options
82
- # :update (array) - data for update (id and data)
83
- # :new (array) - data for create record (data)
84
- #
85
- # +for delete records need use method destroy !!!+
86
39
  def has_many_through_update(options)
87
40
  record_add = []
88
41
  record_del = []
@@ -96,8 +49,7 @@ module ActiveRecord
96
49
  unless options[:new].nil?
97
50
  options[:new].uniq!
98
51
  options[:new].each do |data|
99
- data = data.symbolize_keys
100
- record_add << where(compare => data[compare]).first_or_create(data)
52
+ record_add << new.has_many_update(data).first
101
53
  record_del.delete record_add.last
102
54
  end
103
55
  end
@@ -1,32 +1,17 @@
1
1
  module ActiveRecord
2
2
  module ActsHasMany
3
-
4
- # Class methods:
5
- # <tt><relation>_attributes=</tt>
6
- # <tt><relation>_collection=</tt>
7
3
  module Parent
4
+ extend ActiveSupport::Concern
8
5
 
9
- def self.included base
10
-
11
- # Generate class methods
12
- # <tt><relation>_attributes=</tt> - set one element (use with belogns_to)
13
- # options: data (type: Hash, existing recod, NilClass)
14
- #
15
- # Create or update child record and set to parent when `data` is Hash
16
- # Change data with delating or leaving child record when `data` is exists record, or NilClass
17
- #
18
- # <tt><relation>_collection=</tt> - set many elements (use with has_many :through)
19
- # options: data (type: Array with (exist records or Hash)
20
- #
21
- # Create or select exists records and set to parent, unused record try destory
22
- base.dependent_relations.each do |relation|
23
- unless base.reflect_on_association relation.to_sym
6
+ included do
7
+ dependent_relations.each do |relation|
8
+ unless reflect_on_association relation.to_sym
24
9
  raise ArgumentError, "No association found for name `#{relation}`. Has it been defined yet?"
25
10
  end
26
11
 
27
12
  relation = relation.to_s
28
- unless base.reflect_on_association(relation.to_sym).collection?
29
- base.class_eval <<-EOV, __FILE__ , __LINE__ + 1
13
+ unless reflect_on_association(relation.to_sym).collection?
14
+ class_eval <<-EOV, __FILE__ , __LINE__ + 1
30
15
  def #{relation}_attributes= data
31
16
  self.tmp_garbage ||= {}
32
17
  current = self.#{relation}
@@ -47,7 +32,7 @@ module ActiveRecord
47
32
  end
48
33
  EOV
49
34
  else
50
- base.class_eval <<-EOV, __FILE__ , __LINE__ + 1
35
+ class_eval <<-EOV, __FILE__ , __LINE__ + 1
51
36
  def #{relation}_collection= data
52
37
  self.tmp_garbage ||= {}
53
38
 
@@ -76,7 +61,6 @@ module ActiveRecord
76
61
 
77
62
  private
78
63
 
79
- # <tt>clear_garbage</tt> work with after_save and try destroied records from tmp_garbage
80
64
  def clear_garbage
81
65
  self.tmp_garbage.each do |relation, record|
82
66
  if record.is_a? Array
@@ -1,33 +1,17 @@
1
1
  module ActiveRecord
2
2
  module ActsHasMany
3
-
4
- # Class methods: (for use in your model)
5
- # <tt>acts_has_many_for</tt>
6
- # <tt>acts_has_many</tt>
7
- def self.included base
8
- base.extend ClassMethods
9
- end
3
+ extend ActiveSupport::Concern
10
4
 
11
5
  module ClassMethods
12
-
13
- # Class methods:
14
- # <tt>dependent_relations</tt>
15
- # <tt>compare</tt>
16
- # <tt>model</tt>
17
- # <tt>has_many_through_update</tt>
18
- # Instance mothods:
19
- # <tt>actual?</tt>
20
- # <tt>has_many_update</tt>
21
- # Set:
22
- # validates for <compare_element> (uniqueness: true, presence: true)
23
- def acts_has_many *opt
24
- options = { compare: :title, through: false }
6
+ def acts_has_many *opt, &block
7
+ options = {compare: :title, through: false}
25
8
  options.update opt.extract_options!
26
9
  options.assert_valid_keys :compare, :through
27
- options[:relations] = opt
28
10
 
29
- options[:relations] = self.reflect_on_all_associations(:has_many)
30
- .map(&:name) if options[:relations].blank?
11
+ options[:relations] = opt
12
+ if options[:relations].blank?
13
+ options[:relations] = self.reflect_on_all_associations(:has_many).map(&:name)
14
+ end
31
15
 
32
16
  dependent_relations = []
33
17
  options[:relations].each do |relation|
@@ -38,33 +22,26 @@ module ActiveRecord
38
22
  end
39
23
  end
40
24
 
25
+ if block_given?
26
+ self.class.send :define_method, :condition, block
27
+ else
28
+ self.class.send :define_method, :condition do |data|
29
+ where options[:compare] => data[options[:compare]]
30
+ end
31
+ end
32
+
41
33
  class_eval <<-EOV, __FILE__ , __LINE__ + 1
42
34
  def self.dependent_relations
43
35
  #{dependent_relations}
44
36
  end
45
37
 
46
- def self.compare
47
- '#{options[:compare]}'.to_sym
48
- end
49
-
50
38
  include ActiveRecord::ActsHasMany::Child
51
- #{'extend ActiveRecord::ActsHasMany::ChildThrough' if options[:through]}
39
+ #{"extend ActiveRecord::ActsHasMany::ChildThrough" if options[:through]}
52
40
 
53
- def model
54
- #{self}
55
- end
56
-
57
- validates :#{options[:compare]}, uniqueness: true, presence: true
41
+ #{"validates :#{options[:compare]}, uniqueness: true" unless block_given?}
58
42
  EOV
59
43
  end
60
44
 
61
- # Class methods:
62
- # <tt>dependent_relations</tt>
63
- # <tt><relation>_attributes=</tt>
64
- # <tt><relation>_collection=</tt>
65
- # Set:
66
- # after save filter
67
- # attribut accessor tmp_garbage
68
45
  def acts_has_many_for *relations
69
46
  class_eval <<-EOV, __FILE__ , __LINE__ + 1
70
47
  def self.dependent_relations
@@ -78,7 +55,6 @@ module ActiveRecord
78
55
  after_save :clear_garbage
79
56
  EOV
80
57
  end
81
-
82
58
  end
83
59
  end
84
60
  end
@@ -1,3 +1,3 @@
1
1
  module ActsHasMany
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.2"
3
3
  end
@@ -0,0 +1,134 @@
1
+ shared_examples_for 'acts_has_many' do
2
+ context 'update method' do
3
+ let(:location){Location.create :title => "italy"}
4
+ let(:experience){Experience.create :location => location, :title => "test experience1"}
5
+ before :each do
6
+ Location.delete_all
7
+ Experience.delete_all
8
+ end
9
+
10
+ it 'has_many_update data' do
11
+ add_loc, del_loc = experience.location.has_many_update({"title" => "ukraine"})
12
+
13
+ expect(Location.all.size).to be 1
14
+ expect(location).to eq add_loc
15
+ expect(del_loc).to be nil
16
+ expect(experience.location.title).to eq "ukraine"
17
+
18
+ Experience.create :location => location, :title => "test experience2"
19
+
20
+ add_loc, del_loc = experience.location.has_many_update({"title" => "italy"})
21
+
22
+ expect(Location.all.size).to be 2
23
+ expect(location).not_to eq add_loc
24
+ expect(del_loc).to be nil
25
+
26
+ experience.location = Location.find(add_loc)
27
+ expect(experience.location.title).to eq "italy"
28
+
29
+ add_loc, del_loc = experience.location.has_many_update({"title" => "ukraine"})
30
+
31
+ expect(location).to eq add_loc
32
+ expect(experience.location).to eq del_loc
33
+ end
34
+
35
+ it "parent.child_attributes= Hash" do
36
+ experience = Experience.create location_attributes: {title: "ukraine"}, title: "test experience2"
37
+
38
+ Location.all.size.should be 1
39
+ experience.location.title.should eq "ukraine"
40
+
41
+ Experience.create location_attributes: {title: "ukraine"}, title: "test experience2"
42
+ Location.all.size.should be 1
43
+
44
+ experience.location_attributes = {"title" => "italy"}
45
+ experience.save
46
+
47
+ Location.all.size.should be 2
48
+ experience.location.title.should eq "italy"
49
+
50
+ experience.location_attributes = {"title" => "ukraine"}
51
+ experience.save
52
+
53
+ Location.all.size.should be 1
54
+ experience.location.title.should eq "ukraine"
55
+ end
56
+
57
+ it "parent.child_attributes= exist_record" do
58
+ experience = Experience.create location_attributes: {title: "ukraine"}, title: "test experience2"
59
+
60
+ Location.all.size.should be 1
61
+ experience.location.title.should eq "ukraine"
62
+
63
+ Experience.create location_attributes: Location.first, title: "test experience2"
64
+ Location.all.size.should be 1
65
+
66
+ experience.location_attributes = {"title" => "italy"}
67
+ experience.save
68
+
69
+ Location.all.size.should be 2
70
+ experience.location.title.should eq "italy"
71
+
72
+ experience.location_attributes = Location.first
73
+ experience.save
74
+
75
+ Location.all.size.should be 1
76
+ experience.location.title.should eq "ukraine"
77
+ end
78
+ end
79
+
80
+ it 'destroy' do
81
+ Location.delete_all
82
+ Experience.delete_all
83
+
84
+ location = Location.create(:title => "ukraine")
85
+
86
+ Experience.create( :location => location, :title => "test" )
87
+
88
+ location.destroy
89
+ Location.all.size.should == 1
90
+
91
+ Experience.all[0].destroy
92
+ Location.all.size.should == 0
93
+ end
94
+
95
+ it 'destroy' do
96
+ Location.delete_all
97
+ Experience.delete_all
98
+
99
+ location = Location.create(:title => "ukraine")
100
+
101
+ Experience.create( :location => location, :title => "test" )
102
+
103
+ location.destroy!
104
+ Location.all.size.should == 0
105
+ end
106
+
107
+ it 'actual?' do
108
+ Location.delete_all
109
+
110
+ location = Location.create(:title => "ukraine")
111
+
112
+ location.actual?.should == false
113
+ location.actual?(false).should == false
114
+
115
+ Experience.create( :title => 'test', :location => location )
116
+
117
+ location.actual?.should == false
118
+ location.actual?(false).should == true
119
+
120
+ Experience.create( :title => 'test', :location => location )
121
+
122
+ location.actual?.should == true
123
+ location.actual?(false).should == true
124
+ end
125
+
126
+ it 'dependent_relations' do
127
+ Location.dependent_relations.should == ['experiences']
128
+ end
129
+
130
+ it 'condition' do
131
+ where = Location.condition(:title => "ukraine")
132
+ expect(where).to eq Location.where(:title => "ukraine")
133
+ end
134
+ end
@@ -1,147 +1,64 @@
1
1
  require 'helper'
2
+ require 'has_many_common'
2
3
 
3
- class Location < ActiveRecord::Base
4
- self.table_name = 'locations'
5
- has_many :experiences
4
+ describe "acts_has_many clear initialization" do
5
+ before(:each) do
6
+ Object.send :remove_const, :Location if defined? Location
7
+ class Location < ActiveRecord::Base
8
+ self.table_name = 'locations'
9
+ has_many :experiences
6
10
 
7
- acts_has_many :experiences, compare: 'title'
8
- end
9
-
10
- describe 'acts_has_many' do
11
- context 'update method' do
12
- let(:location){Location.create :title => "italy"}
13
- let(:experience){Experience.create :location => location, :title => "test experience1"}
14
- before :each do
15
- Location.delete_all
16
- Experience.delete_all
17
- end
18
-
19
- it 'has_many_update data' do
20
- add_loc, del_loc = experience.location.has_many_update({"title" => "ukraine"})
21
-
22
- expect(Location.all.size).to be 1
23
- expect(location).to eq add_loc
24
- expect(del_loc).to be nil
25
- expect(experience.location.title).to eq "ukraine"
26
-
27
- Experience.create :location => location, :title => "test experience2"
28
-
29
- add_loc, del_loc = experience.location.has_many_update({"title" => "italy"})
30
-
31
- expect(Location.all.size).to be 2
32
- expect(location).not_to eq add_loc
33
- expect(del_loc).to be nil
34
-
35
- experience.location = Location.find(add_loc)
36
- expect(experience.location.title).to eq "italy"
37
-
38
- add_loc, del_loc = experience.location.has_many_update({"title" => "ukraine"})
39
-
40
- expect(location).to eq add_loc
41
- expect(experience.location).to eq del_loc
42
- end
43
-
44
- it "parent.child_attributes= Hash" do
45
- experience = Experience.create location_attributes: {title: "ukraine"}, title: "test experience2"
46
-
47
- Location.all.size.should be 1
48
- experience.location.title.should eq "ukraine"
49
-
50
- Experience.create location_attributes: {title: "ukraine"}, title: "test experience2"
51
- Location.all.size.should be 1
52
-
53
- experience.location_attributes = {"title" => "italy"}
54
- experience.save
55
-
56
- Location.all.size.should be 2
57
- experience.location.title.should eq "italy"
58
-
59
- experience.location_attributes = {"title" => "ukraine"}
60
- experience.save
61
-
62
- Location.all.size.should be 1
63
- experience.location.title.should eq "ukraine"
64
- end
65
-
66
- it "parent.child_attributes= exist_record" do
67
- experience = Experience.create location_attributes: {title: "ukraine"}, title: "test experience2"
68
-
69
- Location.all.size.should be 1
70
- experience.location.title.should eq "ukraine"
71
-
72
- Experience.create location_attributes: Location.first, title: "test experience2"
73
- Location.all.size.should be 1
74
-
75
- experience.location_attributes = {"title" => "italy"}
76
- experience.save
77
-
78
- Location.all.size.should be 2
79
- experience.location.title.should eq "italy"
80
-
81
- experience.location_attributes = Location.first
82
- experience.save
83
-
84
- Location.all.size.should be 1
85
- experience.location.title.should eq "ukraine"
11
+ acts_has_many
86
12
  end
87
13
  end
14
+ it_behaves_like 'acts_has_many'
15
+ end
88
16
 
89
- it 'destroy' do
90
- Location.delete_all
91
- Experience.delete_all
92
-
93
- location = Location.create(:title => "ukraine")
94
-
95
- Experience.create( :location => location, :title => "test" )
17
+ describe "acts_has_many ititialize with relation" do
18
+ before(:each) do
19
+ Object.send :remove_const, :Location if defined? Location
96
20
 
97
- location.destroy
98
- Location.all.size.should == 1
21
+ class Location < ActiveRecord::Base
22
+ self.table_name = 'locations'
23
+ has_many :experiences
99
24
 
100
- Experience.all[0].destroy
101
- Location.all.size.should == 0
25
+ acts_has_many :experiences
26
+ end
102
27
  end
28
+ it_behaves_like 'acts_has_many'
29
+ end
103
30
 
104
- it 'destroy' do
105
- Location.delete_all
106
- Experience.delete_all
107
-
108
- location = Location.create(:title => "ukraine")
31
+ describe "acts_has_many initialize with :compare" do
32
+ before(:each) do
33
+ Object.send :remove_const, :Location if defined? Location
109
34
 
110
- Experience.create( :location => location, :title => "test" )
35
+ class Location < ActiveRecord::Base
36
+ self.table_name = 'locations'
37
+ has_many :experiences
111
38
 
112
- location.destroy!
113
- Location.all.size.should == 0
39
+ acts_has_many compare: :title
40
+ end
114
41
  end
42
+ it_behaves_like 'acts_has_many'
43
+ end
115
44
 
116
- it 'actual?' do
117
- Location.delete_all
118
-
119
- location = Location.create(:title => "ukraine")
120
-
121
- location.actual?.should == false
122
- location.actual?(false).should == false
123
-
124
- Experience.create( :title => 'test', :location => location )
125
-
126
- location.actual?.should == false
127
- location.actual?(false).should == true
128
-
129
- Experience.create( :title => 'test', :location => location )
45
+ describe "acts_has_many initialize with block" do
46
+ before(:each) do
47
+ Object.send :remove_const, :Location if defined? Location
130
48
 
131
- location.actual?.should == true
132
- location.actual?(false).should == true
133
- end
49
+ class Location < ActiveRecord::Base
50
+ self.table_name = 'locations'
51
+ has_many :experiences
134
52
 
135
- it 'compare' do
136
- Location.compare.should == :title
137
- end
138
-
139
- it 'model' do
140
- location = Location.create(:title => "ukraine")
141
- location.model.should == Location
53
+ acts_has_many do |data|
54
+ where arel_table[:title].eq(data[:title])
55
+ end
56
+ end
142
57
  end
58
+ it_behaves_like 'acts_has_many'
143
59
 
144
- it 'dependent_relations' do
145
- Location.dependent_relations.should == ['experiences']
60
+ it 'condition' do
61
+ where = Location.condition(:title => "ukraine")
62
+ expect(where).to eq Location.where(Location.arel_table[:title].eq("ukraine"))
146
63
  end
147
64
  end
@@ -0,0 +1,94 @@
1
+ shared_examples_for 'acts_has_many through: true' do
2
+ it 'parent.child_colletion=<data>' do
3
+ Local.delete_all
4
+
5
+ company = Company.create title: 'test', locals_collection: [{title: 'testx'}]
6
+ company.locals.first.title.should eq 'testx'
7
+
8
+ company.locals_collection = [{title: 'test2'}]
9
+ company.locals.first.title.should eq 'test2'
10
+ Local.all.size.should be 2
11
+
12
+ company.save # after save we clear garbage
13
+ company.locals.first.title.should eq 'test2'
14
+ Local.all.size.should be 1
15
+
16
+ company2 = Company.create title: 'test2', locals_collection: [{title: 'test2'},{title: 'test1'}]
17
+ company.locals_collection = Local.all
18
+ company.locals.size.should be 2
19
+
20
+ company.save
21
+ Local.all.size.should be 2
22
+
23
+ company.locals_collection = [{title: 'test3'}, {title: 'test2'}]
24
+ company.save
25
+
26
+ company.locals.size.should be 2
27
+ Local.all.size.should be 3
28
+
29
+ company.locals_collection = [{title: 'test1'}]
30
+ Local.all.size.should be 3
31
+
32
+ company.save
33
+ Local.all.size.should be 2
34
+
35
+ company2.locals_collection = [Local.last]
36
+ Local.all.size.should be 2
37
+
38
+ company2.save
39
+ Local.all.size.should be 1
40
+ company2.locals.should eq company.locals
41
+
42
+ company2.locals_collection = []
43
+ company2.save
44
+ company2.locals.should eq []
45
+
46
+ company.locals_collection = []
47
+ company.save
48
+
49
+ Local.all.should eq []
50
+ end
51
+ it 'update' do
52
+ Local.delete_all
53
+
54
+ Local.all.size.should == 0
55
+
56
+ new_records, del_records = Local.has_many_through_update( :new => [
57
+ { title: 'test0'},
58
+ { title: 'test1'},
59
+ { title: 'test2'},
60
+ { title: 'test3'},
61
+ { title: 'test0'},
62
+ ])
63
+
64
+ expect(new_records.count).to be 4
65
+ expect(del_records).to eq []
66
+ expect(Local.all.size).to be 4
67
+
68
+ new_records_1, del_records_1 = Local.has_many_through_update(
69
+ :new => [
70
+ { title: 'test0'},
71
+ { 'title' => 'test1'}
72
+ ],
73
+ :update => {
74
+ new_records[2].id => {title: 'test2s'},
75
+ new_records[3].id.to_s => {'title' => 'test3s'}
76
+ })
77
+
78
+ expect(new_records_1.map(&:id).sort!).to eq new_records.map(&:id)
79
+ expect(Local.find(new_records[2].id).title).to eq 'test2s'
80
+ expect(Local.find(new_records[3].id).title).to eq 'test3s'
81
+ expect(Local.all.size).to be 4
82
+
83
+ new, del = Local.has_many_through_update(
84
+ :new => [
85
+ { title: 'test0'},
86
+ { title: 'test3s'}],
87
+ :update => {
88
+ new_records_1[0].id => {title: 'test0'},
89
+ })
90
+
91
+ expect(del.size).to be 1
92
+ expect(new.size).to be 3
93
+ end
94
+ end
@@ -1,106 +1,96 @@
1
1
  require 'helper'
2
+ require 'has_many_through_common'
2
3
 
3
- class Local < ActiveRecord::Base
4
- self.table_name = 'locals'
5
- has_many :companies, :through => :company_locals
6
- has_many :company_locals
4
+ describe "acts_has_many :through" do
5
+ before(:each) do
6
+ Object.send :remove_const, :Local if defined? Local
7
7
 
8
- acts_has_many :companies, :through => true, compare: 'title'
8
+ class Local < ActiveRecord::Base
9
+ self.table_name = 'locals'
10
+ has_many :companies, :through => :company_locals
11
+ has_many :company_locals
12
+
13
+ acts_has_many through: true
14
+ end
15
+ end
16
+ it_behaves_like 'acts_has_many through: true'
9
17
  end
10
18
 
11
- describe 'acts_has_many with :through' do
12
- it 'parent.child_colletion=<data>' do
13
- Local.delete_all
19
+ describe "acts_has_many :through with relation" do
20
+ before(:each) do
21
+ Object.send :remove_const, :Local if defined? Local
14
22
 
15
- company = Company.create title: 'test', locals_collection: [{title: 'testx'}]
16
- company.locals.first.title.should eq 'testx'
23
+ class Local < ActiveRecord::Base
24
+ self.table_name = 'locals'
25
+ has_many :companies, :through => :company_locals
26
+ has_many :company_locals
17
27
 
18
- company.locals_collection = [{title: 'test2'}]
19
- company.locals.first.title.should eq 'test2'
20
- Local.all.size.should be 2
28
+ acts_has_many :companies, through: true
29
+ end
30
+ end
31
+ it_behaves_like 'acts_has_many through: true'
32
+ end
21
33
 
22
- company.save # after save we clear garbage
23
- company.locals.first.title.should eq 'test2'
24
- Local.all.size.should be 1
34
+ describe "acts_has_many :through with :compare" do
35
+ before(:each) do
36
+ Object.send :remove_const, :Local if defined? Local
25
37
 
26
- company2 = Company.create title: 'test2', locals_collection: [{title: 'test2'},{title: 'test1'}]
27
- company.locals_collection = Local.all
28
- company.locals.size.should be 2
38
+ class Local < ActiveRecord::Base
39
+ self.table_name = 'locals'
40
+ has_many :companies, :through => :company_locals
41
+ has_many :company_locals
29
42
 
30
- company.save
31
- Local.all.size.should be 2
43
+ acts_has_many compare: :title, through: true
44
+ end
45
+ end
46
+ it_behaves_like 'acts_has_many through: true'
47
+ end
32
48
 
33
- company.locals_collection = [{title: 'test3'}, {title: 'test2'}]
34
- company.save
49
+ describe "acts_has_many :through with relation and :compare" do
50
+ before(:each) do
51
+ Object.send :remove_const, :Local if defined? Local
35
52
 
36
- company.locals.size.should be 2
37
- Local.all.size.should be 3
53
+ class Local < ActiveRecord::Base
54
+ self.table_name = 'locals'
55
+ has_many :companies, :through => :company_locals
56
+ has_many :company_locals
38
57
 
39
- company.locals_collection = [{title: 'test1'}]
40
- Local.all.size.should be 3
58
+ acts_has_many :companies, compare: :title, through: true
59
+ end
60
+ end
61
+ it_behaves_like 'acts_has_many through: true'
62
+ end
41
63
 
42
- company.save
43
- Local.all.size.should be 2
64
+ describe "acts_has_many :through with relation and block" do
65
+ before(:each) do
66
+ Object.send :remove_const, :Local if defined? Local
44
67
 
45
- company2.locals_collection = [Local.last]
46
- Local.all.size.should be 2
68
+ class Local < ActiveRecord::Base
69
+ self.table_name = 'locals'
70
+ has_many :companies, :through => :company_locals
71
+ has_many :company_locals
47
72
 
48
- company2.save
49
- Local.all.size.should be 1
50
- company2.locals.should eq company.locals
73
+ acts_has_many :companies, through: true do |local|
74
+ where arel_table[:title].eq local[:title]
75
+ end
76
+ end
77
+ end
78
+ it_behaves_like 'acts_has_many through: true'
79
+ end
51
80
 
52
- company2.locals_collection = []
53
- company2.save
54
- company2.locals.should eq []
81
+ describe "acts_has_many :through with relation and block" do
82
+ before(:each) do
83
+ Object.send :remove_const, :Local if defined? Local
55
84
 
56
- company.locals_collection = []
57
- company.save
85
+ class Local < ActiveRecord::Base
86
+ self.table_name = 'locals'
87
+ has_many :companies, :through => :company_locals
88
+ has_many :company_locals
58
89
 
59
- Local.all.should eq []
60
- end
61
- it 'update' do
62
- Local.delete_all
63
-
64
- Local.all.size.should == 0
65
-
66
- new_records, del_records = Local.has_many_through_update( :new => [
67
- { title: 'test0'},
68
- { title: 'test1'},
69
- { title: 'test2'},
70
- { title: 'test3'},
71
- { title: 'test0'},
72
- ])
73
-
74
- expect(new_records.count).to be 4
75
- expect(del_records).to eq []
76
- expect(Local.all.size).to be 4
77
-
78
- new_records_1, del_records_1 = Local.has_many_through_update(
79
- :new => [
80
- { title: 'test0'},
81
- { 'title' => 'test1'}
82
- ],
83
- :update => {
84
- new_records[2].id => {title: 'test2s'},
85
- new_records[3].id.to_s => {'title' => 'test3s'}
86
- })
87
-
88
- expect(new_records_1.map(&:id).sort!).to eq new_records.map(&:id)
89
- expect(Local.find(new_records[2].id).title).to eq 'test2s'
90
- expect(Local.find(new_records[3].id).title).to eq 'test3s'
91
- expect(Local.all.size).to be 4
92
-
93
-
94
- new, del = Local.has_many_through_update(
95
- :new => [
96
- { title: 'test0'},
97
- { title: 'test3s'}],
98
- :update => {
99
- new_records_1[2].id => {title: 'test2s'},
100
- new_records_1[3].id => {title: ''}
101
- })
102
-
103
- expect(del.size).to be 1
104
- expect(new.size).to be 3
90
+ acts_has_many through: true do |local|
91
+ where arel_table[:title].eq local[:title]
92
+ end
93
+ end
105
94
  end
95
+ it_behaves_like 'acts_has_many through: true'
106
96
  end
metadata CHANGED
@@ -1,94 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_has_many
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
5
- prerelease:
4
+ version: 0.3.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Igor IS04
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-03-20 00:00:00.000000000 Z
11
+ date: 2013-06-05 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: rspec
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: sqlite3
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - '>='
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - '>='
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: activerecord
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - '>='
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - '>='
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  description: This gem gives functional for update elements has_many relation
@@ -109,35 +98,38 @@ files:
109
98
  - lib/acts_has_many/active_record/acts_has_many/child.rb
110
99
  - lib/acts_has_many/active_record/acts_has_many/parent.rb
111
100
  - lib/acts_has_many/version.rb
101
+ - spec/has_many_common.rb
112
102
  - spec/has_many_spec.rb
103
+ - spec/has_many_through_common.rb
113
104
  - spec/has_many_through_spec.rb
114
105
  - spec/helper.rb
115
106
  homepage: https://github.com/igor04/acts_has_many
116
107
  licenses: []
108
+ metadata: {}
117
109
  post_install_message:
118
110
  rdoc_options: []
119
111
  require_paths:
120
112
  - lib
121
113
  required_ruby_version: !ruby/object:Gem::Requirement
122
- none: false
123
114
  requirements:
124
- - - ! '>='
115
+ - - '>='
125
116
  - !ruby/object:Gem::Version
126
117
  version: '0'
127
118
  required_rubygems_version: !ruby/object:Gem::Requirement
128
- none: false
129
119
  requirements:
130
- - - ! '>='
120
+ - - '>='
131
121
  - !ruby/object:Gem::Version
132
122
  version: '0'
133
123
  requirements: []
134
124
  rubyforge_project:
135
- rubygems_version: 1.8.25
125
+ rubygems_version: 2.0.0
136
126
  signing_key:
137
- specification_version: 3
127
+ specification_version: 4
138
128
  summary: All records must be used, otherwise they will be deleted. Clear logic with
139
129
  has_many
140
130
  test_files:
131
+ - spec/has_many_common.rb
141
132
  - spec/has_many_spec.rb
133
+ - spec/has_many_through_common.rb
142
134
  - spec/has_many_through_spec.rb
143
135
  - spec/helper.rb