[英]Metaprogramming predicate methods inside a Class - Rails 4
我有一个名为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(&:name)
确实返回了现有角色名称的数组,但define_method
从未被调用,并且我的规范因未定义方法而失败:
...
subject.roles << create(:role, name: 'foo')
expect(subject.foo?).to be true #<= undefined method `foo?' for #<User...>
...
您正在使用的元编程技术旨在利用这样的事实,即,当类加载时,将执行位于类内部的代码。 因此,当Rails加载User
类时,此时将执行定义谓词方法的逻辑,并且Role.all
User
加载时那个 Role.all
返回的内容创建方法。
因此,正如您在测试中所做的那样,创建新角色将不会对加载类和执行代码时创建的谓词方法产生任何影响。
您可以在其中包含以下代码的任何目录中创建一个名为count.rb
的文件,以查看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
类,然后进行断言。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.