sea*_*vis 4 ruby metaprogramming ruby-on-rails ruby-on-rails-5
I am using Application Record to simplify shared logic throughout an application.
Here's an example that writes a scope for a boolean and its 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
Run Code Online (Sandbox Code Playgroud)
My Application Record class got long enough it made sense for me to break it up into individual modules and load those as needed.
Here's my attempted 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
Run Code Online (Sandbox Code Playgroud)
In this case, I don't get a load error, but boolean_scope is then undefined on User and Message.
Is there a way to ensure the included modules are loaded at the appropriate time and available to Application Record and its inheriting models?
I've also attempted to have the models include the modules directly and that did not fix the issue.
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
Run Code Online (Sandbox Code Playgroud)
作为@Pavan答案的替代方法,您可以执行以下操作:
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1072 次 |
| 最近记录: |