ActiveRecord中的图层超类型(Rails)

时间:2009-02-28 15:45:07

标签: ruby-on-rails activerecord

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

我以为我会创建一个像这样的超级类型:

MyObject << DomainObject << ActiveRecord::Base

并使用我的特殊方法(基本上从对象的字符串属性中删除所有标记,如“H1”)将DomainObject放入回调(before_save)。

问题是rails要求domain_object表,我显然没有。

我的第二次尝试是monkeypatch活跃记录,如下所示:

module ActiveRecord
  class Base
    def my_method .... end
  end
end

把它放在lib文件夹下。

这不起作用,它告诉我my_method未定义。

有什么想法吗?

4 个答案:

答案 0 :(得分:4)

尝试为您的域对象使用抽象类。

class DomainObject < ActiveRecord::Base
  self.abstract_class = true
  # your stuff goes here
end

使用抽象类,您将创建一个不能拥有对象(无法实例化)且没有关联表的模型。

从Strictly Untyped阅读Rails: Where to put the 'other' files

  

当Rails启动时,不会加载lib中的文件。 Rails重写了Class.const_missingModule.const_missing,以根据类名动态加载文件。实际上,这正是Rails加载模型和控制器的方式。

所以将文件放在lib文件夹中,当Rails启动时它不会运行,也不会修补ActiveRecord :: Base。您可以将文件放在config/initializers中,但我认为有更好的选择。

答案 1 :(得分:1)

我在之前的工作中用于从模型中剥离HTML标记的另一种方法是创建一个插件。我们剥离的不只是HTML标签,但这里是HTML剥离部分:

初始化程序(vendor / plugins / stripper / init.rb):

require 'active_record/stripper'
ActiveRecord::Base.class_eval do
  include ActiveRecord::Stripper
end

剥离代码(vendor / plugins / stripper / lib / active_record / stripper.rb):

module ActiveRecord
  module Stripper
    module ClassMethods
      def strip_html(*args)
        opts = args.extract_options!
        self.strip_html_fields = args
        before_validation :strip_html
      end
    end

    module InstanceMethods
      def strip_html
        self.class.strip_html_fields.each{ |field| strip_html_field(field) }
      end
    private
      def strip_html_field(field)
        clean_attribute(field, /<\/?[^>]*>/, "")
      end
      def clean_attribute(field, regex, replacement)
        self[field].gsub!(regex, replacement) rescue nil
      end
    end

    def self.included(receiver)
      receiver.class_inheritable_accessor :strip_html_fields
      receiver.extend         ClassMethods
      receiver.send :include, InstanceMethods
    end
  end
end

然后在MyObject类中,您可以通过调用:

选择性地从字段中删除html
class MyObject < ActiveRecord::Base
  strip_html :first_attr, :second_attr, :etc
end

答案 2 :(得分:1)

已经提供的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

答案 3 :(得分:0)

我monkeypatch ActiveRecord :: Base并将文件放在config / initializers中:

class ActiveRecord::Base

  before_create :some_method

  def some_method
  end

end