Ruby on rails 向Ruby中的属性添加方法

Ruby on rails 向Ruby中的属性添加方法,ruby-on-rails,ruby,methods,metaprogramming,Ruby On Rails,Ruby,Methods,Metaprogramming,如何在Ruby中为实例的属性定义方法 假设我们有一个名为HtmlSnippet的类,它扩展了Rails的ActiveRecord::Base,并具有一个属性content。而且,我想定义一个方法来替换\uURL\u到\uAnchor\u标记!并通过以下方式调用它 html_snippet = HtmlSnippet.find(1) html_snippet.content = "Link to http://stackoverflow.com" html_snippet.content.repl

如何在Ruby中为实例的属性定义方法

假设我们有一个名为HtmlSnippet的类,它扩展了Rails的ActiveRecord::Base,并具有一个属性content。而且,我想定义一个方法来替换\uURL\u到\uAnchor\u标记!并通过以下方式调用它

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>"



# 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

有什么建议吗?

您的代码无法运行的原因很简单-您使用的@content在执行上下文中为零。self是类,而不是实例。所以你们基本上是在修改零的本征类

因此,您需要在设置@content时扩展它的实例。有几种方法,只有一种:

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

Wihtout dup您不仅扩展了x.content,还扩展了您分配的原始字符串。

oops,我总是通过注释而不是Stackoverflow中的任何操作来表示感谢。我会为此做的time@oldergod你能给我一个样品吗?哇,太棒了!我知道如何访问类中的实例属性。
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
x = "something"
s = HtmlSnippet.find(1)
s.content = x

s.content.replace_url_to_anchor_tag # that's ok
x.content.replace_url_to_anchor_tag # that's not ok