Hi, I have a one to many relationship ( stories & votes ), that i wish to test via a unit test. In development everything works great, votes ends up w/ the correct story_id and the relationship is great ( i can Vote.find(:last).story or Story.find(:last).votes ) But when I run the unit test, it fails. The story gets an id of 996332877 ( which is 10000 in dev ) and the votes story_id is 0. Not sure what the heck is going on here. Any help would be greatly appreciated. Merrick stories: +-----------------+ | ID | NAME | URL | +-----------------+ votes: +---------------+ | ID | STORY_ID | +---------------+ models: class Story < ActiveRecord::Base validates_presence_of :name, :link has_many :votes do def latest find :all, :order => ''id DESC'', :limit => 3 end end def to_param "#{id}-#{name.gsub(/\W/, ''-'').downcase}" end end class Vote < ActiveRecord::Base belongs_to :story end vote test: test "story_association" do assert_equal stories(:two), votes(:two).story #FAILS! end -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Merrick Johnson wrote:> has_many :votes do > def latest > find :all, :order => ''id DESC'', :limit => 3 > end > endNice! Could someone hint what that syntax does? (But I don''t think it''s causing the problem...> vote test:Next time, write the test first! You should have developed all those model-level features entirely in test, using the tests essentially the same way - to feel around and sense changes as you grew the code - as you used your Rails app in development mode. But enough of the lecture...> test "story_association" do > assert_equal stories(:two), votes(:two).story #FAILS! > endWhat is in your test/fixtures/stories.yml and votes.yml files? What does the assert_equal spew forth when it fails? -- Phlip http://www.oreillynet.com/onlamp/blog/2008/05/dynamic_languages_vs_editors.html --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Good call Philip, turns out my votes.yml fixture looked like this: one: story_id: one two: story_id: one when it should have looked like this: one: story: one two: story: one Waalaa Thanks -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Phlip wrote:> Merrick Johnson wrote: > >> has_many :votes do >> def latest >> find :all, :order => ''id DESC'', :limit => 3 >> end >> end > > Nice! Could someone hint what that syntax does? (But I don''t think it''s > causing > the problem...this creates a method for the resource. in this case it returns the newest 3 records. This is pretty helpful because i can call this from a view or partial ( @story.votes.latest ) and just get the newest three votes. This should work in any DB ( im using Oracle11G ) -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Merrick Johnson wrote:> one: > story: one > > two: > story: oneAhem. Now for some more lectures! Your test data fixtures should be literate, so you can document your business rules in your test cases. In other words, your fixtures should not just say "one two" etc. They should, instead, tell a ... story. (-: BTW I guessed what this does: > has_many :votes do > def latest > find :all, :order => ''id DESC'', :limit => 3 > end > end It lets you say a_story.votes.latest and call that find. I can''t wait to use that utterly kewl feature! -- Phlip --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Merrick Johnson wrote:> this creates a method for the resource. in this case it returns the > newest 3 records.Yup! > This is pretty helpful because i can call this from a> view or partial ( @story.votes.latest ) and just get the newest three > votes. This should work in any DB ( im using Oracle11G )And you never need to say that about MVC or ActiveRecord. The point is you write the minimum code, all in the right places, to support the maximum features. You don''t have to do it the old-fashioned way, with code scattered everywhere, all very similar, getting in the way of each other! Now this is why that new aggregation notation is so dang cool. Here''s the Rails 1 way to do a bunch of links: class Customer has_many :accounts has_many :accounts_cc, :class_name => ''Account'', :conditions => { :kind => ''cc'' } has_many :accounts_ach, :class_name => ''Account'', :conditions => { :kind => ''ach'' } end Now compared to raw SQL, has_many is already an order of magnitude more DRY (Don''t Repeat Yourself). Yet the one requirement to distinguish Credit Card from Checking accounts forces us to create three very wet has_many calls on the same model. They are, once again, irritatingly similar. Here''s the (apparent!) Rails 2 fix: class Customer has_many :accounts do def kind(k) find :all, :conditions => { :kind => k } end end end Boom done. You can write customer.accounts, customer.accounts.kind(''cc''), and customer.accounts.kind(''ach''), all very similar to what you could write before, but with far fewer executable lines. I''m stoked because we just spent 3 days refactoring a big system which needed this exact fix, and I didn''t know about it. Now I get to install it on Monday. Merry Xmas to me, huh?! -- Phlip --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Phlip wrote:> Merrick Johnson wrote: > >> this creates a method for the resource. in this case it returns the >> newest 3 records. > > Yup! > > > This is pretty helpful because i can call this from a >> view or partial ( @story.votes.latest ) and just get the newest three >> votes. This should work in any DB ( im using Oracle11G ) > > And you never need to say that about MVC or ActiveRecord. The point is > you write > the minimum code, all in the right places, to support the maximum > features. You > don''t have to do it the old-fashioned way, with code scattered > everywhere, all > very similar, getting in the way of each other! > > Now this is why that new aggregation notation is so dang cool. Here''s > the Rails > 1 way to do a bunch of links: > > class Customer > has_many :accounts > has_many :accounts_cc, :class_name => ''Account'', > :conditions => { :kind => ''cc'' } > has_many :accounts_ach, :class_name => ''Account'', > :conditions => { :kind => ''ach'' } > end > > Now compared to raw SQL, has_many is already an order of magnitude more > DRY > (Don''t Repeat Yourself). Yet the one requirement to distinguish Credit > Card from > Checking accounts forces us to create three very wet has_many calls on > the same > model. They are, once again, irritatingly similar. > > Here''s the (apparent!) Rails 2 fix: > > class Customer > has_many :accounts do > def kind(k) > find :all, :conditions => { :kind => k } > end > end > end > > Boom done. You can write customer.accounts, > customer.accounts.kind(''cc''), and > customer.accounts.kind(''ach''), all very similar to what you could write > before, > but with far fewer executable lines. > > I''m stoked because we just spent 3 days refactoring a big system which > needed > this exact fix, and I didn''t know about it. Now I get to install it on > Monday. > Merry Xmas to me, huh?! > > -- > PhlipJust rewrote my test to make a little more sense. The first test fails because the order of the votes, if i reverse it it passes. Since I am not testing order, the third test ( votes_association_improved ) makes a little more sense. Is there a way to write that in one statement without && ? test "votes_association_1" do assert_equal [ votes(:one), votes(:two) ], stories(:one).votes #FAILS end test "votes_association_2" do assert_equal [ votes(:two), votes(:one) ], stories(:one).votes #PASSES end test "votes_association_improved" do assert stories(:one).votes.include? votes(:one) assert stories(:one).votes.include? votes(:two) end -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Merrick Johnson wrote:> test "votes_association_improved" do > assert stories(:one).votes.include? votes(:one) > assert stories(:one).votes.include? votes(:two) > endYou need .to_set, and I will recommend a way to unify assert() and assert_equal() into an assertion that reflects all its variables and values when it fails. gem install assert2 require ''assert2'' assert{ stories(:one).votes.to_set == votes(:one, :two).to_set } .to_set converts an ordered array into an unordered group, so == can''t see the order and can''t complain. (But don''t use assert{ 2.0 } if you use Ruby 1.8.7! A fix for Ruby 1.9 is in the works...) -- Phlip --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Merrick Johnson wrote:> find :all, :order => ''id DESC'', :limit => 3Note that, in a normal database - and in a unit test that generates new records - the ''id'' should increment monotonically as new records get added. So ''latest'' is always the highest ''id''. (Note I have no idea if databases must eternally enforce this rule, but it stands to reason...) However, a modern Rails fixture file uses a "magic ''id'' system" that builds ''id''s out of the hash of each record''s fixture name. So the ''id''s are not monotonic, and these problems illustrate you ought to use a timestamp, such as ''created_at'', instead of an ''id'', to find the latest records! This means, instead of using .to_set in the test, you should actually pin down the ''created_at'' times in your fixture files. And this reminds us, again, to use the fixtures to tell a little story. Suggest one record is "2.hours.ago", and another is "5.minutes.ago", for example! -- Phlip --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---