# using dry-struct for mutable entities

**URL:** <https://discourse.dry-rb.org/t/using-dry-struct-for-mutable-entities/1649>\
**Category:** Support\
**Created:** [April 11, 2023, 4:05pm UTC](https://discourse.dry-rb.org/t/using-dry-struct-for-mutable-entities/1649 "2023-04-11T16:05:00Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![krisleech](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/krisleech/32/19_2.png) [@krisleech](https://discourse.dry-rb.org/u/krisleech)\
**Post date:** [April 11, 2023, 4:05pm UTC](https://discourse.dry-rb.org/t/using-dry-struct-for-mutable-entities/1649/1 "2023-04-11T16:05:00Z")

</div>

I’ve been thinking about using `Dry::Struct` for entities, but they must be mutable.

To set the attributes, post-initialization, from within the object I can use `@attributes[:key] = 'whatever'` but I’m guessing this isn’t part of the public API, so subject to breaking in future releases.

This is an example of what I want to do:

```ruby
class Issue < Dry::Struct
  include Types

  attribute :title, String
  attribute? :resolved_at, HappenedAt
  attribute? :resolved_by, UserId

  def resolve(by:, at:)
    @attributes[:resolved_at] = at
    @attributes[:resolved_by] = by.id
    self
  end

  def resolved?
    !resolved_at.nil?
  end
end

issue = Issue.new(title: 'Shipment Delayed')
issue.resolve(by: current_user, at: Time.now )

```

Maybe this is outside the use case for dry-struct?

---

<div class="post-metadata">

**Author:** ![alassek](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/alassek/32/314_2.png) [@alassek](https://discourse.dry-rb.org/u/alassek)\
**Post date:** [April 11, 2023, 4:21pm UTC](https://discourse.dry-rb.org/t/using-dry-struct-for-mutable-entities/1649/2 "2023-04-11T16:21:43Z")

</div>

`Dry::Struct` is designed to be immutable. This means that changes to the data use a [CoW](https://en.wikipedia.org/wiki/Copy-on-write) strategy instead of mutation.

```ruby
class Issue < Dry::Struct
  include Types

  attribute :title, String
  attribute? :resolved_at, HappenedAt
  attribute? :resolved_by, UserId

  def resolve(by:, at:)
    return self if resolved_at && resolved_by
    new(resolved_at: at, resolved_by: by.id)
  end

  def resolved?
    !resolved_at.nil?
  end
end

issue = Issue.new(title: 'Shipment Delayed')
issue = issue.resolve(by: current_user, at: Time.now)

```

---

<div class="post-metadata">

**Author:** ![krisleech](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/krisleech/32/19_2.png) [@krisleech](https://discourse.dry-rb.org/u/krisleech)\
**Post date:** [April 11, 2023, 4:53pm UTC](https://discourse.dry-rb.org/t/using-dry-struct-for-mutable-entities/1649/3 "2023-04-11T16:53:41Z")

</div>

Thanks for the clarification, it feels like Clojure’s persistent data structures in that respect.

```ruby
    def resolve(by:, at:)
      new(attributes.merge(
        resolved_at: at,
        resolved_by: by.id
      ))
    end

```

---

<div class="post-metadata">

**Author:** ![alassek](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/alassek/32/314_2.png) [@alassek](https://discourse.dry-rb.org/u/alassek)\
**Post date:** [April 12, 2023, 4:06am UTC](https://discourse.dry-rb.org/t/using-dry-struct-for-mutable-entities/1649/4 "2023-04-12T04:06:42Z")

</div>

There is no need to explicitly merge `attributes`, `Struct#new` will do that for you.
