Rails Concerns questions

177 views Asked by At

I am starting to use the concerns pattern in a project and as this is the first time using it, some questions came to mind. First of all, let me share the code snipet I am working on for clarification.

module Approvable
    extend ActiveSupport::Concern

    included do
        #validations
        validates :approval_status,
                    presence: true,
                    inclusion: { :in => NixusValidation::ValidApprovalStatuses, :message => :inclusion, unless: 'approval_status.blank?' }
        #scopes:
            scope :approved, -> { where(approvalStatus: NixusValidation::ApprovalStatuses::APPROVED) }
            scope :pending, -> { where(approvalStatus: NixusValidation::ApprovalStatuses::PENDING) }
            scope :unapproved, -> { where(approvalStatus: NixusValidation::ApprovalStatuses::UNAPPROVED) }
    end

    #INSTANCE METHODS
    #methods:
    def approved?()
            self.approval_status == NixusValidation::ApprovalStatuses::APPROVED
    end
end

This concern defines common characteristics of an "approvable" model, something that needs to be approved like a join request for example. Every approvable model in my project have 3 states, approved, pending and unapproved. Here are some of my doubts about the code I wrote.

For this concern to work, the model needs to have an approval_status attribute, which needs to be persisted somehow. Is this wrong? Should concerns only define behaviour like interfaces? If not, how can I enforce the existence of this attribute in Rails? Is there a way to tell the rails model generator to always include this attribute in approvable models without inheritance?

I also need to implement an approve() method, but every approvable class has its own approvement proccess. The only thing in common is that if everything goes ok approved?() should return true afterwards. Is there a way to enforce the existence of the approve() method if a class includes the Approvable concern?

Is this a good case to use concerns?

Hope I made myself clear.

Thanks in advance,

1

There are 1 answers

1
bananabr On BEST ANSWER

@Surya,

Thanks for the idea. Just to see if I got this right, you are suggesting that I should have an ApprovalStatus class with a polymorphic relation to :approvable.

Something like:

class ApprovalStatus < ActiveRecord::Base
    belongs_to :approvable, polymorphic: true
end

class JoinRequest < ActiveRecord::Base
    has_one :approval_status, as: :approvable
end

class PatchInstallation < ActiveRecord::Base
    has_one :approval_status, as: :approvable
end

In this case the ApprovalStatus is the one that should handle the approvement business logic based on its caller right?