granite-form 0.2.0 → 0.3.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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -2
  3. data/.github/workflows/{ci.yml → ruby.yml} +22 -4
  4. data/.rubocop.yml +1 -1
  5. data/.rubocop_todo.yml +3 -3
  6. data/Appraisals +1 -2
  7. data/CHANGELOG.md +7 -0
  8. data/README.md +0 -2
  9. data/docker-compose.yml +14 -0
  10. data/gemfiles/rails.5.0.gemfile +0 -1
  11. data/gemfiles/rails.5.1.gemfile +0 -1
  12. data/gemfiles/rails.5.2.gemfile +0 -1
  13. data/granite-form.gemspec +15 -15
  14. data/lib/granite/form/active_record/associations.rb +1 -1
  15. data/lib/granite/form/base.rb +1 -2
  16. data/lib/granite/form/errors.rb +0 -15
  17. data/lib/granite/form/model/associations/base.rb +0 -4
  18. data/lib/granite/form/model/associations/collection/embedded.rb +2 -1
  19. data/lib/granite/form/model/associations/collection/proxy.rb +1 -1
  20. data/lib/granite/form/model/associations/embeds_any.rb +7 -0
  21. data/lib/granite/form/model/associations/embeds_many.rb +9 -58
  22. data/lib/granite/form/model/associations/embeds_one.rb +7 -36
  23. data/lib/granite/form/model/associations/nested_attributes.rb +5 -5
  24. data/lib/granite/form/model/associations/persistence_adapters/active_record.rb +0 -4
  25. data/lib/granite/form/model/associations/persistence_adapters/base.rb +0 -4
  26. data/lib/granite/form/model/associations/references_many.rb +0 -32
  27. data/lib/granite/form/model/associations/references_one.rb +0 -28
  28. data/lib/granite/form/model/associations/reflections/embeds_any.rb +1 -1
  29. data/lib/granite/form/model/associations/reflections/references_any.rb +0 -4
  30. data/lib/granite/form/model/associations/reflections/references_one.rb +0 -2
  31. data/lib/granite/form/model/associations/reflections/singular.rb +0 -8
  32. data/lib/granite/form/model/associations.rb +0 -6
  33. data/lib/granite/form/model/attributes/base.rb +1 -1
  34. data/lib/granite/form/model/attributes/reflections/attribute.rb +0 -6
  35. data/lib/granite/form/model/attributes/reflections/base.rb +8 -7
  36. data/lib/granite/form/model/attributes/reflections/reference_one.rb +0 -6
  37. data/lib/granite/form/model/persistence.rb +1 -19
  38. data/lib/granite/form/model.rb +0 -2
  39. data/lib/granite/form/version.rb +1 -1
  40. data/spec/granite/form/active_record/associations_spec.rb +16 -18
  41. data/spec/granite/form/model/associations/embeds_many_spec.rb +29 -305
  42. data/spec/granite/form/model/associations/embeds_one_spec.rb +27 -212
  43. data/spec/granite/form/model/associations/nested_attributes_spec.rb +0 -95
  44. data/spec/granite/form/model/associations/references_many_spec.rb +5 -326
  45. data/spec/granite/form/model/associations/references_one_spec.rb +6 -278
  46. data/spec/granite/form/model/associations/reflections/embeds_any_spec.rb +1 -2
  47. data/spec/granite/form/model/associations/reflections/embeds_many_spec.rb +18 -26
  48. data/spec/granite/form/model/associations/reflections/embeds_one_spec.rb +16 -23
  49. data/spec/granite/form/model/associations/reflections/references_many_spec.rb +1 -1
  50. data/spec/granite/form/model/associations/reflections/references_one_spec.rb +1 -22
  51. data/spec/granite/form/model/associations/validations_spec.rb +0 -3
  52. data/spec/granite/form/model/associations_spec.rb +3 -24
  53. data/spec/granite/form/model/dirty_spec.rb +1 -1
  54. data/spec/granite/form/model/persistence_spec.rb +0 -2
  55. data/spec/granite/form/model/validations/associated_spec.rb +2 -4
  56. data/spec/granite/form/model/validations/nested_spec.rb +2 -4
  57. data/spec/spec_helper.rb +0 -15
  58. data/spec/support/active_record.rb +20 -0
  59. data/spec/support/shared/nested_attribute_examples.rb +3 -21
  60. metadata +32 -38
  61. data/.github/workflows/main.yml +0 -29
  62. data/gemfiles/rails.4.2.gemfile +0 -15
  63. data/lib/granite/form/model/callbacks.rb +0 -72
  64. data/lib/granite/form/model/lifecycle.rb +0 -309
  65. data/spec/granite/form/model/callbacks_spec.rb +0 -337
  66. data/spec/granite/form/model/lifecycle_spec.rb +0 -356
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ebac9979a786e2a3638b1dd7b21648320c779770c10f7fe63707b38a58c0164c
4
- data.tar.gz: 604dcf0abda92863e1503b0d977a53ca1de7a39823bfc8a4aabab8d9c6a27045
3
+ metadata.gz: 848ee19f938a86a22a506585a7a4960bbb192b977fdc61173b05057c0381ec79
4
+ data.tar.gz: 9c024906d4e6c7c8a93db7bcfe005dbffa956e4239a0078d642b3604c4226c0a
5
5
  SHA512:
