題名が何いってるかわからんかもしれないのでどういうことか説明します。
ちょいちょい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 <a href="http://stackoverflow.com">http://stackoverflow.com</a>"
これを実現するのにそのクラス定義内に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]+)/)
- "<a href="#{matching[0]}">#{matching[0]}</a>"
- 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じゃないかなとか思うんだけど、万が一もっと簡潔な方法があったら教えてください。