【问题标题】:Metaprogramming predicate methods inside a Class - Rails 4类中的元编程谓词方法 - Rails 4
【发布时间】:2016-08-01 03:54:14
【问题描述】:

我有一个名为User 的类,它是has_many: roles, through: user_roles。我正在尝试为用户类中的关联角色元编程谓词方法,如下所示:

class User < ActiverRecord::Base 
...      
  Role.all.pluck(:name).each do |role_name|
    define_method("#{role_name}?") do
      roles.map(&:name).include?(role_name)
    end
  end
...
end

虽然Role.all.pluck(&amp;:name) 确实返回了一个现有角色名称的数组,但define_method 永远不会被调用,并且我的规范因未定义的方法而失败:

  ...
  subject.roles << create(:role, name: 'foo')
  expect(subject.foo?).to be true #<= undefined method `foo?' for #<User...>
  ...

【问题讨论】:

  • 应该是pluck(:name),没有&amp;。这可能会破坏集合的构建,导致 define_method 永远不会被调用。
  • @sixty4bit 哎呀,更新了。我决定用pluck 替换.map,却忘了删除to_proc。但是仍然返回undefined method
  • 啊哈。在那种情况下,我认为答案可能更根本地在于元编程是如何工作的。您的Role.all... 逻辑在User 类加载时执行,即在测试运行之前。因此,将定义的唯一方法将用于在加载 User 之前已经存在的角色。在 User 加载后,在测试中创建角色不会对之前运行的代码产生任何影响。希望这是有道理的......

标签: ruby-on-rails ruby metaprogramming predicate


【解决方案1】:

您使用的元编程技术旨在利用这样一个事实,即在加载类时将执行仅位于类内部的代码。因此,当 Rails 加载您的 User 类时,在那一刻正在执行定义谓词方法的逻辑,并且正在为 Role.all 返回的任何方法创建方法在 @987654323 的那一刻@ 已加载

因此,正如您在测试中所做的那样,创建新角色不会影响加载类和执行代码时创建的谓词方法。

您可以通过在任何目录中创建一个名为 count.rb 的文件来查看此操作,其中包含以下代码:

$count += 1

然后,打开 irb 并输入:

irb(main):001:0> $count = 0
=> 0
irb(main):002:0> require './count'
=> true
irb(main):003:0> $count
=> 1

注意$count 在文件加载时加一。现在,如果你再次require 文件,什么都不会发生。您可以通过使用 load 而不是 require 来强制重新加载代码:

# ...continued from above
irb(main):004:0> require './count'
=> false
irb(main):005:0> $count
=> 1
irb(main):006:0> load './foo.rb'
=> true
irb(main):007:0> $count
=> 2

因此,要让您的测试通过,您必须创建角色,然后强制重新加载 User 类,然后进行断言。

【讨论】:

  • 绝对!最终将此测试逻辑移动到Role 的单元测试中,以便在创建新角色后实例化User
  • 虽然这是一个提供有效测试的答案,但我不会采用这种方法。这样,除非冷重启/重新加载,否则向应用程序添加新角色不会有任何影响。我会在Role#after_commit 上定义一个回调,更新User 类中的谓词方法。
  • 明确一点:我并没有试图在我的回答中暗示这是一种应该在应用程序代码中实现的方法。我只是想解释 为什么 @Dimitry_N 在测试中遇到这个问题,以确保他了解底层元编程概念的工作原理等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 2013-06-11
相关资源
最近更新 更多