Example object:
class Foo < ApplicationRecord
composed_of :bar,
mapping: [%w[user_id user_id], %w[color color]],
converter: proc { |user_id, color| Bar.new(user_id, color) }
end
class Bar
include ActiveModel::Model
attr_accessor :user_id, :color
def initialize(user_id, color)
@user_id = user_id
@color = color
end
def change_to_blue
self.color = "blue"
end
end
Is there a way to make it so if I update the bar object's color it also updates the Foo color?
Example
foo = Foo.last
foo.color = "yellow"
foo.bar.change_to_blue
puts foo.color
Currently the above would result in "yellow" but was wondering if it was possible to create the linkage back to Foo so that result is "blue"? I want to be able to do Foo.save! and the color would be updated to "blue"
CodePudding user response:
The Docs explain this concept fairly well.
Active Record implements aggregation through a macro-like class method called
composed_of
for representing attributes as value objects.
Value objects are immutable and interchangeable objects that represent a given value...It's also important to treat the value objects as immutable. Don't allow the [Bar] object to have its [color] changed after creation. Create a new [Bar] object with the new value instead.
Additionally I believe your converter
is incorrect as the converter is used in assignment and thus only passes a single value.
So I think the below is actually what you are looking for to change the color.
class Foo < ApplicationRecord
composed_of :bar,
mapping: [%w[user_id user_id], %w[color color]],
constructor: proc { |user_id, color| Bar.new(user_id, color) }
end
class Bar
include ActiveModel::Model
attr_reader :user_id, :color
def initialize(user_id, color)
@user_id = user_id
@color = color
end
def change_to_blue
self.class.new(user_id,'blue')
end
end
and then
foo = Foo.last
foo.color = "yellow"
foo.bar = foo.bar.change_to_blue
puts foo.color