<br><br><div><span class="gmail_quote">On 7/25/07, <b class="gmail_sendername">Mikel Lindsaar</b> &lt;<a href="mailto:raasdnil@gmail.com">raasdnil@gmail.com</a>&gt; wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Kyle,<br><br>That is a good point.&nbsp;&nbsp;We are after the behaviour, not the implementation.<br><br>Regards<br><br>Mikel<br><br>On 7/25/07, Daniel N &lt;<a href="mailto:has.sox@gmail.com">has.sox@gmail.com</a>&gt; wrote:<br>&gt;
<br>&gt;<br>&gt;<br>&gt; On 7/25/07, Kyle Hargraves &lt;<a href="mailto:philodespotos@gmail.com">philodespotos@gmail.com</a>&gt; wrote:<br>&gt; &gt; Daniel N wrote:<br>&gt; &gt; &gt; On 7/25/07, Mikel Lindsaar &lt;<a href="mailto:raasdnil@gmail.com">
raasdnil@gmail.com</a>&gt; wrote:<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt; There would be a different way.<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt; In the idea of &quot;Only test the code you write&quot; all you really need to
<br>&gt; &gt; &gt;&gt; spec is that you have set the right association, because activerecord<br>&gt; &gt; &gt;&gt; has it&#39;s own tests to ensure the uniq call works.<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt; You can do this with a call to
<br>&gt; reflect_on_association.&nbsp;&nbsp;Unfortunately<br>&gt; &gt; &gt;&gt; that call does not return a hash, but an association object.<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt; I wrote a blog post on how to do this easily with a spec_helper.rb
<br>&gt; &gt; &gt;&gt; method that adds to_hash to reflect on association.<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt;<br>&gt; <a href="http://www.blognow.com.au/q/67540/Reflect_on_association_one_liner_to_check_association_details.html">
http://www.blognow.com.au/q/67540/Reflect_on_association_one_liner_to_check_association_details.html</a><br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt; In the end you end up with a spec that looks like this:
<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt; it &quot;should test reflection details&quot; do<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp; association_results = {<br>&gt; &gt; &gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :macro =&gt; :has_many,<br>
&gt; &gt; &gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :options =&gt; {:through =&gt; :clipping, :uniq =&gt; true},<br>&gt; &gt; &gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :class_name =&gt; &quot;nil&quot;<br>&gt; &gt; &gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp; 
Book.reflect_on_association (:clip).to_hash.should ==<br>&gt; &gt; &gt;&gt; association_results<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt;&nbsp;&nbsp; end<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt; Of course, you can add whatever values you want into the hash.
<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt; I now have one of these specs at the top of pretty much every model<br>&gt; &gt; &gt;&gt; spec.&nbsp;&nbsp;Just set up the hash with all your association rules and then<br>&gt; &gt; &gt;&gt; this can be checked and kept track of when you are refactoring or
<br>&gt; &gt; &gt;&gt; changing code.<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt; Hope that helps.<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt; Regards<br>&gt; &gt; &gt;&gt;<br>&gt; &gt; &gt;&gt; Mikel<br>&gt; &gt; &gt;<br>
&gt; &gt; &gt;<br>&gt; &gt; &gt; Thanx Mikel.<br>&gt; &gt; &gt;<br>&gt; &gt; &gt; I didn&#39;t even think of using a uniq on the has_many.&nbsp;&nbsp;I was using a<br>&gt; &gt; &gt; validates_uniquness_of :scope =&gt; &#39;book_id&#39;
<br>&gt; &gt; &gt;<br>&gt; &gt; &gt; I will definitley look into this one.<br>&gt; &gt; &gt;<br>&gt; &gt; &gt; Thankyou<br>&gt; &gt; &gt; Daniel<br>&gt; &gt;<br>&gt; &gt; However you decide to go about solving it, the idiom you hit upon is
<br>&gt; &gt; what, to me, actually describes the behaviour; if the book already has a<br>&gt; &gt; clip once, you can&#39;t add it again:<br>&gt; &gt;<br>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;lambda { add_twice }.should change(...).by(1)<br>&gt; &gt;
<br>&gt; &gt; It states very clearly what results you wish to see.<br>&gt; &gt;<br>&gt; &gt; Going through reflect_on_association feels too much like specifying the<br>&gt; &gt; use of a particular implementation, rather than the desired outcome.
<br>&gt; &gt;<br>&gt; &gt; Kyle<br>&gt;<br>&gt;<br>&gt;&nbsp;&nbsp;It looks much better when you write it like that though ;)<br>&gt;<br>&gt;<br>&gt;</blockquote><div><br>Thanx for the input guys.&nbsp; I wasn&#39;&#39;t entirely happy with what I had because it didn&#39;t actually test what I wanted.&nbsp; It tests that a duplicate cannot be added.&nbsp; But I specifically wanted to not allow duplicates for a given clip_id
<br><br>&nbsp; it &quot;should have a uniq clip_id for a given book&quot; do<br>&nbsp;&nbsp;&nbsp; lambda do<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Clipping.create( valid_clipping_attributes )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Clipping.create( valid_clipping_attributes )<span class="q"><br>&nbsp;&nbsp;&nbsp; end.should
 change( Clipping, :count ).by( 1 )
<br></span>&nbsp; end<br></div><br></div>became<br><br>&nbsp; it &quot;should have a uniq clip_id for a given book&quot; do<br>&nbsp;&nbsp;&nbsp; lambda do<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Clipping.create( valid_clipping_attributes.with( :book =&gt; @book, :clip =&gt; @clip ) )
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clipping = Clipping.create( valid_clipping_attributes.with( :book =&gt; @book, :clip =&gt; @clip ) )<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clipping.should have(1).error_on( :clip_id )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clipping.errors.on( :clip_id ).should match( /(already|duplicate|exists)/i )
<br><br>&nbsp;&nbsp;&nbsp; end.should change( Clipping, :count ).by( 1 )<br>&nbsp; end<br><br>If anyone was interested :P<br><br>Daniel<br>