How to handle the requirement for certain attributes in models that include a concern in Rails?

1

I'm working on a project where I have several models that share the behavior of being approvables . After a little research, I came to the conclusion that the best in this case is to use the concerns pattern with the help of ActiveSupport :: Concern . I confess that I really could not find much difference in relation to what other languages already do with the use of interfaces, if someone can clarify me better about it; appreciate. Going straight to the point, my concern about Approvable is as follows:

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

Some submissions are still pending, such as "approve" and "disapprove," but my question is as follows, every approved template will need to have and persist an approval_status attribute. How to model this without the use of inheritance? Is the "right" way simply to know that every approvable model must include this attribute? How to draw the tests? I create a simple object that includes the module?

    
asked by anonymous 23.11.2014 / 02:02

1 answer

1

Simple, before ActiveSupport :: Concerns you needed to include a one-lib module in ActiveRecord to be able to use a behavior, for example:

User.my_custom_method

Concerns, it has come to help in this sense, because we concentrate on writing our modules and we only include them in the Models that share the behaviors. The correct way to do this is precisely with Modules that has the concept of being something reusable that we inject into some client that uses it (in other languages we would do this after DI (Dependency Injection)). Inheritance conceptually is something that should be shared only for 'things' that are of the same type, which does not apply to you, since you are taking aproval_status behavior in different types.

To model this without using inheritance (which in this case is more correct) use the Concerns as you have been doing and just include the Module in Models that need to make use of the behavior you want to share:

class User
  include Approvable
end

And your User model will have the behavior:

User.approved?

To test you should create the files in the same test directory you created in the app folder. And test your module in isolation.

app path

app/models/concerns/aprovabble.rb

test path

spec/models/concerns/approvabble_spec.rb

And then test the modules that make use of shared behavior, for example: spec / models / user_spec.rb

expect(User.approved?).to eq(true)
    
24.11.2014 / 11:36