0

我已经阅读了与类似问题有关的大部分答案,但尚未找到解决方案。代码如下:

设置

class Person < ActiveRecord::Base
  # Other inconsequential code
  # ...
  has_and_belongs_to_many :roles
  before_validation: attach_roles
  # ...
  def attach_roles
    roles << Role.default if roles.blank?
  end
end

class Role < ActiveRecord::Base

  has_and_belongs_to_many: people

  def self.default
  #
  # Get default role
  #
  end

end

测试

require 'spec_helper'

RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods
end

describe Person do

  context "constructor" do

    it "creates a valid Person" do
      person = build(:person)
      person.should_receive(:attach_roles) # This works
      person.valid?
      puts person.roles.inspect # Returns []
    end    

    it "creates a another valid Person" do
      person = build(:person)
      person.valid?
      person.should be_valid # This fails
      puts person.roles.inspect # Returns []
    end

  end


end

问题

attach_roles回调似乎没有被调用。然而should_receive断言为真

在控制台中

p = FactoryGirl.build(:person)
p.roles # []
p.valid? # true
p.roles # [<Role>]

有人能解释一下吗?

旁注:也欢迎尝试创建默认角色的任何其他想法。

环境

  • 导轨3.2.1
  • 红宝石1.9.3
  • rspec 2.12.0
  • factory_girl 4.1.0
4

1 回答 1

1

您的should_receive测试证明attach_roles正在调用它,它只是没有按照您的预期进行。

我看到有两件事让我担心。

其中之一与@apneadiving 指出的相同。

在 Ruby 中尝试分配给实例变量时,您必须使用self.roles. 我不确定是如何<< x工作的。如果它是类似的语法糖,roles= roles + x那么你需要self.roles,但如果是,roles.insert(x)那么你不需要。当有疑问时,self.roles总是会做你所期望的。

我担心的另一件事是您正在使用<<尚未持久化的模型。该操作具有破坏性,并且会尝试将Role. 由于您可能在首次创建模型时调用了该函数,因此此代码仅在未持久化时才会运行。虽然我认为它主要是有效的,但我不确定这是否是你想要的。我认为你会更好:

def attach_roles
  roles.build(Role.default)
end

这假设它Role.default正在返回一个属性哈希。不过,我可能对您的意图有误。

我希望这会有所帮助。

于 2013-01-15T01:13:59.693 回答