Ruby on rails ActiveRecord(Rails)中的层超类型

Ruby on rails ActiveRecord(Rails)中的层超类型,ruby-on-rails,activerecord,Ruby On Rails,Activerecord,我正在开发一个RubyonRails应用程序,我希望能够在每次保存之前在每个AR对象上执行一个方法 我想我应该创建一个像这样的图层超级类型: MyObject << DomainObject << ActiveRecord::Base module ActiveRecord class Base def my_method .... end end end 然后把它放在lib文件夹下 这不起作用,它告诉我我的方法是未定义的 有什么想法吗?尝试为域对象使

我正在开发一个RubyonRails应用程序,我希望能够在每次保存之前在每个AR对象上执行一个方法

我想我应该创建一个像这样的图层超级类型:

MyObject << DomainObject << ActiveRecord::Base
module ActiveRecord
  class Base
    def my_method .... end
  end
end
然后把它放在lib文件夹下

这不起作用,它告诉我我的方法是未定义的


有什么想法吗?

尝试为域对象使用抽象类

class DomainObject < ActiveRecord::Base
  self.abstract_class = true
  # your stuff goes here
end
class DomainObject
对于抽象类,您创建的模型不能有对象(不能实例化),也不能有关联的表

从严格的非类型化阅读

Rails启动时不会加载库中的文件。Rails已经覆盖了
Class.const_missing
Module.const_missing
以基于类名动态加载文件。事实上,这正是Rails加载模型和控制器的方式


因此,将文件放在lib文件夹中,Rails启动时将不会运行该文件,也不会对ActiveRecord::Base进行修补。您可以将文件放在
配置/初始值设定项中,但我认为还有更好的选择。

我在以前的工作中用于从模型中剥离HTML标记的另一种方法是创建插件。我们剥离的不仅仅是HTML标记,下面是HTML剥离部分:

初始值设定项(vendor/plugins/stripper/init.rb):

剥离代码(vendor/plugins/stripper/lib/active\u record/stripper.rb):

模块活动记录
模块剥离器
模块类方法
def strip_html(*args)
opts=args.extract\u选项!
self.strip\u html\u fields=args
验证前:剥离html
结束
结束
模块实例方法
def strip_html
self.class.strip_html_字段。每个{字段{strip_html_字段(字段)}
结束
私有的
def strip_html_字段(字段)
清除属性(字段,/]*>/,“”)
结束
def clean_属性(字段、正则表达式、替换)
self[field].gsub!(regex,替换)救援无
结束
结束
def自带(接收器)
receiver.class_可继承_访问器:strip_html_字段
receiver.extend类方法
receiver.send:包括,InstanceMethods
结束
结束
结束
然后在MyObject类中,您可以通过调用以下命令有选择地从字段中删除html:

class MyObject < ActiveRecord::Base
  strip_html :first_attr, :second_attr, :etc
end
class MyObject
已经给出的HTML剥离插件代码将处理问题中提到的特定用途。一般来说,向许多类(包括模块)添加相同的代码将很容易做到这一点,而不需要从某个公共基继承所有内容,也不需要向ActiveRecord本身添加任何方法

module MyBeforeSave
  def self.included(base)
    base.before_save :before_save_tasks
  end

  def before_save_tasks
    puts "in module before_save tasks"
  end
end

class MyModel < ActiveRecord::Base
  include MyBeforeSave
end

>> m = MyModel.new
=> #<MyModel id: nil>
>> m.save
in module before_save tasks
=> true
模块MyBeforeSave
def自带(基本)
base.before\u save:保存任务之前
结束
保存任务前定义
将“保存任务前放入模块”
结束
结束
类MyModel>m=MyModel.new
=> #
>>m.save
保存任务之前在模块中
=>正确

我想要monkeypatch ActiveRecord::Base并将文件放入配置/初始化器中:

class ActiveRecord::Base

  before_create :some_method

  def some_method
  end

end

谢谢迈克,这正是我的意思,你知道为什么lib文件夹下的monkeypatching不起作用吗?如果你能用这个更新答案,我相信它会被接受,我会结束这个问题。再次感谢您,如果您在ActiveRecord::Base中添加了内容,请将其放在lib目录中,并将其包含在environment.rb中。不过,我同意抽象类能更好地解决您的问题。模块方法有缺点。它只能由AR:Base的实例包含,每个类都必须包含它,如果您想添加更常见(不相关)的行为,您必须创建另一个模块。我不明白为什么继承是个问题,在每个类中包含一个模块并不比更改每个类的继承位置更麻烦。许多人会考虑一种新的模式,使每一类无关的行为成为一件好事,分离关注点。如果您在基础上添加3种类型的功能,但希望一个新类只有2种功能,那会怎么样?我宁愿在新类上有额外的方法,而不是在我域的每个类上都有3个include行。这是一个明确的继承案例,向问题抛出模块只会使问题更加复杂。检查你包含的方法,你确定它不是神秘的吗?我不是故意在这里粗鲁,我欣赏你的观点,我理解这是一个完全有效的观点,只是我不分享它。
module MyBeforeSave
  def self.included(base)
    base.before_save :before_save_tasks
  end

  def before_save_tasks
    puts "in module before_save tasks"
  end
end

class MyModel < ActiveRecord::Base
  include MyBeforeSave
end

>> m = MyModel.new
=> #<MyModel id: nil>
>> m.save
in module before_save tasks
=> true
class ActiveRecord::Base

  before_create :some_method

  def some_method
  end

end