使用多个模块覆盖 Ruby 中的相同类方法,需要调用 super.我是否使用方法别名或其他一些巧妙的技巧?

发布于 2024-08-31 18:07:16 字数 1652 浏览 11 评论 0原文

情况是这样的:

我有一个 User 模型和两个用于身份验证的模块:Oauth 和 Openid。它们都重写了ActiveRecord#save,并且具有公平的实现逻辑。

鉴于我可以判断用户何时尝试通过 Oauth 与 Openid 登录,但它们都已覆盖 save,那么“finally”如何覆盖 save 以便我可以有条件地调用它的模块实现之一吗?

这是我所描述的基本结构:

module UsesOauth

  def self.included(base)
    base.class_eval do
      def save
        puts "Saving with Oauth!"
      end

      def save_with_oauth
        save
      end
    end
  end

end

module UsesOpenid

  def self.included(base)
    base.class_eval do
      def save
        puts "Saving with OpenID!"
      end

      def save_with_openid
        save
      end
    end
  end

end

module Sequencer

  def save
    if using_oauth?
      save_with_oauth
    elsif using_openid?
      save_with_openid
    else
      super
    end
  end

end

class User < ActiveRecord::Base
  include UsesOauth
  include UsesOpenid
  include Sequencer
end

我正在考虑使用 alias_method 像这样,但这太复杂了,因为我可能还有 1 或 2 个类似的模块。我还尝试使用那些 save_with_oauth 方法(如上所示),这几乎有效。唯一缺少的是我还需要调用 ActiveRecord::Base#save (超级方法),所以像这样:

def save_with_oauth
  # do this and that
  super.save
  # the rest
end

但我不允许在 ruby​​ 中这样做。

有什么聪明的解决方案吗?

这是 alias_method_chain 会做的吗?我避免这样做,因为人们似乎说这是一个坏主意。

(边走边查找):

Here's the situation:

I have a User model, and two modules for authentication: Oauth and Openid. Both of them override ActiveRecord#save, and have a fair share of implementation logic.

Given that I can tell when the user is trying to login via Oauth vs. Openid, but that both of them have overridden save, how do "finally" override save such that I can conditionally call one of the modules' implementations of it?

Here is the base structure of what I'm describing:

module UsesOauth

  def self.included(base)
    base.class_eval do
      def save
        puts "Saving with Oauth!"
      end

      def save_with_oauth
        save
      end
    end
  end

end

module UsesOpenid

  def self.included(base)
    base.class_eval do
      def save
        puts "Saving with OpenID!"
      end

      def save_with_openid
        save
      end
    end
  end

end

module Sequencer

  def save
    if using_oauth?
      save_with_oauth
    elsif using_openid?
      save_with_openid
    else
      super
    end
  end

end

class User < ActiveRecord::Base
  include UsesOauth
  include UsesOpenid
  include Sequencer
end

I was thinking about using alias_method like so, but that got too complicated, because I might have 1 or 2 more similar modules. I also tried using those save_with_oauth methods (shown above), which almost works. The only thing that's missing is that I also need to call ActiveRecord::Base#save (the super method), so something like this:

def save_with_oauth
  # do this and that
  super.save
  # the rest
end

But I'm not allowed to do that in ruby.

Any ideas for a clever solution to this?

Is that what alias_method_chain would do? I've avoided that because people seemed to say it was a bad idea.

(Finding things as I go):

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

懒的傷心 2024-09-07 18:07:16

是的,别名方法链在这种情况下会帮助你。

但请考虑使用委托模式。原始的 save 方法会触发特殊委托对象(也可以是 nil)的回调,并且它会在保存用户时执行任何需要执行的操作。

另外,还有一个由名为 Observer 的 actve record 直接支持的类似模式,尝试阅读有关它的内容,也许这也是一个很好的解决方案。

我并不是说这种链接方法是错误的,但有更干净的方法来实现你想要的。

Yes alias method chain would help you in this situation.

But consider using delegate pattern. Original save method would trigger a callback on special delegate object (which can be as well nil) and it would do whatever needs to be done when saving user.

Also there is simliar pattern supported directly by actve record called Observer, try to read somethng about it maybe that's a good solution too.

I'm not saying this chaining methods is wrong, but there are cleaner ways to achieve what you want.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文