 Saturday, November 24, 2007
It occurred to me that, even though I can't seem to get rspec installed, I still can move forward and write my first story; I'll try to use Test::Unit. Well, I'll start with a controller. ruby script/generate model Item Looks good. The card says that I need to have a link to the picture and a description, so I should have a test that causes me to have those columns. Let's go over to the unit tests and edit item_test.rb. I'll replace the truth test with one of my own. def test_has_a_picture_link_and_a_description expected_picture_link = "http://IAmALink/" expected_description = "WTF?" t = Item.create( :picture_link => expected_picture_link, :description => expected_description ) assert_equal expected_picture_link, t.picture_link assert_equal expected_description, t.description end I run the test and get that it can't create an item. Let's go do a db:migrate to get the test table created. After the db:migrate, I get the expected exception about undefined method description. Let's create a new migration and get it to add the columns. (sidenote: I got autotest working on my machine, but it does an interesting problem that it doesn't apply the migrations to the test database like rake test:units does. I guess, until I figure that out, I'll just make sure that I run a rake test:units if I create a migration. I also installed snarl for my pc, but autotest isn't bringing them up. I guess that is a troubleshooting step for later). After the migration, the test is passing. Now that I've added the attributes, I can write a test for the controller that says I should be able to create a new one. I'll go generate a Controller and write a test for showing new: def test_should_show_new get :new assert_response :success assert_template 'new' assert_not_nil assigns(:item) end This test will cause me to need a new page. I'm going to see if a temporary scaffolding will help. I'll add the following to the top of the ItemController class. scaffold :Item Interesting, when I did a temporary scaffolding, the test came back that it was expecting "new" but rendering with "new.rhtml". I guess I won't use scaffolding, I'll just create a new action on the ItemController. class ItemController < ApplicationController def new end end Interesting! The test failed because it couldn't find a view. I wasn't totally expecting to not be able to test the ItemController without a view. No problem, lesson learned, let's go make a new.rhtml with something stupid in just to have it. We'll start adding to it when we create tests for the view. After adding the view, I get a failure on my test, as expected, since the new action doesn't create a new story. I'll add code to do it. def new @item = Item.new end That did it! Awesome, my first passing controller test. This took me a lot longer than I had hoped, due to some obnoxious oversights on my part. We are back on track, though. Now, let's write a test that posts to the new page and gets saved. def test_should_add_new_item post :new, :item => { :description => 'The Description', :picture_link => 'http://link', } assert ! assigns(:item).new_record? end That fails, so I change new to have support for posting. def new @item = Item.new(params[:item]) if request.post? @item.save end end So far, so good. I'm going to add to the test to make sure that the attributes are set: def test_should_add_new_item expected_description ='The Description' expected_picture_link = 'http://link' post :new, :item => { :description => expected_description, :picture_link => expected_picture_link, } assert ! assigns(:item).new_record? item = Item.find(:first) assert_equal expected_description, item.description assert_equal expected_picture_link, item.picture_link end Where am I missing something? I would have expected this to pass, but it is telling me that item.description is nil. That seems strange.Now, if I have the following lines, then it passes. I'm misunderstanding something about the test facilities that it doesn't have an item in the database to get with item.find(:first). item = assigns(:item) assert ! item.new_record? assert_equal expected_description, item.description assert_equal expected_picture_link, item.picture_link Oh well, I'll stick with that for now. I guess the new_record? will make sure that it got put in the database. So, where am I? I have a new action on my ItemController that correctly creates a new Item with a get and stores the new item with a post. Excellent. Now, I've got about half an hour left, so I'm going to try to write some tests to force a form to be displayed on the view. Let's see if this works: def test_should_show_new_form get :new assert_response :success assert_select 'input', :count=>1 end I get an assertion failure that it expected at least 1, found 0. Let's see if adding that to the view helps: <% form_for :item do |f| %> <p><%= f.text_area :picture_link %></p> <% end %> Well, that worked. I had a couple false starts, because I had done an assert_select 'select' rather than 'input', so I struggled a bit. I need to pay more attention. I think I'm copying too much from examples and not thinking it through. Let's add a little more to the test to experiment a bit with assert_select. assert_select 'input[id=item_picture_link]', :count=>1 Looks good. Let's add one for the description, although this is going to be a text area. assert_select 'textarea[id=item_description]', :count=>1 Jumping back to the view, we can add this line: <p><%= f.text_area :description %></p> to get this test to pass. Now, let's add the submit button. assert_select 'input[type=submit]', :count=>1 I get this test passing with the following line: <p><%= submit_tag %></p> And, presto! I now have a form. I'm going to open it up in a browser, look at it, then submit a new item. I'll load up WEBrick and then go to http://localhost:3000/item/new to view my gorgeous page. AWESOME! Well, after putting some stuff in and submitting it, I jump over to the ruby console and put in the following: >>Item.count => 1 >>Item.find(:first) => #<Item:0x4c70084 @attributes={"id"=>"2", "description"=>"This is a sample what is it", "picture_link"=>"http://sample_link"}> >> Looks like exactly what I wanted! Summary I had a lot of problems due to lack of attention on my part (I was using the Rails book that I just went through as an example, so I ended up with a lot of :story instead of :item) and also because I am just learning the testing framework/rails. I should have been able to get the new action done from start to finish in much sooner, but I am happy about all that I learned along the way. I hope the next action will be faster. :) Or, at the very least, that I learn as much. All in all, though, I'm starting to feel a lot better in the environment, and I think I'm going to enjoy this a lot. I love being able to test-drive my entire view without actually having to pull up a browser. I'm going to have to start worrying about the styling eventually, but not yet. Autotest is very useful. I couldn't get it working on windows earlier, but I found this tutorial on getting autotest working in windows. I haven't seen the Snarl stuff work, but I'm going to look at that later. Unfortunately, I'm out of time for today, so I'm going to wrap this up and put it off until later.
[Update1: I tried doing a list of the repository listed here, and it returned nothing. ruby script/plugin list --source=svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec ruby script/plugin list --source=http://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec ] [Update2: I wonder whether the plugin script pays attention to the svn: protocol, or whether it uses something from subversion. I don't have subversion installed, so I don't know. ] [Update3: I found another rspec on rails tutorial that has the path enclosed in quotes. I'm used to not having to use quotes in powershell, so I tend not to use them unless there are spaces in the name. When I try it with rspec_on_rails (I added a --trace, since it didn't give me output, it gives me the following: ruby script/plugin install --trace "svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec_on_rails" Plugin not found: ["svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec_on_rails"] ] Well, first things first. Let's get a rails project set up with rspec as the test framework. WhatIsThis will be the name of the website, so let's jump into powershell, go to the ruby/rails_apps directory and create the app rails WhatIsThis Ah, the beauty of setting up a rails app, as the console just zips by with the creation of my structure. Let's get rspec installed on rails. I'm taking the recommended approach of installing it as a plugin. Hmmm... First weirdness. I went to my site directory and executed the following two commands: ruby script/plugin install svn://rubyforge.org/var/svn/rspect/tags/CURRENT/rspec ruby script/plugin install svn://rubyforge.org/var/svn/rspect/tags/CURRENT/rspec_on_rails I generally expect some output, but nothing happened; I just got back to my command prompt. Strange. I also would expect something to show up in vendor/plugin, but nothing was there. I ran script/plugin with no parameters to see some help, and it has an example of getting from an subversion repository, but it uses http: instead of svn:, so I'll try that. ruby script/plugin install http://rubyforge.org/var/svn/rspect/tags/CURRENT/rspec Well, at least I got some feedback: Plugin not found: [http://rubyforge.org/var/svn/rspect/tags/CURRENT/rspec] Oh, hey, maybe you've noticed that I spelled rspec wrong (it doesn't have a t). Let's try it without a t. I wonder if Aretha Franklin was on the radio, and I just subconsciously added a t. I ran the correctly spelled and it appears that I already have rspec installed (I installed the gem, I don't know if that has anything do with it). ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec already installed: rspec (svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec). pass --force to reinstall Let's try the rspec_on_rails install. ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec_on_rails Huh? I am getting no feedback again. Nothing, no "not found" or "already installed." Hmmm... Could it be that I don't have svn locally? Let me try the http option. ruby script/plugin install http://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec_on_rails Nope, got the "Plugin not found" error. Now, I am really confused. I can't even get the "already installed" message again. Talk about frustrating. I wonder what I'm missing here. I notice that there is an rspec_on_rails directory in my vendor/plugins, but it is empty. Should I start over? Let's do that. del -recurse WhatIsThis rails WhatIsThis cd WhatIsThis ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec (no output came from this command) ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec_on_rails (no output came from this command) I just don't think those last two lines did anything. There is nothing in vendor/plugins, which goes against my expectations. I ran a ruby script/plugin list, but there is no rspec or anything. I wonder if my powershell needs to be running as administrator. Let's try that. Ran powershell as administrator and executed the plugin install, but it didn't do anything. ARGH! Well, I have to leave to take care of some stuff, so my first session has ended in frustration. Maybe someone will have some ideas?
If you've read any of my ruby stuff, you'll notice that I was using RSpec for the Ruby stuff, then I switched to the Test::Unit framework while working on learning Rails. Why is this? Well, it is very simple: the book I was going through was using Test::Unit. Personally, I really like the RSpec model and am intending to learn to use it for Rails. My current project, What Is This, will be a great opportunity to learn RSpec on Rails, as well. The first step for learning RSpect on Rails is to get RSpec as my test framework for the rails application.
Mary has often told me that she thinks I should write a website that people can put a picture and ask if anyone knows what it is. I've been putting it off, mostly because I didn't feel like writing it in asp.net, which is my general web language (when I have to do web). Now, though, I'm on a roll with learning Ruby and Rails, so I figured it would be a perfect time to do it. The website is going to be called WhatIsThis. There will be two parts to the site: uploading new things; commenting on existing things. I'm first going to focus on uploading new things, so here is my first batch of stories: - Create a new thing
There should be a simple form for creating new things. There will be two items that are required: picture url and description. - View a thing
There should be a simple view for viewing an existing thing. The picture should be displayed. This should cover the first little bit. I'm impressed by the agility inherent in the rails model to support a nice evolutionary design, so I'm not going to worry about much more.
Ron Jeffries and Chet Hendrickson, in their usual style, are blogging their sessions as they add a feature to the website. I recently went through a Ruby on Rails book in order to get familiar with it. I have a specific project that I'm interested in developing, so I thought I would take a cue from Ron and Chet and blog my progress through. Not only will this give me a bit of practice writing, but it will also help keep me focused on what I'm working on, rather than wandering around.
 Thursday, November 22, 2007
As I wrote about previously, I needed to have a logged on user when doing my tests of the StoryController. With a little help from google and "Programming Ruby," I found a way to send the login action to a different controller. This mostly was because I couldn't figure out how to set a session value (session[:user_id]). Just a couple pages later in the book, there are two methods def get_with_user(action, parameters=nil, session=nil, flash=nil) get action, parameters, :user_id => users(:patrick).id end def post_with_user(action, parameters=nil, session=nil, flash=nil) post action, parameters, :user_id=>users(:patrick).id end Well, those are slightly easier. It looks like I know how to set session values on post and get, so I now have learned two things today: how to pass a code block and execute it; and, posting/getting with session variables set. Sweet! Going a few pages later, it has the following paragraph: "If you've been particularly eager, and tried executing your functional test suite prematurely, you'll have noticed that a few tests that worked previously now fail. These failures occur because we modified our story submission form - it requires that a user_id is present in the session before a page request can be successful. Our old tests didn't account for this change, so they now fail." HAHA! It has been ingrained in me that all my tests should pass always before I move on to something new has failed me here; I didn't follow the directions of the book word-for-word. If I had just been satisfied with typing the stuff from the book and following directions, I wouldn't have had spent time figuring out how to get the tests to pass. :) In the end, though, I learned a couple things about Ruby and Rails, so I'm happy.
Interesting. The book I'm going through for rails has added login functionality to adding a new story to the site. I've added a before_filter for the new action on StoryController. before_filter :login_required, :only => :new Now, though, my StoryController tests fail that look at getting the new form. The :login_required filter looks like def logged_in? ! @current_user.blank? end helper_method :logged_in? def login_required return true if logged_in? session[:return_to] = request.request_uri redirect_to :controller => "/account", :action => "login" and return false end Well, unfortunately, in order to get a user logged in, I need to call the :login action on the AccountController. The book didn't include this, so my functional tests for StoryController are failing, as a test like def test_should_show_new_form get :new assert_select 'form p', :count => 3 end doesn't have form with 3 p elements. I had a thought that it was getting redirected, so I changed the test to def test_should_show_new_form get :new assert_redirected_to :controller=>"/account", :action=>'login' end and it passes. So, it appears that the before_filter is working. So, I need to fake out the filter somehow; I need to set up a logged on user. The log on looks like: before_filter :fetch_logged_in_user protected def fetch_logged_in_user return if session[:user_id].blank? @current_user = User.find_by_id(session[:user_id]) end I am not 100% sure if I need to fake the session[:user_id] or just have a @current_user. I tried both, actually, and session[:user_id] = 1 throws an exception in the test. @current_user = users(:corey) doesn't work either. I figured that I could call the login action with credentials from users(:corey). I first tried post :controller=>'/account',:action=>'login', :login => users(:corey).login, :password => users(:corey).password at the top of the my test, hoping that it would call the action and get my system logged in. Here's the exception I got: ActionController::UnknownAction: No action responded to passwordCorey Hainesactionlogincontroller/accountlogincorey That is a really strange error. Looking at it, I think my understanding of the users fixture may not be getting what I think, so I'll try this: post :controller=>'/account',:action=>'login', :login => 'patrick', :password => 'sekrit' Nope, that didn't work either. So, my I do understand users. Looking closer at the exception, I'm guessing that I may just have the parameters for post wrong. Off I go to http://api.rubyonrails.com/ to look up post. post(path, parameters=nil,headers=nil) Doesn't look like the post that I'm using. Doh! Of course it isn't, since I'm using the post from the testing framework. Looking up on google, I finally find a post called "#post method in tests with a different controller." It turns out that you need to redefine the controller, then call post, then reset the controller. Let's try it. I changed the test to the following code: def test_should_show_new_form old_controller = @controller @controller = AccountController.new post :login, :login => 'patrick', :password => 'sekrit' @controller = old_controller get :new assert_select 'form p', :count => 3 end I ran the test, and, voila, it worked! So, now, I just need to add this to the other tests that are failing. I have a test to check adding a story: def test_should_add_story post :new, :story => { :name=>'test story', :link=>'http://www.test.com/' } assert ! assigns(:story).new_record? assert_redirected_to :action=>'index' assert_not_nil flash[:notice] end Let me change it to support logging in: def test_should_add_story old_controller = @controller @controller = AccountController.new post :login, :login => 'patrick', :password => 'sekrit' post :new, :story => { :name=>'test story', :link=>'http://www.test.com/' } assert ! assigns(:story).new_record? assert_redirected_to :action=>'index' assert_not_nil flash[:notice] end HUZZAH! It worked! Let me pull it out into a new method: def login_user old_controller = @controller @controller = AccountController.new post :login, :login => 'patrick', :password => 'sekrit' @controller = old_controller end This seems like a fantastic helper method execute_under_different_controller(controller, code). I'm not 100% sure how to build this method, so I'm going to take a minute to learn how to do it in Ruby. We now have a nice method called execute_different_controller, so changed login_user to def login_user execute_under_different_controller AccountController do post :login, :login => 'patrick', :password => 'sekrit' end end I don't like the fact that I'm duplicating the data from my users.yaml file in my tests. If I load the fixture, I should be able to reference users(:patrick) here. Let's try it. def login_user user = users(:patrick) execute_under_different_controller AccountController do post :login, :login => user.login, :password => user.password end end Well, that worked. I guess I can understand that the book doesn't push too hard on this point, but it is a crazy, dangerous amount of duplication in your tests. This sort of data duplication leads to fragile tests. After adding login_user to the tests for StoryController, things are back on track to continue through the book.
As part of my Rails learning, I've found a situation where I would like to be able to execute a method under a different controller's context. Something like: def login_user old_controller = @controller @controller = AccountController.new post :login, :login => 'patrick', :password => 'sekrit' @controller = old_controller end I'd like to write a helper method that accepts a controller type and a codeblock, then do something like (in pseudo-ruby) def execute_under_different_controller controller, block old_controller = @controller @controller = controller block() @controller = old_controller end I don't think that it is the syntax, although I'm going to try to execute it. In order to do this, I need to figure out how to pass a codeblock to a method and execute it. In order to figure this out, I need to write some tests. So, off I go to powershell to create a new gem for this. I had a set of tests before when I was learning some basic Ruby initially, inspired by Mike Clark's Ruby Learning Test series. newgem learning_ruby --test=rspec My first test looks like this describe "Passing a codeblock" do it "should set a value" do @value = 0 execute_this do @value = 1 end @value.should == 1 end def execute_this block block end end This is my belief that Ruby should really work the way that I think it should. Well, going to my command-line spec spec That didn't work. I got a "wrong number of arguments (0 for 1)" error. I guess it doesn't just pass the do blocks like I thought it should. Let's try this line: execute_this { @value = 1 } I believe that the {} notation is a stand-in for "do end," so this should give me the same result. Same result, so I'll leave it like this. The question is how to execute a passed in block. Off to "Programming Ruby." What do you know, it appears you just call yield. Let's try it: def execute_this yield end And, it worked! Hurra. Now, I can get back to my Rails problem. I want to execute under a different controller, so I'll change the following method: def login_user old_controller = @controller @controller = AccountController.new post :login, :login => 'patrick', :password => 'sekrit' @controller = old_controller end to def login_user execute_under_different_controller AccountController.new do post :login, :login => 'patrick', :password => 'sekrit' end end def execute_under_different_controller controller old_controller = @controller @controller = controller yield @controller = old_controller end That worked. So, here's a question, could I just pass AccountController in and have the execute method call new? Let's try it. def login_user execute_under_different_controller AccountController do post :login, :login => 'patrick', :password => 'sekrit' end end def execute_under_different_controller controller old_controller = @controller @controller = controller.new yield @controller = old_controller end That seems to have worked. So, I now have a nice helper method for Rails.
 Monday, November 19, 2007
Well, I'm having a great time so far working through the Ruby on Rails book that I downloaded. It is really fun, except that Ruby runs like a dog on my machine. It literally takes 10 seconds to run my test suite; it appears that it takes most of the time just to read the files. I disabled my virus scan, but it doesn't seem to have helped. UGH!
 Saturday, November 17, 2007
Well, I have been using Notepad++, but I am going to try UltraEdit for this book. I then might switch back to trying out e. (I followed this script on adding RoR support for UltraEdit. I'll see how it works)
Well, I have officially started on my Ruby On Rails (RoR) learning experience. I downloaded a free RoR PDF from sitepoint and am working my way through it. So far, I have set up MySql (after going through too much figuring out that the password for root was somehow set to sa), installed rails, and I have now done the following stuff in the ruby console: - Create a Stories table in MySql (used the mysql console for this)
- Created a Story class definition in ruby, subclassing ActiveRecord::Base
- Put the following line of code:
story = Story.new story.save and, voila, it showed up in the database. Sweet! I'm going to try to keep blogging my thoughts as I go through it.
| What Kind of Reader Are You? Your Result: Literate Good Citizen You read to inform or entertain yourself, but you're not nerdy about it. You've read most major classics (in school) and you have a favorite genre or two. | | Dedicated Reader | | | Obsessive-Compulsive Bookworm | | | Book Snob | | | Fad Reader | | | Non-Reader | | What Kind of Reader Are You? Create Your Own Quiz | (courtesy of sorting out science)
 Saturday, November 10, 2007
Fraser Cain mentions that the Rosetta spacecraft is going to be making a close encounter with Earth on November 13, 2007. It is doing a fly-by to pick up some speed on the way to Comet 67/P Churyumov-Gerasimenko. Fraser writes a good explanation of gravity assist and why Rosetta is flying back by Earth if the comet is out in space. If you don't know how spaceships can use gravity to speed up, go read it. After that, say hello to Rosetta on November 13.
The Bad Astronomy blog has a cool link to a picture from Earth Science Picture of the Day that shows the paths of solar eclipses over the last two thousand years. You can click on the picture to get a larger view; it is much more impressive big, so do it! Also, he mentions that the next total solar eclipse is August 1st, 2008 and starts in the far north of Canada. The Agile 2008 conference is in Toronto and starts on August 4th. Hmmmm... Wouldn't that be a sweet trip: go see the beginnings of the solar eclipse in way northern Canada, then travel down to Toronto for the conference. Probably won't happen for me, but still a cool dream.
 Wednesday, November 07, 2007
Sarah Rainsberger sent me a link to a great picture from the Agile 2007 conference that is posted on Willem van den Ende's blog. I'll admit that I don't know Willem, although his picture sure does look familiar (I must have met him at the conference). I remember exactly when the picture was taken (although I don't remember the actual camera). I was sitting on the couch, doing some stuff in Ruby that I wasn't totally sure how to do, and, as happens at the Agile conferences, it only took about 2-3 minutes before someone comes over (in this case, it was Joe Rainsberger) and says, "hey, what are you working on?" He knows Ruby better than I do (I'm very much at the "still a beginner" stage), so he sat and we started looking at what I wanted to do. Next thing I knew, we had a few people looking at it. Good times. At the Denver conference in 2005, when Joe won the Gordon Pask award, he said that the Agile conference had become for him a sort of family reunion. Since then, I've quoted him often when talking about the feeling that I get during the week. I love the first day, before the sessions have started, when everyone sees each other again (a lot of people only see each other this one time a year) and gets caught up. For example, I distinctly remember standing in the lobby of the hotel this year (I actually have a picture in my mind of exactly where I was standing), when up walked the other Agile Cor(e)y (he doesn't have an e). I hadn't really spoken to him since the previous year, so it was great to catch up in person. I actually don't spend a tremendous amount of time in the sessions at the conference, as I get a lot more out of the side conversations, where I can share experiences with people. A friend of mine grew up going to camp every summer, and she speaks about it very fondly; it really does seem like it is a huge part of her life. I've mentioned to her that the Agile conference is like my camp. I proudly have said to people that it is one of the personal and professional highlights of my year. I go to my share of other conferences, such as Codemash, SDTConf and XPDay, but I do love the Agile conference for the opportunity to spend a week with a fantastic group of people.
 Monday, November 05, 2007
I'm surprised I don't see more people having this on their wall. After all, there are so many who do believe that the bible contains absolute truth. Perhaps the answers in genesis people can start selling these.
© Copyright 2008 Corey Haines
Theme design by Bryan Bell
newtelligence dasBlog 2.0.7226.0  | Page rendered at Tuesday, December 02, 2008 7:51:29 AM (Eastern Standard Time, UTC-05:00)
Pick a theme:
|
On this page....
| | Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|
| 28 | 29 | 30 | 31 | 1 | 2 | 3 | | 4 | 5 | 6 | 7 | 8 | 9 | 10 | | 11 | 12 | 13 | 14 | 15 | 16 | 17 | | 18 | 19 | 20 | 21 | 22 | 23 | 24 | | 25 | 26 | 27 | 28 | 29 | 30 | 1 | | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
Search
Navigation
Categories
Blogroll
Sign In
|