在 Ruby 中,如何验证 Struct 的身份?

Posted

技术标签:

【中文标题】在 Ruby 中,如何验证 Struct 的身份?【英文标题】:In Ruby, how does one verify the identity of a Struct? 【发布时间】:2018-11-06 12:41:01 【问题描述】:

我一直试图理解 Ryan Bates 在其 Presenters RailsCast (#287 Presenters from Scratch (pro) - RailsCasts) 中使用的 present 方法中的 self 类。在视频中,Ryan 说,“Self 是具有我们想要访问的所有辅助方法的模板对象”,但我想知道这个对象的类。在阅读了一系列博客文章、SO 线程和 Ruby 文档之后,我开始认为 self 是一种结构,但我不知道如何确认这个概念。

我的问题是:1) 在下面的 present 方法中,self 是 Struct?,以及 2) 如何验证某事是结构体?

module ApplicationHelper
  def present(object, klass = nil)
    klass ||= "#object.classPresenter".constantize
    presenter = klass.new(object, self)
    yield presenter if block_given?
    presenter
  end
end

我问这个是因为我没有太多使用Struct 类的经验,当我将binding.pry 粘贴在上述方法的中间并尝试获取self 的类名称时,我最终会遇到更多问题。

当我输入 self.class 时,我得到了 #<Class:0x007fb64f696268> 我想知道这里得到 Class 是否表明我有一个 Struct,但我找不到任何证实这一点的文档时间> 当我输入self.class.class 时,我得到Class

当我输入 self 时,我会得到一个以下面列出的代码行开头的扩展对象

@ line 16 ApplicationHelper#present:

14: def present(object, klass = nil)
15:   klass ||= "#object.classPresenter".constantize
16:   binding.pry
17:   presenter = klass.new(object, self)
18:   yield presenter if block_given?
19: end

[1] pry(#<#<Class:0x007fb64f696268>>)> self
=> #<#<Class:0x007fb64f696268>:0x007fb64f6948f0
@_assigns="marked_for_same_origin_verification"=>true,
@_config=,
@_controller=
  #<PostsController:0x007fb64f6762d8
   @_action_has_layout=true,
   @_action_name="show",
   @_config=,
   @_db_runtime=0,
   @_lookup_context=
    #<ActionView::LookupContext:0x007fb64f6760d0
      @cache=true,
      @details=
        :locale=>[:en],
        :formats=>[:html],
        :variants=>[],
        :handlers=>[:raw, :erb, :html, :builder, :ruby],
      @details_key=#<Concurrent::Map:0x007fb64f697938 entries=0 default_proc=nil>,
      @prefixes=["posts", "application"],
      @rendered_format=:html,
      @view_paths=
        #<ActionView::PathSet:0x007fb64f675fe0

post 有助于解释 Struct 的工作原理,但没有解释如何确认他们拥有 Struct。

最初,当我开始剖析present 方法时,我发现answer 很有帮助。但是,我被评论吓到了,说“ModelPresenter 是通过传递模型和 ApplicationHelper 类来初始化的”,因为 ApplicationHelper 是一个模块。

【问题讨论】:

请记住,您在这里接触的是 Rails 内部结构,Rails 内部结构并不简单、直接或有据可查。它非常令人困惑,并且需要很长时间才能消除所有魔法并理解它。 确实!我不想迷失在杂草中,但我也想花一些时间来挑战自己的错误假设,以便最终能够突破魔法。 【参考方案1】:

总结

使用is_a?(Struct)

解释

结构是匿名类的构造函数:

struct_class = Struct.new(:foo)
# => #<Class:0x007fa7e006ea98>

您可以检查匿名类的实例是否是这样的结构:

inst = struct_class.new
inst.class.superclass
# => Struct

但是Object#is_a? 检查父类以及超类:

inst.is_a?(Struct)
# => true

您可以在以下任意示例中看到相同的行为:

# inherits from String
anon_class = Class.new(String) 

inst = anon_class.new
# => ""

inst.class == String
# => false

inst.is_a?(String)
# => true

【讨论】:

问题是,当我提交self.is_a?(Struct) 时,我得到false 但是,self.class.superclass 返回 ActionView::Base... 最后,这让我更接近于我正在寻找的东西。谢谢你,@max-pleaner @GinnieHench 这表明Class.new(ActionView::Base) do ... end 用于动态创建ActionView::Base 的子类,其中包含一些额外的方法,并且不特定于相关视图。 嗯,我没有在我的应用程序中调用任何类似的方法,但是我在视图中调用了 erb 中的present 方法。通过在 pry 中运行 self.class.ancestors,我看到列出了一堆 ActionView::Helpers 以及其他 Rails 模块,所以我可以看到 Bates 提到的 self “拥有我们想要访问的所有帮助方法”,但我我仍然不能 100% 确定如何称呼 self....鉴于 self.is_a?(Object) 返回 true 并且 self.class.is_a?(Class) 返回 true,我必须接受 self 是来自 Class 类的对象。 Rails 通常会在需要为一堆东西(例如视图)提供隔离容器时创建匿名类。你没有这样做,Rails 是。然后 Rails 会将一堆模块(例如视图助手)混入匿名类中,并将实例变量从控制器复制到视图实例。

以上是关于在 Ruby 中,如何验证 Struct 的身份?的主要内容,如果未能解决你的问题,请参考以下文章

ruby 如何从用于客户端身份验证的X509证书中获取电子邮件。该电子邮件可用于在Devise或中设置当前用户

Ruby 使用标头进行身份验证的方法?

Ruby on Rails 中身份验证的最佳解决方案 [关闭]

Ruby/Rack 中的单点登录服务器身份验证

Ruby:摘要代理身份验证

ruby 使用rkerberos gem对使用Kerberos的用户进行身份验证,并将凭据存储在默认文件缓存中。不是