I have a class called
has_many: roles, through: user_roles
class User < ActiverRecord::Base
Role.all.pluck(:name).each do |role_name|
subject.roles << create(:role, name: 'foo')
expect(subject.foo?).to be true #<= undefined method `foo?' for #<User...>
The metaprogramming technique you're employing is meant to take advantage of the fact that code just sitting inside of a class is going to be executed when the class is loaded. So when Rails loads your
User class, at that moment the logic to define the predicate methods is being executed and methods are being created for whatever
Role.all returns at that moment when
User is loaded.
Creating a new role, as you do in the test, will therefore have no effect on what predicate methods were created when the class was loaded and the code was executed.
You can see this in action by creating a file called
count.rb in any directory with the following code inside:
$count += 1
irb and type:
irb(main):001:0> $count = 0 => 0 irb(main):002:0> require './count' => true irb(main):003:0> $count => 1
$count was incremented by one when the file was loaded. Now, if you were to
require the file again, nothing would happen. You could force the code to be re-loaded by using
load instead of 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
So to get your test to pass, you would have to create the role, then force a reload of the
User class, then make the assertion.