使用多个模块覆盖 Ruby 中的相同类方法,需要调用 super.我是否使用方法别名或其他一些巧妙的技巧?
情况是这样的:
我有一个 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
是的,别名方法链在这种情况下会帮助你。
但请考虑使用委托模式。原始的 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.