6
- metadata.gz: cfc2c624834fe5d0ad4fadb903e6b9a38eed17778cea3c0cf9430437fb095436429c1a0941fd418e143805b064c1a74c0c959fb57493d96fb9602cdca625f36d
7
- data.tar.gz: 4937e3d02a378edf48daa770799206b3ecdb91ee71ed1025169e6e3bf4a25bc157c01aea9db54dcb70645728eeb0055ca42be7db23258f0b7f2744d8f7415dd9
6
+ metadata.gz: e35f2d05bd0adaabdb00df1799b9997d6f01818f00271ee24cc628b9e5edf859ab4f15e1ee3e56f697485d89a2f1c05ebeff42816f53b4293c82854e3f4e247e
7
+ data.tar.gz: df23355e592e78a1d998ace8a8010e188360ce99173fe69623bf3b03da18286f3476d509620b89f91fcaa5df299a20b32906cb3c0ae95353b75eb2c694afe409
data/.github/CODEOWNERS CHANGED
@@ -1,2 +1 @@
1
- .github/workflows/ci.yml @toptal/coresmiths-team
2
- .github/workflows/main.yml @toptal/coresmiths-team
1
+ * @toptal/coresmiths-team
@@ -1,21 +1,39 @@
1
- name: CI
2
- on: [push, pull_request]
1
+ name: Ruby
2
+ on:
3
+ push:
4
+ branches: [ master ]
5
+ pull_request:
6
+ branches: [ master ]
3
7
  jobs:
4
8
  rspec:
5
9
  strategy:
6
10
  fail-fast: false
7
11
  matrix:
8
12
  include:
9
- - { ruby: '2.3', rails: '4.2' }
10
13
  - { ruby: '2.4', rails: '5.0' }
11
14
  - { ruby: '2.5', rails: '5.1' }
12
15
  - { ruby: '2.6', rails: '5.2' }
13
16
  - { ruby: '2.7', rails: '6.0' }
14
17
  - { ruby: '3.0', rails: '6.1' }
15
- - { ruby: '3.0', rails: '7.0' }
18
+ - { ruby: '3.1', rails: '7.0' }
16
19
  runs-on: ubuntu-latest
17
20
  env:
18
21
  BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/rails.${{ matrix.rails }}.gemfile
22
+ services:
23
+ postgres:
24
+ image: postgres
25
+ env:
26
+ POSTGRES_USER: granite
27
+ POSTGRES_PASSWORD: granite
28
+ # Set health checks to wait until postgres has started
29
+ options: >-
30
+ --health-cmd pg_isready
31
+ --health-interval 10s
32
+ --health-timeout 5s
33
+ --health-retries 5
34
+ ports:
35
+ # Maps tcp port 5432 on service container to the host
36
+ - 5432:5432
19
37
  steps:
20
38
  - uses: actions/checkout@v2
21
39
  - uses: ruby/setup-ruby@v1
data/.rubocop.yml CHANGED
@@ -2,7 +2,7 @@ inherit_from: .rubocop_todo.yml
2
2
 
