ruby on rails - rspec परीक्षण है has_many: through और after_save




ruby-on-rails has-many-through (2)

मेरा अनुमान है कि आपको @thing.reload Thing करके @thing.reload पुनः लोड करने की आवश्यकता है। रीलोड (मुझे यकीन है कि इस से बचने का एक तरीका है, लेकिन इससे पहले कि आपका परीक्षा पास हो सकती है और फिर आप यह समझ सकते हैं कि आप गलत कहां गए )।

कुछ सवाल:

मुझे नहीं लगता कि आप @thing.save को अपनी कल्पना में बुला रहे हैं। क्या आप ऐसा कर रहे हैं, बस आपके सांत्वना उदाहरण की तरह?

आप t.save क्यों बुला रहे हैं और आपकी कंसोल परीक्षा में नहीं हैं, क्या आप u पर t को धक्का दे रहे हैं? सहेजा जा रहा है u को सहेजने के लिए ट्रिगर करना चाहिए, आपको अंतिम परिणाम प्राप्त करना चाहिए, और मुझे लगता है कि यह वास्तव में आप पर काम कर रहे हैं, "टी और अधिक समझ में आता है", न कि

मेरे पास एक (मुझे लगता है) तुलनात्मक रूप से सीधा- has_many :through एक शामिल तालिका के साथ संबंध के has_many :through :

class User < ActiveRecord::Base
  has_many :user_following_thing_relationships
  has_many :things, :through => :user_following_thing_relationships
end

class Thing < ActiveRecord::Base
  has_many :user_following_thing_relationships
  has_many :followers, :through => :user_following_thing_relationships, :source => :user
end

class UserFollowingThingRelationship < ActiveRecord::Base
  belongs_to :thing
  belongs_to :user
end

और ये आरएसपीईसी परीक्षण (मुझे पता है कि यह जरूरी नहीं कि अच्छे परीक्षण हैं, ये सिर्फ यह समझाने के लिए है कि क्या हो रहा है):

describe Thing do     
  before(:each) do
    @user = User.create!(:name => "Fred")
    @thing = Thing.create!(:name => "Foo")    
    @user.things << @thing
  end

  it "should have created a relationship" do
    UserFollowingThingRelationship.first.user.should == @user
    UserFollowingThingRelationship.first.thing.should == @thing
  end

  it "should have followers" do
    @thing.followers.should == [@user]
  end     
end

यह ठीक काम करता है जब तक मैं एक after_save को Thing मॉडल में after_save हूं जो इसके followers संदर्भ देता है। यही है, अगर मैं करता हूँ

class Thing < ActiveRecord::Base
  after_save :do_stuff
  has_many :user_following_thing_relationships
  has_many :followers, :through => :user_following_thing_relationships, :source => :user

  def do_stuff
    followers.each { |f| puts "I'm followed by #{f.name}" }
  end
end

फिर दूसरा परीक्षण विफल रहता है - यानी, रिश्ते को अब भी शामिल होने के टेबल में जोड़ा जाता है, लेकिन @thing.followers एक खाली सरणी देता है। इसके अलावा, कॉलबैक का वह भाग कभी नहीं बुलाता (जैसे कि followers मॉडल के भीतर खाली हैं)। यदि मैं followers.each सामने कॉलबैक में puts "HI" हूं .ईच लाइन, "HI" stdout पर दिखाई देता है, इसलिए मुझे पता है कि कॉलबैक को बुलाया जा रहा है। अगर मैं followers.each टिप्पणी करता हूं। followers.each लाइन, तो परीक्षा फिर से गुज़रती हैं।

यदि मैं कंसोल के माध्यम से यह सब करता हूं, तो यह ठीक काम करता है। यानी, मैं कर सकता हूँ

>> t = Thing.create!(:name => "Foo")
>> t.followers # []
>> u = User.create!(:name => "Bar")
>> u.things << t
>> t.followers  # [u]
>> t.save    # just to be super duper sure that the callback is triggered
>> t.followers  # still [u]

यह आरएसपीसी में क्यों असफल है? क्या मैं कुछ गलत कर रहा हूं?

अद्यतन करें

सब कुछ तब भी काम करता है जब मैं खुद Thing#followers को मैन्युअल रूप से परिभाषित करता हूं

def followers
  user_following_thing_relationships.all.map{ |r| r.user }
end

