Skip to content

Commit

Permalink
WIP: use association manipulation iff external associations
Browse files Browse the repository at this point in the history
For #121
  • Loading branch information
chrisandreae committed Jul 8, 2019
1 parent 93837cd commit 904fc06
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 0 deletions.
12 changes: 12 additions & 0 deletions lib/view_model/active_record/association_manipulation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ def load_associated(association_name, scope: nil, eager_include: true, serialize
def replace_associated(association_name, update_hash, references: {}, deserialize_context: self.class.new_deserialize_context)
association_data = self.class._association_data(association_name)

unless association_data.external?
raise ViewModel::DeserializationError::InternalAssociationWrite.new(association_name, self.to_reference)
end

if association_data.referenced?
is_fupdate =
association_data.collection? &&
Expand Down Expand Up @@ -105,6 +109,10 @@ def append_associated(association_name, subtree_hash_or_hashes, references: {},
direct_reflection = association_data.direct_reflection
raise ArgumentError.new("Cannot append to single association '#{association_name}'") unless association_data.collection?

unless association_data.external?
raise ViewModel::DeserializationError::InternalAssociationWrite.new(association_name, self.to_reference)
end

ViewModel::Utils.wrap_one_or_many(subtree_hash_or_hashes) do |subtree_hashes|
model_class.transaction do
ViewModel::Callbacks.wrap_deserialize(self, deserialize_context: deserialize_context) do |hook_control|
Expand Down Expand Up @@ -218,6 +226,10 @@ def delete_associated(association_name, associated_id, type: nil, deserialize_co
association_data = self.class._association_data(association_name)
direct_reflection = association_data.direct_reflection

unless association_data.external?
raise ViewModel::DeserializationError::InternalAssociationWrite.new(association_name, self.to_reference)
end

unless association_data.collection?
raise ArgumentError.new("Cannot remove element from single association '#{association_name}'")
end
Expand Down
6 changes: 6 additions & 0 deletions lib/view_model/active_record/update_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,12 @@ def parse(hash_data, valid_reference_keys)
when AssociationData
association_data = member_data

# FIXME: replace_associated uses this update machinery, this won't work
# until we mark it.
if association_data.external?
raise ViewModel::DeserializationError::ExternalAssociationWrite.new(name)
end

case
when value.nil?
if association_data.collection?
Expand Down
27 changes: 27 additions & 0 deletions lib/view_model/deserialization_error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,33 @@ def meta
end
end

# Attempted to write to an external association during a deserialization
class ExternalAssociationWrite < InvalidRequest
attr_reader :association

def initialize(association, node)
@association = association
super([node])
end

def detail
"Invalid write to external association #{association} in deserialization"
end
end

# Attempted to write to an internal association during an association_manipulation
class InternalAssociationWrite < InvalidRequest
attr_reader :association
def initialize(association, node)
@association = association
super([node])
end

def detail
"Invalid write to internal association #{association} via external manipulation"
end
end

class InvalidViewType < InvalidRequest
attr_reader :expected_type

Expand Down
4 changes: 4 additions & 0 deletions test/unit/view_model/active_record/has_many_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,10 @@ def new_model
end

describe 'with association manipulation' do
def subject_association_features
super.merge(external: true)
end

it 'appends a child' do
view = create_viewmodel!

Expand Down

0 comments on commit 904fc06

Please sign in to comment.