3
3
  AllCops:
4
4
  DisplayCopNames: true
5
- TargetRubyVersion: 2.2.10
5
+ TargetRubyVersion: 2.4.0
6
6
 
7
7
  Lint/AmbiguousBlockAssociation:
8
8
  Enabled: false
data/.rubocop_todo.yml CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  # Offense count: 19
10
10
  Metrics/AbcSize:
11
- Max: 55
11
+ Max: 59
12
12
 
13
13
  # Offense count: 2
14
14
  # Configuration parameters: CountComments.
@@ -17,7 +17,7 @@ Metrics/ClassLength:
17
17
 
18
18
  # Offense count: 4
19
19
  Metrics/CyclomaticComplexity:
20
- Max: 13
20
+ Max: 15
21
21
 
22
22
  # Offense count: 904
23
23
  # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives.
@@ -41,7 +41,7 @@ Metrics/BlockLength:
41
41
 
42
42
  # Offense count: 4
43
43
  Metrics/PerceivedComplexity:
44
- Max: 16
44
+ Max: 18
45
45
 
46
46
  # Offense count: 75
47
47
  Style/Documentation:
data/Appraisals CHANGED
@@ -1,8 +1,7 @@
1
- %w[4.2 5.0 5.1 5.2 6.0 6.1 7.0].each do |version|
1
+ %w[5.0 5.1 5.2 6.0 6.1 7.0].each do |version|
2
2
  appraise "rails.#{version}" do
3
3
  gem 'activesupport', "~> #{version}.0"
4
4
  gem 'activemodel', "~> #{version}.0"
5
5
  gem 'activerecord', "~> #{version}.0"
6
- gem 'sqlite3', '~> 1.3.6' if version < '6.0'
7
6
  end
8
7
  end
data/CHANGELOG.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # master
2
2
 
3
3
  ## Next
4
+ ## v0.3.0
5
+
6
+ - [BREAKING] Stop automatically saving `references_one`/`references_many` when applying changes.
7
+ - [BREAKING] Removed Lifecycle module. `embeds_many`/`embeds_one` objects can no longer be created/saved/updated/destroyed.
8
+ - [BREAKING] Due to changes above `accepts_nested_attributes_for` for `embeds_many`/`embeds_one` associations no longer marks objects for destruction but simply removes them, making changes instantly.
9
+ - Drop support for ruby 2.3 and rails 4.2
10
+
4
11
  ## v0.2.0
5
12
 
6
13
  - Replace typecasters with proper type definitions.
data/README.md CHANGED
@@ -384,8 +384,6 @@ Options:
384
384
  * `:validate` - true or false
385
385
  * `:default` - default value for association: reference collection or objects themselves
386
386
 
387
- #### Interacting with ActiveRecord
388
-
389
387
  ### Persistence Adapters
390
388
 
391
389
  Adapter definition syntax:
@@ -0,0 +1,14 @@
1
+ version: '3.7'
2
+ services:
3
+ postgresql:
4
+ image: 'postgres:12.4'
5
+ environment:
6
+ POSTGRES_USER: granite
7
+ POSTGRES_PASSWORD: granite
8
+ volumes:
9
+ - granite_dbdata:/var/lib/postgresql/data
10
+ ports:
11
+ - '5432:5432'
12
+
13
+ volumes:
14
+ granite_dbdata:
@@ -5,7 +5,6 @@ source "https://rubygems.org"
5
5
  gem "activesupport", "~> 5.0.0"
6
6
  gem "activemodel", "~> 5.0.0"
7
7
  gem "activerecord", "~> 5.0.0"
8
- gem "sqlite3", "~> 1.3.6"
9
8
 
10
9
  group :test do
11
10
  gem "guard"
@@ -5,7 +5,6 @@ source "https://rubygems.org"
5
5
  gem "activesupport", "~> 5.1.0"
6
6
  gem "activemodel", "~> 5.1.0"
7
7
  gem "activerecord", "~> 5.1.0"
8
- gem "sqlite3", "~> 1.3.6"
9
8
 
10
9
  group :test do
11
10
  gem "guard"
@@ -5,7 +5,6 @@ source "https://rubygems.org"
5
5
  gem "activesupport", "~> 5.2.0"
