# Duplication of enum across two models

In my Rails app, I have two classes each with the same enum for status. Code climate is complaining about duplication.

class Enrolment < ActiveRecord::Base
has_many :enrolment_presentations
has_many :presentations, through: :enrolment_presentations

enum status: {
'Pending' => 1,
'Suspended' => 2,
'Cancelled' => 3,
'Pass' => 4,
'Fail' => 5,
'DPR' => 6,
'Unknown' => 7,
'Enrolled' => 8
}
end

class EnrolmentPresentations < ActiveRecord::Base
belongs_to :enrolment
belongs_to :presentation

enum status: {
'Pending' => 1,
'Suspended' => 2,
'Cancelled' => 3,
'Pass' => 4,
'Fail' => 5,
'DPR' => 6,
'Unknown' => 7,
'Enrolled' => 8
}
end


How would you go about removing this duplication?

• Can you can clarify this? I don't understand why an EnrolmentPresentation would need an independent status attribute. Shouldn't it use the associated enrolment.status? – tokland Jan 21 '16 at 10:12
• You haven't explained the usage of these enums at all, as far as I'm concerned, you should just remove status from both classes because they are useless. Could you explain why you need them? – 200_success Jan 21 '16 at 15:39
• I don't see how you can say I should remove them because they are useless. Of course I have a usage for them, however it is not relevant, I have simplified the code to more clearly show the problem, that is duplication. Both models need a status field (this is a business requirement), the possible options/values available for the status on each model are the same. However, an Enrolment can have a status different from it's associated EnrolmentPresentations. – mdkrog Jan 23 '16 at 14:49

ActiveRecord enums "are exposed through a class method with the pluralized attribute name", so I recommend the following code. However, I would highly recommend making the enums symbols instead of strings for compatibility. Also, enrollment is spelled with two l's. Note that you can control the capitalization of DPR using inflections.

class Enrollment < ActiveRecord::Base
has_many :enrollment_presentations
has_many :presentations, through: :enrollment_presentations

enum status: {
pending: 1,
suspended: 2,
cancelled: 3,
pass: 4,
fail: 5,
dpr: 6,
unknown: 7,
enrolled: 8
}
end

class EnrollmentPresentations < ActiveRecord::Base
belongs_to :enrollment
belongs_to :presentation

enum status: Enrollment.statuses
end

• I've been meaning to change them to symbols (was more wondering about the duplication). Your solution of using the Enrollment.statuses is reasonable and I think I will go with that. Side note in US it is spelt Enrollment, UK (or outside of US) it can be spelt Enrolment :) – mdkrog Jan 21 '16 at 11:56

Forgive my ignorance, but isn't ActiveRecord::Base#enum just a method? Therefore, to help reduce duplication (but not eliminate it), you could do something like this:

STATUS_FLAGS = {
'Pending' => 1,
'Suspended' => 2,
'Cancelled' => 3,
'Pass' => 4,
'Fail' => 5,
'DPR' => 6,
'Unknown' => 7,
'Enrolled' => 8
}

class Enrolment < ActiveRecord::Base
has_many :enrolment_presentations
has_many :presentations, through: :enrolment_presentations

enum status: STATUS_FLAGS
end

class EnrolmentPresentations < ActiveRecord::Base
belongs_to :enrolment
belongs_to :presentation

enum status: STATUS_FLAGS
end


This, of course, doesn't eliminate duplication. One way around that might be to use a module as a mixin (though I'm not sure how that would work with ActiveRecord) or use singular inheritance to create a class that extends ActiveRecord::Base with the enum status, and then inherit from that - though I have to admit it feels hacky extending Active Records through inheritance.

As a stylistic note, it appears that the convention for #enum is to use lowercase names rather than PascalCase.

• Oh yes, you are right about "convention for #enum is to use lowercase names rather than PascalCase.". Also not a huge fan of monkey patching ActiveRecord classes. Where would STATUS_FLAGS live (i.e. what file), for it to be available to both classes? – mdkrog Jan 21 '16 at 7:46
• @mdkrog You'd put it in it's own file and require it, I suppose. – Dan Pantry Jan 21 '16 at 7:55