class_evalの使用を理解しようとしています
-
11-10-2019 - |
質問
私は使用しています Rails-Settings gem、そして私はあなたがActiverecordクラスに関数を追加する方法を理解しようとしています(私はカードゲームのために自分のライブラリを構築しています)。 ::基本クラス(私はRubyのメタプログラミングマスターとはほど遠いですが、私はそれを学ぼうとしています)
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
2番目のclass_eval(def settingsの前)は、「has_settings」というクラスのすべてのクラスでその場で機能を定義することであることを理解していますか?ここで同じ質問、彼は「class_eval .... def settings」の代わりに「def self.settings」を使用できると思います。
解決
何 Rails-Settings コードは良い練習と見なされます。それは、明示的にそうするように求められている場合にのみ、サードパーティモジュールを台無しにします。このようにして、名前空間を整然と分離し、すべてのコードをモジュールに残します。
所属していません StackOverflow