यह मुझे विश्वास करने की ओर जाता है कि शायद मैं अपने has_many :through परिभाषित कर रहा हूँ has_many :through से :source गलत है?

अद्यतन करें

मैंने एक न्यूनतम उदाहरण प्रोजेक्ट बनाया है और इसे गिटब पर डाल दिया है: https://github.com/dantswain/RspecHasMany

एक और अपडेट

पीटर पैनिक्स और @किकुचियो को अपने सुझावों के लिए नीचे एक टन धन्यवाद अंतिम उत्तर दोनों उत्तरों के संयोजन के रूप में निकले और मुझे लगता है कि मैं उन दोनों के बीच क्रेडिट विभाजित कर सकता हूं। मैंने जीथूब प्रोजेक्ट को अपडेट किया है जो मुझे लगता है कि यह सबसे साफ समाधान है और बदलावों को धक्का दे दिया है: https://github.com/dantswain/RspecHasMany

मैं अभी भी इसे प्यार करता हूँ अगर कोई मुझे यहाँ पर क्या हो रहा है की एक ठोस ठोस व्याख्या दे सकता है मेरे लिए सबसे अधिक परेशान सा क्यों है, प्रारंभिक समस्या बयान में, (कॉलबैक के संचालन को छोड़कर सभी) काम करेंगे अगर मैं followers के संदर्भ को टिप्पणी करता हूं


नवीनीकृत उत्तर ** यह आरएसपीसी पास करता है, बिना कूल्हे के, सहेजने के लिए कॉलबैक चल रहा है (after_save कॉलबैक शामिल है), और जाँचता है कि @ चीज़। इसके तत्वों का उपयोग करने से पहले खाली नहीं है। (;

describe Thing do
  before :each do
    @user  = User.create(:name => "Fred");
    @thing = Thing.new(:name => 'Foo')
    @user.things << @thing
    @thing.run_callbacks(:save)
  end 

  it "should have created a relationship" do
    @thing.followers.should == [@user]
    puts @thing.followers.inspect
  end 
end
class Thing < ActiveRecord::Base
  after_save :some_function
  has_many :user_following_thing_relationships
  has_many :followers, :through => :user_following_thing_relationships, :source => :user

  def some_function
    the_followers = followers
    unless the_followers.empty?
      puts "accessing followers here: the_followers = #{the_followers.inspect}..."
    end
  end
end

मूल उत्तर **

मैं चीजों को after_save कॉलबैक के साथ काम करने में सक्षम था, इतने लंबे समय के रूप में मैं do_stuff के शरीर / ब्लॉक के भीतर followers संदर्भ नहीं किया। क्या आप followers को वास्तविक विधि में संदर्भित करना चाहते हैं जो आप after_save से कॉल कर रहे हैं?

कॉलबैक को बाहर करने के लिए अपडेटेड कोड अब मॉडल के रूप में आप की आवश्यकता हो सकती है, हम @ चीज़ दिखाते हैं.फोलोरर्स वास्तव में हम के रूप में निर्धारित हैं, और हम do_stuff / some_function की कार्यक्षमता की जांच कर सकते हैं after_save द्वारा एक अलग कल्पना में।

मैंने यहां कोड की एक प्रति धक्का दिया: https://github.com/kikuchiyo/RspecHasMany

और युक्ति पासिंग * कोड नीचे है:

# thing_spec.rb
require 'spec_helper'

describe Thing do
    before :each do
        Thing.any_instance.stub(:some_function) { puts 'stubbed out...' }
        Thing.any_instance.should_receive(:some_function).once
        @thing = Thing.create(:name => "Foo");
        @user  = User.create(:name => "Fred");
        @user.things << @thing
    end

    it "should have created a relationship" do
        @thing.followers.should == [@user]
        puts @thing.followers.inspect
    end
end
# thing.rb
class Thing < ActiveRecord::Base
    after_save :some_function
    has_many :user_following_thing_relationships
    has_many :followers, :through => :user_following_thing_relationships, :source => :user

    def some_function
        # well, lets me do this, but I cannot use @x without breaking the spec...
        @x = followers 
        puts 'testing puts hear shows up in standard output'
        x ||= 1
        puts "testing variable setting and getting here: #{x} == 1\n\t also shows up in standard output"
        begin
            # If no stubbing, this causes rspec to fail...
            puts "accessing followers here: @x = #{@x.inspect}..."
        rescue
            puts "and this is but this is never seen."
        end
    end
end




after-save