granite-form 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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