Ruby on Rails Tutorial Chapter 12 is out
news.railstutorial.org
news.railstutorial.org
One question for experienced Rails folks:
I noticed that a lot of the test code seems to be somewhat redundant and not actually testing many different paths of execution.
E.g. I saw a lot of test cases like this in his examples:
it "should be successful" do
get :new
response.should be_success
end
it "should have a follower attribute" do
@relationship.should respond_to(:follower)
end
it "should have a followers method" do
@user.should respond_to(:followers)
end
it "should render the home page" do
post :create, :micropost => @attr
response.should render_template('pages/home')
end
Writing a unit test that verifies that some object has a new method/attribute that you're about to add to it, or that some request returns a 200 OK, or that some request renders a specific template? It all seems very...boilerplate to me.Is this a common practice?
it "should be successful" do
get :new
response.should be_success
end
Then def new
end
Next you'd add a test for what the 'new' action actually does, and then get the 'new' action to do it.In a book, interleaving the test and application code like this is rather cumbersome. The real payoff to this approach will be in the upcoming screencast series (http://www.railstutorial.org/screencasts), which will allow me to interleave the tests and application code much more finely. Together with Autotest continuous testing and Growl notifications, the screencasts will show just how addictive TDD can be.
I should probably motivate this practice better in the book, because it is counter-intuitive. In fact, I thought this technique was crazy when I first saw it. (The same goes for TDD in general.) But it's amazing how much easier it is to get started on a method when the first step is "make sure the method is there". Indeed, such tests aren't really designed to make the application better-tested; they're designed to help the programmer stay in the zone.
That being said, there probably are some places where such fine-grained tests aren't worth the trouble, or might even be confusing. I'm about to embark on a Rails 3 update of the book, so I'll keep my eye out for tests that should be removed. If you have any suggestions for tests that should be on the chopping block, please let me know (http://www.railstutorial.org/feedback).
Programs should be written for people to read,
and only incidentally for machines to execute.
(That's a bit of an over-statement, of course, but its spirit is true.)I also reevaluated the code for possible implementation lock-down. It looks like most such cases involve standard REST action names, such as new and show, or other aspects of the application that are unlikely to change.
In the end, you'll have to develop a style that works for you. The code presented in the book is based on the style I've developed in my own work and from reading the code of others, but there are as many styles as there are Rails developers. My job is to help get you on the road to finding a style of your own.
For example, I enjoyed things such as Figure 2.11 (a detailed explanation of MVC in Rails), but then Michael flashes through Ruby in Chapter 4. I understood it because I'm a programmer, but I don't know if any of the other target audiences would.
And as the tutorial progressed, I felt that Michael explained concepts and topics less and less.
For example, for user sign-in/out, another Rails book simply insert a session[:user_id] = @user.id, but Michael goes through the trouble of creating a new User.remeber_token field (Chapter 9). Why?
Security? Surely not, since he previously explained that cookies are checksumed to make sure that it was not tampered with on the client side. Efficiency? Nope. The session[:user_id] = @user.id is more efficient.
Then there are also other quirks such as modifying the Users table everytime the user logs in (it calls User.remember_me!). (I might be wrong about this, please check me).
I started this tutorial to remove some magic fairy dust from my eyes, but I'm afraid it has blinded me even more.
Michael, I'd really appreciate it if you could answer some of my questions.
NOTE: I've played around w/ RoR before, but not much.
I'll do my best to answer your questions. The session[:user_id] solution you mention only persists over one session, i.e., if a user closes his browser, his session is lost. The tutorial's remember token, on the other hand, persists even after the browser is closed. Once you have a persistent cookie, though, you have a potential security breach. The reason a persistent cookie can't just be the user id is because it can be trivially spoofed: if you can simulate a cookie with id 17 (not hard with, e.g., Perl, Python, or Ruby), you can log in as user 17. That would be a Bad Thing™. By hashing the user id with a salt, we avoid this problem. I've made a note to motivate the remember token better in the tutorial.
Saving the user on each login is correct; it's needed to change the remember token for security purposes. That the remember token doesn't currently change on each login is a bug in the tutorial, and I'll fix it ASAP (probably tomorrow). (The id-salt hash should also include a timestamp.)
Finally, Rails does have a lot of magic, which is a source of its power but is also a potential stumbling block. The Rails Tutorial book is designed not to remove fairy dust but rather to teach you how to use it—mainly because most Rails application developers never need to know what's behind the curtain. (Indeed, in many cases I don't know, nor do I particularly care. After all, Ruby is mostly written in C, but you don't have to dig into the C source to use Ruby.) If you're a pull-back-the-curtain kind of guy, I recommend The Rails Way as a companion volume to Rails Tutorial.
You've raised some good issues here. Let me know if you have any other suggestions: http://www.railstutorial.org/feedback
http://api.rubyonrails.org/classes/ActionController/Session/...
For rails 3 in config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store, :key => '_session', :expire_after => 2.weeksUpdate: I don't see any way to persist the session variable (where do the options go in session[:user_id] = user.id?), and I'm a little nervous about doing so, since the whole point of a session is that it doesn't persist. I'll stick with cookies for now. The Rails 3 version of the tutorial will probably use "permanent" cookies as per this blog post: http://m.onkey.org/2010/2/5/signed-and-permanent-cookies-in-...
Just a note, that cookie is used by created by rails and used dokuwiki using a custom authenication class I made. (dokuwiki verifies the signing)
But a question. I guess I don't fully comprehend Rails sessions, but if you try to spoof user 17, wouldn't Rails notice this due to the cookie checksum?
http://www.railstutorial.org/chapters/sign-in-sign-out#sideb...
and the material surrounding
http://www.railstutorial.org/chapters/sign-in-sign-out#code:...
http://www.railstutorial.org/chapters/sign-in-sign-out#sideb...
Thanks again for bringing this to my attention! :-)
-- Fred
There's a lot of prepwork to be done before PolyTeXnic is ready for release—among other things, I want to write some good documentation first, which IMHO is important for an open-source project but takes a lot of time—so it won't be available soon(ish). More like eventually(ish). :-)