題名が何いってるかわからんかもしれないのでどういうことか説明します。
ちょいちょいActiveRecord::Baseのattributeだけにメソッドを足してこういう風に書きたいことがあった。
html_snippet = HtmlSnippet.find(1) html_snippet.content = "Link to http://stackoverflow.com" html_snippet.content.replace_url_to_anchor_tag! # => "Link to http://stackoverflow.com"
これを実現するのにそのクラス定義内にcontentにreplace_url_to_anchor_tag!を追加するメソッドを定義したかった。
ActiveRecordのクラスはこんなかんじ
# app/models/html_snippet.rb
class HtmlSnippet < ActiveRecord::Base
# I expected this bit to do what I want but not
class << @content
def replace_url_to_anchor_tag!
matching = self.match(/(https?:\/\/[\S]+)/)
"#{matching[0]}"
end
end
end
↑あきらかにClass classの@content(常にnil)にメソッドを定義してるため動かない。
1つの解;
頂いた回答によると、インスタンスメソッドの中で変数にメソッドを追加すればいい。ここでいうと`decorate_it`
class HtmlSnippet < ActiveRecord::Base
# getter is overrided to extend behaviour of freshly loaded values
def content
value = read_attribute(:content)
decorate_it(value) unless value.respond_to?(:replace_url_to_anchor_tag)
value
end
def content=(value)
dup_value = value.dup
decorate_it(dup_value)
write_attribute(:content, dup_value)
end
private
def decorate_it(value)
class << value
def replace_url_to_anchor_tag
# ...
end
end
end
end
なんかやりたいことに対してコーディング量がtoo muchじゃないかなとか思うんだけど、万が一もっと簡潔な方法があったら教えてください。