1

I'm developing a blog in Rails and I'm stuck when I was trying to test the default scope I added to the Post model in order to have the posts in descending order of their creation date.

Post code:

class Post < ActiveRecord::Base
  attr_accessible :content, :name, :title

  validates :title, presence: true,uniqueness: true
  validates :name, presence: true
  validates :content, presence: true

  default_scope order: "posts.created_at DESC"

end

Rspec code:

  describe "Posts descending order of creation date" do
    let(:older_post) do
    FactoryGirl.create(:post, created_at: 1.day.ago)
    end   
    let(:newer_post) do 
    FactoryGirl.create(:post, created_at: 1.hour.ago)
    end

    it "should have the 2 posts in desc order" do
    Post.all.should == [newer_post, older_post]

    end    
  end

FactoryGirl definition

FactoryGirl.define do
    factory :post do
    sequence(:title) { |n| "A book #{n}" }
    name  "Johnny"
    content "Lorem Ipsum"
    end    
end   

The output .....F...

Failures:

    1) Post Posts descending order of creation date should have the 2 posts in desc order
    Failure/Error: Post.all.should == [newer_post, older_post]
       expected: [#<Post id: 1, name: "Johnny", title: "A book 1", content: "Lorem Ipsum", created_at: "2013-05-01 14:44:45", updated_at: "2013-05-01 15:44:45">, #<Post id: 2, name: "Johnny", title: "A book 2", content: "Lorem Ipsum", created_at: "2013-04-30 15:44:45", updated_at: "2013-05-01 15:44:45">]
        got: [] (using ==)
   Diff:
   @@ -1,3 +1,2 @@
   -[#<Post id: 1, name: "Johnny", title: "A book 1", content: "Lorem Ipsum", created_at: "2013-05-01 14:44:45", updated_at: "2013-05-01 15:44:45">,
   - #<Post id: 2, name: "Johnny", title: "A book 2", content: "Lorem Ipsum", created_at: "2013-04-30 15:44:45", updated_at: "2013-05-01 15:44:45">]
   +[]

 # ./spec/models/post_spec.rb:54:in `block (3 levels) in <top (required)>'

Finished in 1.03 seconds 9 examples, 1 failure

Failed examples:

    rspec ./spec/models/post_spec.rb:53 # Post Posts descending order of creation date should have the 2 posts in desc order

I also want to mention that when I type Post.all in the Rails console, I get the records in descending order ( so as I wanted them).

Can someone give me a suggestion on what the problem might be?

Dragos C.
  • 621
  • 2
  • 7
  • 15

1 Answers1

1

Please know that let is evaluated lazily in RSpec. This often creates problem in such scenarios where ordering is concerned. Try these two alternatives:

  describe "Posts descending order of creation date" do
    let!(:older_post) do
    FactoryGirl.create(:post, created_at: 1.day.ago)
    end   
    let!(:newer_post) do 
    FactoryGirl.create(:post, created_at: 1.hour.ago)
    end

    it "should have the 2 posts in desc order" do
    Post.all.should == [newer_post, older_post]
    end    
  end

Note, the use of let! instead of let.
Or, use before as:

  describe "Posts descending order of creation date" do

    it "should have the 2 posts in desc order" do
    @older_post = FactoryGirl.create(:post, created_at: 1.day.ago)
    @newer_post = FactoryGirl.create(:post, created_at: 1.hour.ago)

    Post.all.should == [@newer_post, @older_post]
    end    
  end

Do let me know if it works or not. :)

kiddorails
  • 12,961
  • 2
  • 32
  • 41
  • Unless there is a reason to share those objects across tests, don't use a `let`. Just use local variables inside the `it` block. – Aaron K May 01 '13 at 17:49
  • Thanks!. Actually, I intended to place the objects in `before` block in last example. But somehow, forgot it. – kiddorails May 01 '13 at 17:55
  • The context of surrounding tests will matter, but why bother with the `before`? With a single test, those variables only matter locally, and should just be locals. – Aaron K May 01 '13 at 17:56
  • For single test, yes. But, considering that he used `let` for a single test like this in `describe` block; one could safely assume that he might be planning to add more specs in same context - like addition of one more post and then crosschecking the order, or something. – kiddorails May 01 '13 at 17:59
  • Minor detail, for you can use `default_scope { order(created_at: :desc) }`. It's more railsy, and reads better in my opinion – JK Gunnink Nov 14 '16 at 16:31