6
6
  gem "activemodel", "~> 5.2.0"
7
7
  gem "activerecord", "~> 5.2.0"
8
- gem "sqlite3", "~> 1.3.6"
9
8
 
10
9
  group :test do
11
10
  gem "guard"
data/granite-form.gemspec CHANGED
@@ -1,32 +1,32 @@
1
1
  require File.expand_path('../lib/granite/form/version', __FILE__)
2
2
 
3
3
  Gem::Specification.new do |gem|
4
- gem.authors = ['pyromaniac']
5
- gem.email = ['kinwizard@gmail.com']
6
- gem.description = 'Making object from any hash or hash array'
7
- gem.summary = 'Working with hashes in AR style'
8
- gem.homepage = ''
4
+ gem.authors = ['Toptal Engineering']
5
+ gem.description = 'Making object from any hash or hash array'
6
+ gem.summary = 'Working with hashes in AR style'
7
+ gem.homepage = 'https://github.com/toptal/granite-form'
9
8
 
10
- gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
11
- gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
12
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
13
- gem.name = 'granite-form'
9
+ gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
10
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
11
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
12
+ gem.name = 'granite-form'
14
13
  gem.require_paths = ['lib']
15
- gem.version = Granite::Form::VERSION
14
+ gem.required_ruby_version = '>= 2.4.0'
15
+ gem.version = Granite::Form::VERSION
16
16
 
17
- gem.add_development_dependency 'actionpack', '>= 4.0'
18
- gem.add_development_dependency 'activerecord', '>= 4.0'
17
+ gem.add_development_dependency 'actionpack', '>= 5.0'
18
+ gem.add_development_dependency 'activerecord', '>= 5.0'
19
19
  gem.add_development_dependency 'appraisal'
20
20
  gem.add_development_dependency 'bump'
21
21
  gem.add_development_dependency 'database_cleaner'
22
+ gem.add_development_dependency 'pg'
22
23
  gem.add_development_dependency 'rake'
23
24
  gem.add_development_dependency 'rspec', '~> 3.7.0'
24
25
  gem.add_development_dependency 'rspec-its'
25
26
  gem.add_development_dependency 'rubocop', '0.52.1'
26
- gem.add_development_dependency 'sqlite3'
27
27
  gem.add_development_dependency 'uuidtools'
28
28
 
29
- gem.add_runtime_dependency 'activemodel', '>= 4.0'
30
- gem.add_runtime_dependency 'activesupport', '>= 4.0'
29
+ gem.add_runtime_dependency 'activemodel', '>= 5.0'
30
+ gem.add_runtime_dependency 'activesupport', '>= 5.0'
31
31
  gem.add_runtime_dependency 'tzinfo'
32
32
  end
@@ -45,7 +45,7 @@ module Granite
45
45
  before_save callback_name
46
46
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
47
47
  def #{callback_name}
