Including a Module in a Rails 5 Application Writer
I am using Application Record to simplify common logic throughout my application.
Here's an example that writes the scope for boolean and inverse. This works well:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
def self.boolean_scope(attr, opposite = nil)
scope(attr, -> { where("#{attr}": true) })
scope(opposite, -> { where("#{attr}": false) }) if opposite.present?
end
end
class User < ApplicationRecord
boolean_scope :verified, :unverified
end
class Message < ApplicationRecord
boolean_scope :sent, :pending
end
The My Application Record class became quite long, and it made sense for me to split it into separate modules and load them as needed.
Here's my attempt at a solution:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
include ScopeHelpers
end
module ScopeHelpers
def self.boolean_scope(attr, opposite = nil)
scope(attr, -> { where("#{attr}": true) })
scope(opposite, -> { where("#{attr}": false) }) if opposite.present?
end
end
class User < ApplicationRecord
boolean_scope :verified, :unverified
end
class Message < ApplicationRecord
boolean_scope :sent, :pending
end
In this case, I don't get a download error, but boolean_scope
then undefined on User
and Message
.
Is there a way to ensure that included modules are loaded at the appropriate time and are available to the Application Record and its inheriting models?
I have also tried to get models to include modules directly and that didn’t solve the problem.
module ScopeHelpers
def self.boolean_scope(attr, opposite = nil)
scope(attr, -> { where("#{attr}": true) })
scope(opposite, -> { where("#{attr}": false) }) if opposite.present?
end
end
class User < ApplicationRecord
include ScopeHelpers
boolean_scope :verified, :unverified
end
class Message < ApplicationRecord
include ScopeHelpers
boolean_scope :sent, :pending
end
source to share
As an alternative to @ Pavan's answer, you can do this:
module ScopeHelpers
extend ActiveSupport::Concern # to handle ClassMethods submodule
module ClassMethods
def boolean_scope(attr, opposite = nil)
scope(attr, -> { where(attr => true) })
scope(opposite, -> { where(attr => false) }) if opposite.present?
end
end
end
# then use it as usual
class ApplicationRecord < ActiveRecord::Base
include ScopeHelpers
...
end
source to share
In this case I don't get the upload error, but the boolean_scope is then undefined for the user and the message
The problem lies in the include
methods of adding the class instance. You need to useextend
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
extend ScopeHelpers
end
Now you can call it like User.boolean_scope
. Below is an example include vs extend
module Foo
def foo
puts 'heyyyyoooo!'
end
end
class Bar
include Foo
end
Bar.new.foo # heyyyyoooo!
Bar.foo # NoMethodError: undefined method ‘foo’ for Bar:Class
class Baz
extend Foo
end
Baz.foo # heyyyyoooo!
Baz.new.foo # NoMethodError: undefined method ‘foo’ for #<Baz:0x1e708>
source to share