У меня есть класс под названием User
, который has_many: roles, through: user_roles
. Я пытаюсь метапрограммных предикатные методы связанных ролей внутри класса пользователей, как так:Методы предикатов метапрограммирования внутри класса - Rails 4
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...>
...
Это должно быть 'pluck (: name)' без '&'. Это может отбросить здание коллекции, что приведет к тому, что 'define_method' никогда не будет вызван. – sixty4bit
@ sixty4bit oops, обновлено. Я решил заменить '.map' на' pluck' и забыл удалить 'to_proc'. Тем не менее возвращает 'undefined method' однако –
Ah ha. В этом случае, я думаю, ответ может быть более фундаментальным в том, как работает метапрограммирование. Логика 'Role.all ...' выполняется, когда загружается класс 'User', который находится перед запуском теста. Таким образом, единственные методы, которые будут определены, будут для ролей, которые уже существовали до загрузки пользователя. Создание роли в вашем тесте после загрузки «Пользователь» не повлияет на предыдущий код. Надеюсь, это имеет смысл ... – sixty4bit