48
- association(:#{reflection.name}).apply_changes!
48
+ association(:#{reflection.name}).sync
49
49
  end
50
50
  METHOD
51
51
  end
@@ -1,6 +1,5 @@
1
1
  require 'granite/form/model'
2
2
  require 'granite/form/model/primary'
3
- require 'granite/form/model/lifecycle'
4
3
  require 'granite/form/model/associations'
5
4
 
6
5
  module Granite
@@ -8,7 +7,7 @@ module Granite
8
7
  class Base
9
8
  include Granite::Form::Model
10
9
  include Granite::Form::Model::Primary
11
- include Granite::Form::Model::Lifecycle
10
+ include Granite::Form::Model::Persistence
12
11
  include Granite::Form::Model::Associations
13
12
  end
14
13
  end
@@ -17,21 +17,6 @@ module Granite
17
17
  end
18
18
  end
19
19
 
20
- class UnsavableObject < Error
21
- end
22
-
23
- class UndestroyableObject < Error
24
- end
25
-
26
- class ObjectNotSaved < Error
27
- end
28
-
29
- class ObjectNotDestroyed < Error
30
- end
31
-
32
- class AssociationChangesNotApplied < Error
33
- end
34
-
35
20
  class AssociationTypeMismatch < Error
36
21
  def initialize(expected, got)
37
22
  super "Expected `#{expected}` (##{expected.object_id}), but got `#{got}` (##{got.object_id})"
@@ -41,10 +41,6 @@ module Granite
41
41
  target
42
42
  end
43
43
 
44
- def apply_changes!
45
- apply_changes or raise Granite::Form::AssociationChangesNotApplied
46
- end
47
-
48
44
  def callback(name, object)
49
45
  evaluator = reflection.options[name]
50
46
  return true unless evaluator
@@ -4,7 +4,8 @@ module Granite
4
4
  module Associations
5
5
  module Collection
6
6
  class Embedded < Proxy
7
- delegate :build, :create, :create!, to: :@association
7
+ delegate :build, to: :@association
8
+ delegate :delete, to: :target
8
9
  alias_method :new, :build
9
10
  end
10
11
  end
@@ -6,7 +6,7 @@ module Granite
6
6
  class Proxy
7
7
  include Enumerable
8
8
 
9
- delegate :target, :save, :save!, :loaded?, :reload, :clear, :concat, to: :@association
9
+ delegate :target, :loaded?, :reload, :clear, :concat, to: :@association
10
10
  delegate :each, :size, :length, :first, :last, :empty?, :many?, :==, :dup, to: :target
11
11
  alias_method :<<, :concat
12
12
  alias_method :push, :concat
@@ -12,6 +12,13 @@ module Granite
12
12
  def embed_object(object)
13
13
  object.instance_variable_set(:@embedder, owner)
14
14
  end
15
+
16
+ def model_data(model)
17
+ return unless model
18
+
19
+ model.association_names.each { |assoc_name| model.association(assoc_name).sync }
20
+ model.attributes
21
+ end
15
22
  end
16
23
  end
17
24
  end
@@ -7,27 +7,6 @@ module Granite
7
7
  push_object(build_object(attributes))
8
8
  end
9
9
 
10
- def create(attributes = {})
11
- build(attributes).tap(&:save)
12
- end
13
-
14
- def create!(attributes = {})
15
- build(attributes).tap(&:save!)
16
- end
17
-
18
- def destroyed
19
- @destroyed ||= []
20
- end
21
-
22
- def apply_changes
23
- result = target.map do |object|
24
- object.destroyed? || object.marked_for_destruction? ? object.destroy : object.save
25
- end.all?
26
- @destroyed = target.select(&:destroyed?)
27
- target.delete_if(&:destroyed?)
28
- result
29
- end
30
-
31
10
  def target=(objects)
32
11
  objects.each { |object| setup_performers! object }
33
12
  loaded!
@@ -63,13 +42,14 @@ module Granite
63
42
  @target = []
64
43
  end
65
44
 
45
+ def sync
46
+ write_source(target.map { |model| model_data(model) })
47
+ end
48
+
66
49
  def clear
67
- begin
68
- transaction { target.all?(&:destroy!) }
69
- rescue Granite::Form::ObjectNotDestroyed
70
- nil
71
- end
72
- reload.empty?
50
+ target
51
+ @target = []
52
+ true
73
53
  end
74
54
 
75
55
  def reader(force_reload = false)
@@ -80,7 +60,7 @@ module Granite
80
60
  def replace(objects)
81
61
  transaction do
82
62
  clear
83
- append(objects) or raise Granite::Form::AssociationChangesNotApplied
63
+ append(objects)
84
64
  end
85
65
  end
86
66
 
@@ -101,8 +81,7 @@ module Granite
101
81
  raise AssociationTypeMismatch.new(reflection.klass, object.class) unless object && object.is_a?(reflection.klass)
102
82
  push_object object
103
83
  end
104
- result = owner.persisted? ? apply_changes : true
105
- result && target
84
+ target
106
85
  end
107
86
 
108
87
  def push_object(object)
@@ -115,34 +94,6 @@ module Granite
115
94
  embed_object(object)
116
95
  callback(:before_add, object)
117
96
 
118
- association = self
119
-
120
- object.define_create do
121
- source = association.send(:read_source)
122
- index = association.target
123
- .select { |one| one.persisted? || one.equal?(self) }
124
- .index { |one| one.equal?(self) }
125
-
126
- source.insert(index, attributes)
127
- association.send(:write_source, source)
128
- end
129
-
130
- object.define_update do
131
- source = association.send(:read_source)
132
- index = association.target.select(&:persisted?).index { |one| one.equal?(self) }
133
-
134
- source[index] = attributes
135
- association.send(:write_source, source)
136
- end
137
-
138
- object.define_destroy do
139
- source = association.send(:read_source)
140
- index = association.target.select(&:persisted?).index { |one| one.equal?(self) }
141
-
142
- source.delete_at(index) if index
143
- association.send(:write_source, source)
144
- end
145
-
146
97
  callback(:after_add, object)
147
98
  end
148
99
  end
@@ -3,33 +3,10 @@ module Granite
3
3
  module Model
4
4
  module Associations
5
5
  class EmbedsOne < EmbedsAny
6
- attr_reader :destroyed
7
-
8
6
  def build(attributes = {})
9
7
  self.target = build_object(attributes)
10
8
  end
11
9
 
12
- def create(attributes = {})
13
- build(attributes).tap(&:save)
14
- end
15
-
16
- def create!(attributes = {})
17
- build(attributes).tap(&:save!)
18
- end
19
-
20
- def apply_changes
21
- if target
22
- if target.destroyed? || target.marked_for_destruction?
23
- @destroyed = target
24
- clear
25
- else
26
- target.save
27
- end
28
- else
29
- true
30
- end
31
- end
32
-
33
10
  def target=(object)
34
11
  if object
35
12
  callback(:before_add, object)
@@ -63,9 +40,14 @@ module Granite
63
40
  object
64
41
  end
65
42
 
43
+ def sync
44
+ write_source(model_data(target))
45
+ end
46
+
66
47
  def clear
67
- target.try(:destroy)
68
- reload.nil?
48
+ target
49
+ @target = nil
50
+ true
69
51
  end
70
52
 
71
53
  def reader(force_reload = false)
@@ -79,7 +61,6 @@ module Granite
79
61
  transaction do
80
62
  clear
81
63
  self.target = object
82
- apply_changes! if owner.persisted?
83
64
  end
84
65
  else
85
66
  clear
@@ -94,16 +75,6 @@ module Granite
94
75
 
95
76
  def setup_performers!(object)
96
77
  embed_object(object)
97
- association = self
98
-
99
- object.define_save do
100
- association.send(:write_source, attributes)
101
- end
102
-
103
- object.define_destroy do
104
- association.send(:write_source, nil)
105
- true
106
- end
107
78
  end
108
79
  end
109
80
  end
@@ -78,7 +78,8 @@ module Granite
78
78
  end
79
79
 
80
80
  if existing_record && (!primary_attribute || options[:update_only] || existing_record.primary_attribute == primary_attribute_value)
81
- assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) unless call_reject_if(object, association_name, attributes)
81
+ assign_to(existing_record, attributes) unless call_reject_if(object, association_name, attributes)
82
+ association.clear if destroy_flag?(attributes) && options[:allow_destroy]
82
83
  elsif attributes[primary_attribute_name].present?
83
84
  raise Granite::Form::ObjectNotFound.new(object, association_name, attributes[primary_attribute_name])
84
85
  elsif !reject_new_object?(object, association_name, attributes, options)
@@ -127,7 +128,8 @@ module Granite
127
128
  record.primary_attribute == primary_attribute_value
128
129
  end
129
130
  if existing_record
130
- assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) unless call_reject_if(object, association_name, attributes)
131
+ assign_to(existing_record, attributes) unless call_reject_if(object, association_name, attributes)
132
+ association.target.delete(existing_record) if destroy_flag?(attributes) && options[:allow_destroy]
131
133
  elsif association.reflection.embedded?
