Bami Gaffald
Bami Gaffald

Reputation: 41

Dynamic define_method throwing error in RSpec

I am pretty sure I am missing a basic mistake here, so I am hoping another set of eyes might help. I am using Rails 3, Ruby 1.9.2 and Rspec 2.

I would like to define dynamic class methods on a model so that I can return base roles for an assignable object (such as account) as they are added to the system. For example:

BaseRole.creator_for_account

Everything works fine via the console:

ruby-1.9.2-p180 :003 > BaseRole.respond_to?(:creator_for_account)
 => true 

but when I run my specs for any of class methods, I get a NoMethodError wherever I call the method in the spec. I am assuming that something about how I am dynamically declaring the methods is not jiving with RSpec but I cannot seem to figure out why.

The lib dir is autoloaded path and the methods return true for respond_to?.

# /lib/assignable_base_role.rb
module AssignableBaseRole
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    BaseRole.all.each do |base_role|
      role_type = RoleType.find(base_role.role_type_id)
      assignable_name = base_role.assignable_type.downcase
      method = "#{role_type.name}_for_#{assignable_name}"

      define_method(method) do
        self.where(:role_type_id => role_type.id,
                :assignable_type => assignable_name).first
      end
    end 
  end
end

Then include the Module in BaseRole

# /models/base_role.rb
class BaseRole < ActiveRecord::Base
  include AssignableBaseRole

  belongs_to :role
  belongs_to :role_type

  ......
  ......

end

Then in my spec:

  it "adds correct authority for creator role" do
    create_assignment 
    base_role = BaseRole.creator_for_account # <== NoMethodError here
    user1 = Factory.create(:user)
    account.users << user1
    user1.roles_for_assignable(account).should include(base_role.role)
  end

Upvotes: 4

Views: 1165

Answers (2)

joffotron
joffotron

Reputation: 11

Did you have another class in your project or specs with the same name, but doesn't have the dynamic methods added? I had the exact same problem as you, and renaming one of the classes fixed it.

My guess is the other class is getting loaded first

Upvotes: 1

twmills
twmills

Reputation: 3015

It appears you are defining these methods based on values in the database:

BaseRole.all.each do |base_role|
.....

Could it be that "creator" doesn't exist in the test database as a role type, or "account" doesn't exist as assignable_type?

Presumably you are testing this in the console for development, not test, so the data could be mismatched. Might need to set up the data in a before hook.

Upvotes: 0

Related Questions