是否可以从同名方法中调用先前定义的方法?

时间:2018-08-22 07:48:41

标签: ruby-on-rails

是否可以覆盖一个方法而仍然回退到原始方法(如果不涉及任何超类)?

def User
  def method
    # do some original stuff
  end
  def method
    # do some new stuff
    call_the_original :method
  end
end

希望我的具体例子可以使我的意思更清楚。

在用户模型中使用活动存储has_one_attached :avatar将添加一个setter方法。调用此setter时,我想做一些事情,但我仍然希望运行原始方法。

class User 
  has_one_attached :avatar
  # According to the source (see references) this mixes in the following setter method 
  def avatar=(attachable)
    # do activestorage stuff 
  end 

  # I want to add some custom functions to this, before still running "do activestorage
  # stuff". I could copy, paste and edit the entire function. But out of interest, 
  # I wondered if a more elegant solution exists. 
  def avatar=(attachable)
    # do my stuff
    super(attachable)
  end
end

super显然不起作用,因为用户没有从定义了avatar=()的任何内容继承。

我可以创建例如包含MasterUser且继承自has_one_attached的{​​{1}}类,但是对于这种特殊情况,这似乎有些过分。

我可以提交给User的{​​{1}}

但是对于这个问题,我真正感兴趣的是是否有一种方法可以从同名方法中调用先前定义的方法?

参考

2 个答案:

答案 0 :(得分:3)

您可以在此处使用alias_method来访问先前的定义:

class User 
  def avatar=(attachable)
    # do activestorage stuff 
  end 
  alias_method :original_avatar=, :avatar=

  def avatar=(attachable)
    # do my stuff
    self.original_avatar=(attachable)
  end
end

答案 1 :(得分:2)

另一种选择是将旧方法保存在变量中,然后再定义具有相同名称的新方法。然后从新定义的方法内部调用变量:

class User 
  def avatar=(attachable)
    # do activestorage stuff 
  end 

  instance_method(:avatar=).tap do |avatar_eq|
    define_method(:avatar=) do |attachable|
      # do my stuff
      avatar_eq.bind(self).call(attachable)
    end
  end
end

在上面的示例中,必须使用define_method(:avatar=),因为常规的def avatar=不允许您访问avatar_eq变量。

代码比JagdeepSinghs answer复杂一些,但是使类的方法不那么混乱。不再定义旧方法,因此无法再单独调用。

参考