我正在开发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未定义。
有什么想法吗?
答案 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_missing
和Module.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类中,您可以通过调用:
选择性地从字段中删除htmlclass 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