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が呼び出されていることを証明しました.それはあなたが期待したことをしていないだけです.

私が気になることが 2 つあります。

1つは、@apneadivingが指摘したものと同じです。

Ruby でインスタンス変数に代入しようとするときは、 を使用する必要がありますself.roles。私がよくわからないのは、どのように機能するか<< xです。それが次のような構文糖衣である場合はroles= roles + xが必要ですがself.roles、そうである場合は必要ありroles.insert(x)ません。疑わしいときは、self.roles常に期待どおりに実行します。

私が懸念するもう1つのことは、<<永続化されていないモデルで使用していることです。その操作は破壊的であり、Role. おそらく最初にモデルを作成したときに関数を呼び出したので、このコードは永続化されていない場合にのみ実行されます。私はそれがほとんどうまくいくと思いますが、それがあなたが望むものかどうかはわかりません. 私はあなたがより良いと思う:

def attach_roles
  roles.build(Role.default)
end

Role.defaultこれは、が属性ハッシュを返していることを前提としています。私はあなたが意図したものについて間違っているかもしれません。

それが役立つことを願っています。

于 2013-01-15T01:13:59.693 に答える