# Best Pattern for 'repeatable' Model Concerns

**URL:** <https://discuss.rubyonrails.org/t/best-pattern-for-repeatable-model-concerns/81583>\
**Category:** rubyonrails-talk\
**Created:** [October 18, 2022, 6:59pm UTC](https://discuss.rubyonrails.org/t/best-pattern-for-repeatable-model-concerns/81583 "2022-10-18T18:59:03Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![matthewjsummers](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/matthewjsummers/32/8909_2.png) [@matthewjsummers](https://discuss.rubyonrails.org/u/matthewjsummers)\
**Post date:** [October 18, 2022, 6:59pm UTC](https://discuss.rubyonrails.org/t/best-pattern-for-repeatable-model-concerns/81583/1 "2022-10-18T18:59:03Z")

</div>

I have a concern that allows me to mark a model in my Rails app as “Durationable”. Something like this:

```ruby
module Durationable
  extend ActiveSupport::Concern

  included do
    attr_accessor :duration_years, :duration_months, ... etc

    after_initialize(unless: :new_record?) do |record|
      duration = record.read_attribute(durationable_field_name)

      @duration_years = record.duration&.parts&.dig(:years) || 0
      @duration_months = record.duration&.parts&.dig(:months) || 0
        ...etc
    end

    before_save do |record|
      record.duration = (@duration_years.to_i.years + @duration_months.to_i.months ... etc)
    end

  end
  
end

```

This worked fine on my model:

```ruby
class Task < ApplicationRecord
   include Durationable
end

```

It turns out that I now have a model that has two “duration” fields - say `booked_duration` and `actual_duration`. My concern doesn’t seem particularly well suited as it only copes with a single duration field.

I was thinking of being able to define my model with something like:

```ruby
class Task < ApplicationRecord
   include Durationable
   acts_as_duration :booked_duration
   acts_as_duration :actual_duration
end

```

I would then define a class method in the concern called `acts_as_duration` that manags an array of duration fields and add similar behaviour to the original concern, but operating over these multiple fields.

Does this seem like a good/suitable use of concerns? I can certainly get something functional working, but I wonder if there is a better suited pattern? It seems strange to `include Durationable` but that doesn’t actually do anything until a call to `acts_as_duration`?

Would really appreciate any thoughts on the best way to architect this.

---

<div class="post-metadata">

**Author:** ![walterdavis](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/walterdavis/32/705_2.png) [@walterdavis](https://discuss.rubyonrails.org/u/walterdavis)\
**Post date:** [October 18, 2022, 10:32pm UTC](https://discuss.rubyonrails.org/t/best-pattern-for-repeatable-model-concerns/81583/2 "2022-10-18T22:32:09Z")

</div>

That sounds like a good way to start. Another thing you might try is to look at how another gem “decorates” values. The money-rails gem has its `monetize` method [money-rails/monetizable.rb at main · RubyMoney/money-rails · GitHub](https://github.com/RubyMoney/money-rails/blob/main/lib/money-rails/active_record/monetizable.rb#L22-L152) which loops over the arguments passed to it and uses `define_method` internally to create the predictably named getters and setters for the attribute.

That’s a long method, and it does a lot more than what you’re trying to do, but if you squint and read through it a few times, the pattern should become clear.

As far as including Durationable, that’s probably just fine for this stage of your module. If you were to turn it into a Gem, then you’d want to allow it to register on the ActiveModel::Base so any of your classes could just use it without that extra line. Especially if you write it in such a way that it doesn’t do anything until you call your modifier class method to set it loose on a set of attributes…

Walter

---

<div class="post-metadata">

**Author:** ![e\_a](https://avatars.discourse-cdn.com/v4/letter/e/9fc348/32.png) [@e\_a](https://discuss.rubyonrails.org/u/e_a)\
**Post date:** [October 31, 2022, 4:50pm UTC](https://discuss.rubyonrails.org/t/best-pattern-for-repeatable-model-concerns/81583/3 "2022-10-31T16:50:43Z")

</div>

Since in Ruby a module is just an instance of class `Module` you can also just use normal object-oriented mechanics to have a constructor for your module which takes an argument allowing multiple different instances of the same class of module.

I wrote [an article](https://medium.com/@eric.programmer/arguments-for-included-modules-in-ruby-8056b9fa2743) a while back about this but the end result might end up looking like:

```ruby
class Task < ApplicationRecord
  include Durationable.new :booked
  include Durationable.new :actual
end

```
