tag:blogger.com,1999:blog-27488238.post3273517603082008265..comments2024-03-22T11:34:45.165+01:00Comments on taw's blog: Two months with Ruby on Railstawhttp://www.blogger.com/profile/16972845140253292628noreply@blogger.comBlogger26125tag:blogger.com,1999:blog-27488238.post-81399949722257229302008-08-11T23:54:00.000+02:002008-08-11T23:54:00.000+02:00Good writeup for a beginner's understanding to it....Good writeup for a beginner's understanding to it. I don't personally love rails or rhtml, but...they work, and they pay the bills.<BR/>Here's my own pet plugin:<BR/>http://code.google.com/p/ruby-roger-useful-functions/wiki/EnglishLikeQueries<BR/>Take care.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-27488238.post-80549767934872426262007-11-22T01:02:00.000+01:002007-11-22T01:02:00.000+01:00You can setup an "after_filter" in your controller...You can setup an "after_filter" in your controllers that will do whatever you want to the response.body part. You can setup a regex that will strip all XSS possibilities from your output.Chrishttps://www.blogger.com/profile/01620116812953292506noreply@blogger.comtag:blogger.com,1999:blog-27488238.post-53399238997394707972007-11-10T18:00:00.000+01:002007-11-10T18:00:00.000+01:00Anonymous: after_save is not good enough. If a bun...Anonymous: after_save is not good enough. If a bunch of objects are saved in one transaction, after_save of some will be called before some others will be saved. At the very least there should be a before_commit hook which would be called after all objects were saved but before database COMMIT.tawhttps://www.blogger.com/profile/16972845140253292628noreply@blogger.comtag:blogger.com,1999:blog-27488238.post-74244868343827722332007-11-10T17:52:00.000+01:002007-11-10T17:52:00.000+01:00taw: Again, your "on_commit" problem is just a lac...taw: Again, your "on_commit" problem is just a lack of knowledge of the framework. Raising an exception inside of an after_save callback would do exactly what you're looking for. You're still inside the transaction at that point, and can easily rollback.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-27488238.post-8428327819558765652007-10-22T17:33:00.000+02:002007-10-22T17:33:00.000+02:00Hampton: I have limited supply of hatred and I've ...Hampton: I have limited supply of hatred and I've almost ran out of it hating so many things. So please forgive me if I don't have sufficient amount of hatred left to keep hating HAML more than just a little.tawhttps://www.blogger.com/profile/16972845140253292628noreply@blogger.comtag:blogger.com,1999:blog-27488238.post-11269105728396527292007-10-20T20:17:00.000+02:002007-10-20T20:17:00.000+02:00Awe, come on!Keep hating Haml! I love a good flami...Awe, come on!<BR/><BR/>Keep hating Haml! I love a good flaming.<BR/><BR/>I'm sick and tired of people *liking* what I make. All I'm saying is, please consider hating Haml again. Like the olden days.Hampton Catlinhttps://www.blogger.com/profile/02541429177469422891noreply@blogger.comtag:blogger.com,1999:blog-27488238.post-76972208863132283852007-10-15T22:45:00.000+02:002007-10-15T22:45:00.000+02:00sjs: I never cared much for single-stepping debugg...sjs: I never cared much for single-stepping debuggers. Unit testing, Object#inspect and script/console were so far sufficient for all my Ruby debugging needs.tawhttps://www.blogger.com/profile/16972845140253292628noreply@blogger.comtag:blogger.com,1999:blog-27488238.post-54203923613679524532007-10-15T22:10:00.000+02:002007-10-15T22:10:00.000+02:00I share some of your gripes with Rails. Have you ...I share some of your gripes with Rails. Have you tried out the Ruby NetBeans builds? The OS X daily builds are more stable than the Linux ones in my experience, but they both work pretty well. Being able to set breakpoints, snoop around local vars, step into Rails iteslf, etc. are pretty nice.sjshttps://www.blogger.com/profile/14285255211269339227noreply@blogger.comtag:blogger.com,1999:blog-27488238.post-35236433968485499492007-10-10T00:08:00.000+02:002007-10-10T00:08:00.000+02:00Taw, Check out optimistic and/or pessimistic locki...Taw, <BR/><BR/>Check out optimistic and/or pessimistic locking. Rails has support for both. Locking on the aggregate root object (Person) will solve your multiple primary emails problem.<BR/><BR/>Martin Fowler has a good discussion of concurrency and locking in his book 'Patterns of Enterprise Application Architecture'. It's a fundamental problem with concurrency, not just relational databases. There are different solutions with different tradeoffs, and you can implement any of them just fine in Rails.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-27488238.post-47032079977682002012007-10-09T23:59:00.000+02:002007-10-09T23:59:00.000+02:00Always nice with a good rant :-)Always nice with a good rant :-)Unknownhttps://www.blogger.com/profile/15717354097255611832noreply@blogger.comtag:blogger.com,1999:blog-27488238.post-18112035039302066232007-10-09T23:33:00.000+02:002007-10-09T23:33:00.000+02:00Anonymous: Unfortunately multiple operations modif...Anonymous: Unfortunately multiple operations modify database concurrently so before_validate hooks are not enough. And ActiveRecord doesn't have anything like an on_commit hook.<BR/><BR/>Imagine two operations happening, both trying to add new primary email address. The important thing is that one starts before the other commits, so SELECTing all existing email addresses returns only old ones (456) in each case.<BR/><BR/>BEGIN;<BR/>SELECT id FROM email_addresses WHERE user_id = 123;<BR/>INSERT INTO email_adresses(user_id, address, is_primary) VALUES (123,'foo@gmail.com', 1);<BR/>UPDATE email_addresses SET is_primary=0 WHERE id in (456);<BR/>COMMIT<BR/><BR/>BEGIN;<BR/>SELECT id FROM email_addresses WHERE user_id = 123;<BR/>INSERT INTO email_adresses(user_id, address, is_primary) VALUES (123,'foo@yahoo.com', 1);<BR/>UPDATE email_addresses SET is_primary=0 WHERE id in (456);<BR/>COMMIT<BR/><BR/>And user 123 now has two primary email addresses. One way to protect against such stuff is evil database-side triggers. Or rearranging database so that it's not possible (like keep primary_email_address_id on users table). I don't know if there's any pretty way of doing that stuff.tawhttps://www.blogger.com/profile/16972845140253292628noreply@blogger.comtag:blogger.com,1999:blog-27488238.post-23434141173477512412007-10-09T23:10:00.000+02:002007-10-09T23:10:00.000+02:00OK you've lost me one this one as well:"Unfortunat...OK you've lost me one this one as well:<BR/><BR/>"Unfortunately Active Record hooks are too weak to handle things like ensuring that each person has exactly one primary email address."<BR/><BR/>Can't you just stick a check for the number of primary email addresses in before_validate, before_validate_on_create, or before_validate_on_update? You know, add an error and cancel the save operation if an attempt is made to add a second primary email address? I've done stuff like this quite often; works fine.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-27488238.post-87916392281617903212007-10-09T23:06:00.000+02:002007-10-09T23:06:00.000+02:00Taw,Sorry to bang up on you so much, but this one ...Taw,<BR/><BR/>Sorry to bang up on you so much, but this one is way off base:<BR/><BR/>"It ends with paths like /posts/123/destroy which are then fetched by web spiders deleting all your database."<BR/><BR/>If a GET request deletes data then you deserve whatever you get (pun intended). That's just bad web design. It has nothing to do with Rails or routes.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-27488238.post-63446162800731589502007-10-09T22:56:00.000+02:002007-10-09T22:56:00.000+02:00"And redirects to the same controller should be fo..."And redirects to the same controller should be followed. POST/PUT which returns a redirect and the following GET are logically a single action, it's just an implementation detail (browser refresh, history, bookmarkability etc.) that they're implemented in two steps."<BR/><BR/>It's an implementation detail to the browser perhaps, but I have to verify that my code follows the conventions properly. How would else would I test the first POST request in isolation otherwise? Again, I think you're looking for a higher level test, which is an integration test: <BR/><BR/>http://weblog.jamisbuck.org/2006/3/9/integration-testing-in-rails-1-1<BR/><BR/>"Functional tests are very narrowly focused on testing a single constroller and the interactions between the models it employs."Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-27488238.post-41697954010905244502007-10-09T22:52:00.000+02:002007-10-09T22:52:00.000+02:00Taw,I'm not sure I follow. If your controller (or...Taw,<BR/><BR/>I'm not sure I follow. If your controller (or code called by it) raises an exception, it will be propagated to the test. The rails request process catches exceptions that escape the controller, which ideally should never happen, and translates them into 500 errors. But you're not testing Rails in a functional test, you're testing your controller. So if your controller raises (and does not catch) an exception, it will get propagated to the test. That's how exceptions work in Ruby (and most languages); it'd be weird if it didn't.<BR/><BR/>If your controller explicitly sets the response status to 500 (or 400, or 403, or 201), no exception will be raised, and the response status will be whatever you coded it to be in your controller. And you can test it with assert_response, or more explicitly by checking @response.status.<BR/><BR/>Let's say my controller looks like this (pseudo-code):<BR/><BR/>if user_input_is_good<BR/> create_widget<BR/> head :created # (201)<BR/>elsif duplicate_widget<BR/> head :conflict # (409)<BR/>elsif invalid_widget<BR/> head :unprocessable_entity (422)<BR/>end<BR/><BR/>How would I test each condition? Well, I'd write three different test methods in my controller test, passing valid, conflicting, and invalid data. And I'd assert that the response was 201, 409, or 422 as appropriate. It'd confuse the heck out of me if the test weaved in magic code that translated certain response codes into exceptions. <BR/><BR/>***Especially since in production, no exceptoin would ever be raised!*** If my controller sets the HTTP response status to 4xx, Rails dutifully returns that in the HTTP response; no exception is raised. Why should tests behave differently than production code in this case?<BR/><BR/>To answer your question, if I coded my controller to return 403, I set up a test to verify that 403 is returned in certain circumstances, and indeed the controller returned 403 when the test was excecuted, then no, I would say nothing was wrong -- my code was working as I designed it.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-27488238.post-18469096772398613512007-10-09T21:52:00.000+02:002007-10-09T21:52:00.000+02:00One more point -- the setup method of a functional...One more point -- the setup method of a functional creates a new controller instance every test method. It lasts for the length of a test method. Usually one functional test method makes exactly one request. If you want controller instance variables cleared out every request, you'd need to re-instantiate the control (which makes sense to me -- having it automagically 'clear out' instance variables of the controller but leaving the controller object itself alone would be surprising to say the least).<BR/><BR/>If you want to execute multiple request in one test you probably want an integration test.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-27488238.post-79045632613832957562007-10-09T21:48:00.000+02:002007-10-09T21:48:00.000+02:00Anonymous: Do you agree that unexpected 403 in tes...Anonymous: Do you agree that unexpected 403 in tests indicates that something is wrong, and all tests which validly return 403 should be tested ? But the way it works now, unless you do assert_response :success/:redirect after almost every single action (what massively violates DRY principle) unexpected 403s pass undetected and that's wrong.<BR/><BR/>Testing already raises an exception instead of silently returning 500, so why should 4xx family of errors be handled any differently ?<BR/><BR/>And redirects to the same controller should be followed. POST/PUT which returns a redirect and the following GET are logically a single action, it's just an implementation detail (browser refresh, history, bookmarkability etc.) that they're implemented in two steps.tawhttps://www.blogger.com/profile/16972845140253292628noreply@blogger.comtag:blogger.com,1999:blog-27488238.post-33826981927158664592007-10-09T21:38:00.000+02:002007-10-09T21:38:00.000+02:00If you want to follow redirects use an integration...If you want to follow redirects use an integration test. The functional tests are supposed to just execute your controller method and let you test that in isolation. From the look of your pseudo test it looks like you want an integration test.<BR/><BR/>I use the request and response objects in my functional (and integration) tests sometimes to set custom MIME accepts types in the request header, to check the response headers, etc. You could also use it to check the response status (like 403).<BR/><BR/>Or you could check the response status using 'assert_response 403'. It doesn't 'ignore' 403 or flash[:error], but it doesn't raise an exception either -- and it would be weird if it did. In an HTTP client raising Error403 might make sense, but in the server that's not an exception, it's something you coded for and want to test for directly.<BR/><BR/>Nice blog, some of your points are valid, others misinformed (which is understanable). Let us know what you think in 2 more months!Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-27488238.post-34677267096525231932007-10-09T21:03:00.000+02:002007-10-09T21:03:00.000+02:00I hear you and agree on some of your points.Especi...I hear you and agree on some of your points.<BR/><BR/>Especially with Capistrano. I think the whole need of such a separate tool shows how deployment is a bug black hole in Ruby/Rails as a platform. At least, when compared to what has been standardized in .war/.ear files in Java world.<BR/><BR/>I recently did a post on the same subject of <A HREF="http://techpolesen.blogspot.com/2007/10/10-areas-where-rails-fails.html" REL="nofollow">problems in rails</A>, with some other annoyances than you have.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-27488238.post-16937544987106111552007-10-09T19:29:00.000+02:002007-10-09T19:29:00.000+02:00Pardon, I didn't mean to imply Seaside was a java ...Pardon, I didn't mean to imply Seaside was a java framework, and it's arguable that Smalltalk is about as agile as it gets ... but the likelihood of smalltalk going mainstream again is about as likely as <clever analogy here>Chuck Adamshttps://www.blogger.com/profile/12403744972060658849noreply@blogger.comtag:blogger.com,1999:blog-27488238.post-4081334133314068242007-10-09T19:27:00.000+02:002007-10-09T19:27:00.000+02:00Flash is an ugly hack that is best generalized int...Flash is an ugly hack that is best generalized into "flows", something that most java frameworks have an answer to: such as Spring Web Flow, Seam with its stateful Conversation model, or more exotically, Seaside and Rife with continuations. Others such as Wicket and Tapestry prefer session-scoped widgets/components instead, with the object scope of widgets being persistent between requests, and managed by a retention policy.<BR/><BR/>Ironically, virtually none of the "agile languages" have managed to duplicate this sort of basic functionality in their own framework, requiring the developer to stuff everything in the session, use half-measures like 'flash', or reinvent their own system. CherryFlow seems to be the only serious effort at this, and it was abandoned years ago.Chuck Adamshttps://www.blogger.com/profile/12403744972060658849noreply@blogger.comtag:blogger.com,1999:blog-27488238.post-29181290429139976402007-10-09T18:28:00.000+02:002007-10-09T18:28:00.000+02:00Simon said, "At least one of the semi-cool feature...Simon said, "At least one of the semi-cool features of Rails (and Ruby) is that hacking is possible; one of the semi-uncool features is that it is necessary most of the time."<BR/><BR/>When I tried playing with RoR 2 years ago, within 30 minutes I needed to do something that wasn't built into the framework already. For something so "new" and "cool", it amazed me that I'd need to break free of the RoR sandbox that quickly. It's sad to see that this is still the case now. <BR/><BR/>Other languages may lack the ease of use provided by RoR... but getting complex stuff to work never seemed quite as hackish.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-27488238.post-78207122541061522632007-10-09T14:40:00.000+02:002007-10-09T14:40:00.000+02:00your comment on models being all or nothing shows ...your comment on models being all or nothing shows you didn't read the docs or understand the methods of array and hash<BR/>http://www.ruby-doc.org/core/classes/Array.html#M002210<BR/><BR/><BR/>http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M001044<BR/><BR/>:include => [contact => phone ]<BR/><BR/>basic?<BR/>http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.htmlAnonymousnoreply@blogger.comtag:blogger.com,1999:blog-27488238.post-32479983287309310872007-10-09T12:59:00.000+02:002007-10-09T12:59:00.000+02:00Simon: For what I can tell :include, :conditions a...Simon: For what I can tell :include, :conditions and stuff quickly break, as they don't support complex actions (mass update, mass delete) or reports (group by, getting info from multiple columns) etc. Are "%" in execute and conversion of results to Ruby objects that much to ask for ?<BR/><BR/>I know I can hack it all. I do hack it all. It would just be nicer if things I consider basic worked out of the box.tawhttps://www.blogger.com/profile/16972845140253292628noreply@blogger.comtag:blogger.com,1999:blog-27488238.post-49716693288466540402007-10-09T12:04:00.000+02:002007-10-09T12:04:00.000+02:00I agree with you in a lot of ways, especially the ...I agree with you in a lot of ways, especially the SQL being annoying. But there are a couple of in-between SQL levels -- you can do a fair bit of stuff with :conditions and :include, and all those sort of things. And by using the right :conditions syntax you can solve a lot of the escaping problems (but you probably know that). A useful feature is that anywhere that takes SQL can use the :conditions array syntax, with substitutions.<BR/><BR/>As szeryf said, a lot of Rails is about finding a bunch of plugins to do what you want. And then hacking your own stuff. At least one of the semi-cool features of Rails (and Ruby) is that hacking is possible; one of the semi-uncool features is that it is necessary most of the time.Unknownhttps://www.blogger.com/profile/17249200538291402347noreply@blogger.com