比如我有两个 model,里面都有一个叫做 generate 的方法,是 before_save 的 callback,但这两个 generate 的方法里面的内容只是类似,如下
#model1的generate
before_save :generate
def generate
self.slug = self.title.gsub(' ', '-').downcase
end
#model2的generate
before_save :generate
def generate
self.slug = self.name.gsub(' ', '-').downcase
end
现在我想把这两个方法弄成一个 module,问题是我想要还是能够用 before_save 来调用,但方法里面的内容又不大一样,不知道要怎么做才好,请教一下各位
module Slug
module ClassMethods
def generate_slug field
before_save generate_slug_field(field)
end
end
module InstanceMethods
def generate_slug_field field
self.slug = self.send(field).gsub(' ', '-').downcase
end
end
def self.included(receiver)
receiver.extend ClassMethods
receiver.send :include, InstanceMethods
end
end
试试行不行,随手写的
before_save 也可以是个 block
before_save { |r| r.slug = r.generate_slug_field(field) }
class UtilObserver < ActiveRecord::Observer
observe :model1, :model2
def before_save(record)
record.slug = record.slug_format
end
end
module Model1
def slug_format
self.title.gsub(' ', '-').downcase
end
end
module Model2
def slug_format
self.name.gsub(' ', '-').downcase
end
end
你的场景非常类似 Ruby China 的 Markdown 处理动作,可以参考这个文件: https://github.com/ruby-china/ruby-china/blob/master/app/models/mongoid/markdown_body.rb
我觉得可以考虑将它抽取成类:
class SlugGenerator
def self.generate(slug_base)
slug_base.gsub(' ', '-').downcase
end
end
module Model1
before_save :generate
def generate
self.slug = SlugGenerator.generate(self.title)
end
end
module Model2
before_save :generate
def generate
self.slug = SlugGenerator.generate(self.name)
end
end
抽取主要逻辑到类中,解耦并且便于测试。
以下代码手写,没实际跑过,你可以看看这个写法和思路
module MarkdownBody
extend ActiveSupport::Concern
included do
end
def markdown_content_with_field(field)
self.body_html = MarkdownTopicConverter.format(self.send(field)) if self.send("#{field}_changed?")
end
module ClassMethods
def markdown_body(body_field)
class_eval %(
before_save do
markdown_content_with_field('#{body_field}')
end
)
end
end
end
class Post
include MarkdownBody
field :content
markdown_body :content
end
class Comment
include MarkdownBody
field :comment
markdown_body :comment
end
还有你可以看看我之前写的 redis-search 的某个文件:https://github.com/huacnlee/redis-search/blob/master/lib/redis/search/base.rb