132
134
  unless reject_new_object?(object, association_name, attributes, options)
133
135
  association.reflection.klass.with_sanitize(false) do
@@ -156,9 +158,8 @@ module Granite
156
158
  raise Granite::Form::TooManyObjects.new(limit, attributes_collection.size)
157
159
  end
158
160
 
159
- def self.assign_to_or_mark_for_destruction(object, attributes, allow_destroy)
161
+ def self.assign_to(object, attributes)
160
162
  object.assign_attributes(attributes.except(*unassignable_keys(object)))
161
- object.mark_for_destruction if destroy_flag?(attributes) && allow_destroy
162
163
  end
163
164
 
164
165
  def self.destroy_flag?(hash)
@@ -170,7 +171,6 @@ module Granite
170
171
  end
171
172
 
172
173
  def self.call_reject_if(object, association_name, attributes)
173
- return false if destroy_flag?(attributes)
174
174
  case callback = object.nested_attributes_options[association_name][:reject_if]
175
175
  when Symbol
176
176
  method(callback).arity.zero? ? send(callback) : send(callback, attributes)
@@ -26,10 +26,6 @@ module Granite
26
26
  data_source.new(attributes)
27
27
  end
28
28
 
29
- def persist(object, raise_error: false)
30
- raise_error ? object.save! : object.save
31
- end
32
-
33
29
  def scope(owner, source)
