title: How can I properly test my model (in rspec) that uses the unread gem?
body: <p>I have an app that's using the <a href="https://github.com/ledermann/unread" rel="nofollow">unread gem</a> to mark certain models as read or unread for a user. The gem is frakkin sweet and works flawlessly in the app. Unfortunately, I'm hitting some weird errors when working on some Rspec tests that involve the models that <code>act_as_readable</code> and I can't, for the life of me, figure out where to go next. I'm hoping the amazing StackOverflow community can help me out. Here are the necessary details:</p>
  
  <h2>Model method</h2>
  
  <pre><code>def unread_subscriptions
      reviews = Array.new
      subscriptions = Subscription.where(user_id: self.id)
  
      unless subscriptions.empty?
          subscriptions.each do |subscription|
              subscription_reviews = Review.where(user_id: subscription.subscription_user_id)
  
              unless subscription_reviews.empty?
                  subscription_reviews.each do |subscription_review|
                      if subscription_review.unread?(self)
                          reviews &lt;&lt; subscription_review
                      end
                  end
              end
          end
      end
  
      reviews.sort_by(&amp;:created_at).reverse
  end
  </code></pre>
  
  <p><em>This code has some obvious spots where it can be improved or re-factored which is exactly why I'm writing tests for it so please, let's keep the discussion focused on the error at hand.</em></p>
  
  <h2>Rspec Test Block</h2>
  
  <pre><code>describe "#unread_subscriptions", focus: true do
      context "when subscriptions and subscription reviews are not empty" do
          let(:subscription_user) { FactoryGirl.create(:user) }
          let(:reviews) { FactoryGirl.create_list(Review, 3, user: subscription_user) }
  
          before(:each) {
              subscription_double = double(Subscription)
              subscription_double.stub(:where)
                                  .with(user_id: user.id)
                                  .and_return(
                                      FactoryGirl.create(:subscription, 
                                          user_id: user.id, 
                                          subscription_user_id: subscription_user.id))
              review_double = double(Review)
              review_double.stub(:unread_by).with(user).and_return(reviews)
              review_double.stub(:unread?).with(user).and_return(true)
              review_double.stub(:where).with(user_id: subscription_user.id).and_return(reviews)
          }
  
          its(:unread_subscriptions) { should be_instance_of(Array) }
          its(:unread_subscriptions) { should_not be_empty }
      end
  end
  </code></pre>
  
  <p>All of the above code seems to work properly. The <code>subscription_user</code> gets created by FactoryGirl properly and has an id. The <code>reviews</code> array generated by a FactoryGirl <code>create_list</code> is legit and has the <code>user_id</code> filled in properly. As can be seen in the code above, I've tried stubbing out the methods for the <code>unread</code> gem on the <code>Review</code> class but they don't seem to be working properly.</p>
  
  <h2>Review Factory</h2>
  
  <pre><code>FactoryGirl.define do
      sequence :created_at do |n|
          n.minutes.ago
      end
      factory :review do
          user
          bar
          body "MyText"
          rating 3
          created_at
      end
  end
  </code></pre>
  
  <p>I run these tests with <code>rspec spec/models/user_spec.rb -f d</code> and get the following output:</p>
  
  <pre><code>Run options: include {:focus=&gt;true}
  
  User
    #unread_subscriptions
      when subscriptions and subscription reviews are not empty
        unread_subscriptions
          example at ./spec/models/user_spec.rb:231 (FAILED - 1)
        unread_subscriptions
          example at ./spec/models/user_spec.rb:232 (FAILED - 2)
  
  Failures:
  
    1) User#unread_subscriptions when subscriptions and subscription reviews are not empty unread_subscriptions 
       Failure/Error: its(:unread_subscriptions) { should be_instance_of(Array) }
       ActiveRecord::StatementInvalid:
         Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AND read_marks.timestamp     &gt;= reviews.created_at WHERE `reviews`.`id` = 1 AND ' at line 4: SELECT  1 FROM `reviews` LEFT JOIN read_marks ON read_marks.readable_type  = 'Review'
                                                           AND read_marks.readable_id    = reviews.id
                                                           AND read_marks.user_id        = 
                                                           AND read_marks.timestamp     &gt;= reviews.created_at WHERE `reviews`.`id` = 1 AND (read_marks.id IS NULL) ORDER BY created_at DESC LIMIT 1
       # ./app/models/user.rb:217:in `block (2 levels) in unread_subscriptions'
       # ./app/models/user.rb:216:in `block in unread_subscriptions'
       # ./app/models/user.rb:212:in `unread_subscriptions'
       # ./spec/models/user_spec.rb:231:in `block (4 levels) in &lt;top (required)&gt;'
  
    2) User#unread_subscriptions when subscriptions and subscription reviews are not empty unread_subscriptions 
       Failure/Error: its(:unread_subscriptions) { should_not be_empty }
       ActiveRecord::StatementInvalid:
         Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AND read_marks.timestamp     &gt;= reviews.created_at WHERE `reviews`.`id` = 4 AND ' at line 4: SELECT  1 FROM `reviews` LEFT JOIN read_marks ON read_marks.readable_type  = 'Review'
                                                           AND read_marks.readable_id    = reviews.id
                                                           AND read_marks.user_id        = 
                                                           AND read_marks.timestamp     &gt;= reviews.created_at WHERE `reviews`.`id` = 4 AND (read_marks.id IS NULL) ORDER BY created_at DESC LIMIT 1
       # ./app/models/user.rb:217:in `block (2 levels) in unread_subscriptions'
       # ./app/models/user.rb:216:in `block in unread_subscriptions'
       # ./app/models/user.rb:212:in `unread_subscriptions'
       # ./spec/models/user_spec.rb:232:in `block (4 levels) in &lt;top (required)&gt;'
  
  Finished in 8.88 seconds
  2 examples, 2 failures
  
  Failed examples:
  
  rspec ./spec/models/user_spec.rb:231 # User#unread_subscriptions when subscriptions and subscription reviews are not empty unread_subscriptions 
  rspec ./spec/models/user_spec.rb:232 # User#unread_subscriptions when subscriptions and subscription reviews are not empty unread_subscriptions
  </code></pre>
  
  <p>For some reason the <code>readmarks</code> query is not getting the user id for the review (even though the review has a user associated). I am at an absolute loss as to what is going on here and really need someone's genius to get me pointed in the right direction. Thanks for any help anyone can provide. For completeness' sake, here are some facts about my environment:</p>
  
  <ul>
  <li><strong>OS</strong>: Mac OSX 10.7.5</li>
  <li><strong>Ruby Version</strong>: ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin11.4.0]</li>
  <li><strong>Rails Version</strong>: Rails 3.2.3</li>
  <li><strong>RVM Version</strong>: rvm 1.15.8 (stable)</li>
  <li><strong>RSpec Version</strong>: 2.11.1</li>
  <li><strong>unread gem Version</strong>: 0.1.1</li>
  <li><strong>factory_girl_rails Version</strong>: 4.1.0</li>
  </ul>
  
  <p><strong>Extra</strong>: I am also using the suggestion in <a href="https://github.com/ledermann/unread/pull/12" rel="nofollow">this thread</a> regarding the shared macro for the <code>wait</code> method. It did not fix the error.</p>