我正在使用rails-settings gem,我正在尝试了解如何向ActiveRecord类添加函数(我正在为卡片游戏构建自己的库),我注意到这个gem使用了一个元编程技术将函数添加到ActiveRecord :: Base类(我远离ruby中的Meta-programming master,但我正在努力学习它)
module RailsSettings
class Railtie < Rails::Railtie
initializer 'rails_settings.initialize', :after => :after_initialize do
Railtie.extend_active_record
end
end
class Railtie
def self.extend_active_record
ActiveRecord::Base.class_eval do
def self.has_settings
class_eval do
def settings
RailsSettings::ScopedSettings.for_thing(self)
end
scope :with_settings, :joins => "JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
settings.thing_type = '#{self.base_class.name}')",
:select => "DISTINCT #{self.table_name}.*"
scope :with_settings_for, lambda { |var| { :joins => "JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
settings.thing_type = '#{self.base_class.name}') AND
settings.var = '#{var}'" } }
scope :without_settings, :joins => "LEFT JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
settings.thing_type = '#{self.base_class.name}')",
:conditions => 'settings.id IS NULL'
scope :without_settings_for, lambda { |var| { :joins => "LEFT JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
settings.thing_type = '#{self.base_class.name}') AND
settings.var = '#{var}'",
:conditions => 'settings.id IS NULL' } }
end
end
end
end
end
end
我不明白为什么他在ActiveRecord :: Base上使用class_eval,如果他只是打开ActiveRecord :: Base类并定义函数,这不是更容易吗?特别是块中没有动态(动态的含义是当你对包含变量的字符串执行class_eval或instance_eval时)
类似的东西:
module ActiveRecord
class Base
def self.has_settings
class_eval do
def settings
RailsSettings::ScopedSettings.for_thing(self)
end
scope :with_settings, :joins => "JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
settings.thing_type = '#{self.base_class.name}')",
:select => "DISTINCT #{self.table_name}.*"
scope :with_settings_for, lambda { |var| { :joins => "JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
settings.thing_type = '#{self.base_class.name}') AND
settings.var = '#{var}'" } }
scope :without_settings, :joins => "LEFT JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
settings.thing_type = '#{self.base_class.name}')",
:conditions => 'settings.id IS NULL'
scope :without_settings_for, lambda { |var| { :joins => "LEFT JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
settings.thing_type = '#{self.base_class.name}') AND
settings.var = '#{var}'",
:conditions => 'settings.id IS NULL' } }
end
end
end
end
我理解第二个class_eval(在def设置之前)是在'has_settings'对的每个类上动态定义函数吗?同样的问题,我认为他可以使用“def self.settings”而不是“class_eval .... def settings”,不是吗?
答案 0 :(得分:0)
rails-settings 代码的作用被认为是一种很好的做法:当明确要求时,它只会与第三方模块混淆。这样,您还可以将名称空间保持整齐分离,并且所有代码都保留在模块中。