34
30
  scope = data_source.unscoped
35
31
 
@@ -16,10 +16,6 @@ module Granite
16
16
  raise NotImplementedError, 'Should be implemented in inhereted adapter. Build new instance of data object by attributes'
17
17
  end
18
18
 
19
- def persist(_object, *)
20
- raise NotImplementedError, 'Should be implemented in inhereted adapter. Build new instance of data object by attributes'
21
- end
22
-
23
19
  def scope(_owner, _source)
24
20
  raise NotImplementedError, 'Should be implemented in inhereted adapter. Better to be Enumerable'
25
21
  end
@@ -3,38 +3,6 @@ module Granite
3
3
  module Model
4
4
  module Associations
5
5
  class ReferencesMany < ReferencesAny
6
- def build(attributes = {})
7
- append([build_object(attributes)]).last
8
- end
9
-
10
- def create(attributes = {})
11
- object = build(attributes)
12
- persist_object(object)
13
- object
14
- end
15
-
16
- def create!(attributes = {})
17
- object = build(attributes)
18
- persist_object(object, raise_error: true)
19
- object
20
- end
21
-
22
- def apply_changes
23
- target.all? do |object|
24
- if object
25
- if object.marked_for_destruction? && reflection.autosave?
26
- object.destroy
27
- elsif object.new_record? || (reflection.autosave? && object.changed?)
28
- persist_object(object)
29
- else
30
- true
31
- end
32
- else
33
- true
34
- end
35
- end
36
- end
37
-
38
6
  def target=(object)
39
7
  loaded!
40
8
  @target = object.to_a
@@ -3,34 +3,6 @@ module Granite
3
3
  module Model
4
4
  module Associations
5
5
  class ReferencesOne < ReferencesAny
6
- def build(attributes = {})
7
- replace(build_object(attributes))
8
- end
9
-
10
- def create(attributes = {})
11
- persist_object(build(attributes))
12
- target
13
- end
14
-
15
- def create!(attributes = {})
16
- persist_object(build(attributes), raise_error: true)
17
- target
18
- end
19
-
20
- def apply_changes
21
- if target
22
- if target.marked_for_destruction? && reflection.autosave?
23
- target.destroy
24
- elsif target.new_record? || (reflection.autosave? && target.changed?)
25
- persist_object(target)
26
- else
27
- true
28
- end
29
- else
30
- true
31
- end
32
- end
33
-
34
6
  def target=(object)
35
7
  loaded!
36
8
  @target = object
@@ -22,7 +22,7 @@ module Granite
22
22
  Class.new(superclass || Granite::Form.base_class) do
23
23
  include Granite::Form::Model
24
24
  include Granite::Form::Model::Associations
25
- include Granite::Form::Model::Lifecycle
25
+ include Granite::Form::Model::Persistence
26
26
  include Granite::Form::Model::Primary
27
27
  include Granite::Form.base_concern if Granite::Form.base_concern
28
28
  end
@@ -53,10 +53,6 @@ module Granite
53
53
  def inspect
54
54
  "#{self.class.name.demodulize}(#{persistence_adapter.data_type})"
55
55
  end
56
-
57
- def autosave?
58
- !!options[:autosave]
59
- end
60
56
  end
61
57
  end
62
58
  end