Open Source Rails Site

I found a site called Open Source Rails. It is a listing of sites that are written in Rails. I will look at it in more detail later.

It might be a good way to see how some high-profile Rails apps test stuff. I think I might be able to see how certain things are done and tested in Rails, sort of like a Rails cookbook.

Image from the Rheinau Psalter, a 13th century manuscript housed at Central Library of Zurich. Image from e-Codices. This image is assumed to be allowed under Fair Use.

Update On RailsApps Tutorials

I started using the RailsApps tutorials.

They are pretty good, but I noticed a glaring flaw: There is only one model, the User model. You don’t just create an app where users do nothing.

So I started working with a couple of them to add another model. I also wanted to be able to test them. I wanted to make Capybara tests to test actions for both authenticated and unauthenticated users, similar to what Hartl does, but with a standard authentication gem. Some of the RailsApps use Cucumber, but I have noticed that most Rails developers are not interested in Cucumber, and it looks like Capybara can do some of the things that people do with Cucumber.

One of the apps uses Devise. I have a Github repo based off of the rails3-devise-rspec-cucumber RailsApps tutorial:
https://github.com/emacadie/rails3-devise-rspec-cucumber/tree/add_book
The “add_book” branch has the authentication tests. The model is called Book.

Note 2015-06-14_12.46.25: Now at https://github.com/EMacAdie/rails_apps_dir/tree/master/rails3-devise-rspec-cucumber – HerokuPinger now at https://github.com/EMacAdie/rails_apps_dir/tree/master/heroku-pinger

I have another app that uses Omniauth called Heroku Pinger. The “second_attempt” branch has some tests that I think do what I am trying to do:
https://github.com/emacadie/heroku-pinger/tree/second_attempt

People will put up a free app on Heroku, but sometimes when they give out the URL the app will not be very responsive since Heroku puts free applications into a hibernate mode. This app was intended to allow people to have a few apps get pinged every hour. John McCaffrey told me that is not very sportsmanlike since the point of free apps is to not suck up too many resources. He is correct, but I decided to keep going because the real point was to work with OmniAuth, and eventually work with mocking and stubbing tests as well. Besides, you could ping any site, not just a Heroku site.

For the Devise app, it turned out to be pretty simple. I did some googling on how to get a Devise session in Capybara. A lot of the results said you had to mess with a Devise dependency called Warden. They say you need to put the following line in your tests:

include Warden::Test::Helpers

I think that some of that information might be out of date, because I went back and commented out those lines, and the Capybara tests still do what I intend them to do. Perhaps updates to the gems made that unnecessary.

The magic is to get an instance of Capybara::Session and pass it around as you need it. I put the code in spec/support/session_provider.rb:

require "spec_helper"

include Capybara::DSL
include Capybara::RSpecMatchers

  class SessionProvider
    attr_reader :the_session
    def self.get_session
      the_session ||= create_session
    end

    private
    def self.create_session
      user = User.create(:name => "Joe",
                       :email => "alindeman@example.com",
                       :password => "ilovegrapes",
                       :password_confirmation => "ilovegrapes")

      visit "/users/sign_in"
      puts "Here is method of visit: #{self.method(:visit).owner} "

      fill_in "Email", :with => "alindeman@example.com"
      fill_in "Password", :with => "ilovegrapes"
      click_button "Sign in"

      page.should have_content("Signed in successfully.")
      return page
    end
  end

The Capybara::Session is stored in the “page” variable. You can use it like this:

  it "gets a page to add book with session provider" do
    p = SessionProvider.get_session
    visit "/books/new"
    # puts "Page is a #{page.class}"
    page.should have_content("New book")
  end

 

I have a slightly more involved test that actually adds a book and checks that the count of Books has increased by 1.

The OmniAuth test took me longer. Part of is I later realized was that I was using methods like “get” from the Controller tests, and not the Capybara “visit” method. Capybara has a “get” method, but for some reason I got nowhere with that. I wasted a lot of time thinking it would work.

The SessionProvider class is in spec/support/session_provider.rb and looks like this:

require "spec_helper"
include Capybara::DSL
include Capybara::RSpecMatchers
  class SessionProvider
    attr_reader :the_session
    def self.get_session
      the_session ||= create_session
    end
    private
    def self.create_session
      OmniAuth.config.test_mode = true
      OmniAuth.config.mock_auth[:twitter] = {
      'uid' => '12345',
      'provider' => 'twitter',
        'info' => {
        'name' => 'Jimmy C'
        }
      }
      @user = FactoryGirl.create(:user)
      visit '/signin'
      return page
    end
  end

In the tests that use this, you just do this:

it "should contain link to stuff" do
      p = SessionProvider.get_session
      visit "/websites"
      response.body.should have_content('Listing websites')
      response.body.should have_content('New Website')
 end

 

 

I looked at the OmniAuth wiki and a few posts on StackOverflow and tried and re-tried several  times, until I had my “visit” epiphany.

 

Image from the Sinope Gospels, a 6th-century Byzantine manuscript housed at the Bibliothèque nationale de France (Wikipedia page here), manuscript information here, image from Wikimedia, image assumed allowed under Fair Use.

Update on Chicago Ruby Testing Group

The Chicago Ruby Testing Group is currently on hold. We are revising the curriculum. We will also probably only do it once a week instead of twice a week.

Right now I am working on a short presentation on Cucumber. A big chunk of it will cover why we will not be spending a lot of time on Cucumber. A big reason is the network effect: It seems like a beast, yet it does not have a lot of traction. But people might encounter it, so I think we should cover it.

Image from a 12th century manuscript housed at Bavarian State Library, webpage information here, image from World Document Library, image assumed allowed under Fair Use.

Notes On Creating Test Data With FactoryGirl

A while ago Steve Klabnik posted about creating objects for tests via FactoryGirl  and there was another post in response.

I am working with FactoryGirl for Heroku Pinger. I was trying to restrict users to only create five websites.

To test this, I copied the test “creates a few websites with FactoryGirl” into a new one called “only creates five websites with FactoryGirl”. It failed. It seemed to allow the user to only create 5 sites, but at the end of the test the site count (querying on user_id) was 11. I could not figure this out.

Then it hit me: FactoryGirl was creating an array of sites using the generate_factory_sites method. I would then take that array and try to create the sites again. The user’s site count is only checked in the website controller, while FactoryGirl uses the model directly. So by the time I am checking to see how many sites a user has, I am already over the limit, and the limit is set to 0. So I changed the test to put data for websites in an array of hashes first, and use the hashes to create the sites manually.

I might go back later and clean things up. (I was about to write “I will”, but let’s be honest: how often does that REALLY happen?)

I also put in something to ensure that a user can only delete their own sites. That was a hassle.

So what I tried to do is to add some sites with one user id, and then delete them with another, and then delete them with the first user ID. It did not work. The session variable user_id will not change. I read online that you can set it like this:
session[:user_id] = JDJDDJ
but that did not work.

So I added some sites, changed the user ID of that site instance, then deleted it with the first user ID.

I created two users and changed the user_id in the website model, and then tried to delete the sites. I was not able to delete the sites after changing the user_id field in the website objects. Then I changed it back and deleted the sites.

Image from World Digital Library, assumed allowed under Fair Use. Image from the Psalter of Frederick II, a 13th century manuscript in the Byzantine style, housed at Riccardiana Library of Florence, aka Biblioteca Riccardiana.

Ruby Testing Archaeology

Note 2022-12-06: This is a consolidation of three posts, two posted on 2012-07-17, and one posted on 2012-07-23.

POST 1:

One of my frustrations with Rails is that there are few if any ‘include’ or ‘require’ statements. Now I am going to do something about it. At least something for myself.

I went through the Hartl tutorial (as do most Code Academy students, and many aspiring Rails devs). He uses RSpec and Capybara for testing. RSpec can be used for any Ruby project, while Capybara is used for web projects. I think it can be used for other Ruby web frameworks, and other testing frameworks besides RSpec.

One thing I find in the tutorial and the tests is that Hartl will just call methods and instantiate variables. I don’t always know whether he is calling something from RSpec or Capybara.

At one point, he says this: Because of subject { page }, the call to should automatically uses the page variable supplied by Capybara (Section 3.2.1). This is in refernce to the  file spec/requests/static_pages_spec.rb.

But where in Capybara does “page” come from?

You see it in code like this:

subject {page}

The “subject” method is used for the models as well:

subject {@user}

But there is no “page” model, or a “page” factory.  But it raises another question in my mind: What is “subject”?

I am pretty sure “subject” is from RSpec, either
http://rubydoc.info/gems/rspec-core/RSpec/Core/Subject/ExampleGroupMethods#subject-instance_method
or
http://rubydoc.info/gems/rspec-core/RSpec/Core/Subject/ExampleMethods#subject-instance_method

In the Hartl specs (2nd edition) you see this (via grep -r subject * | grep page)
requests/static_pages_spec.rb:5:  subject { page }
requests/authentication_pages_spec.rb:5:  subject { page }
requests/micropost_pages_spec.rb:5:  subject { page }
requests/user_pages_spec.rb:5:  subject { page }

In the Hartl tutorial, at say, like http://ruby.railstutorial.org/chapters/filling-in-the-layout#sec:pretty_rspec, he says
Because of subject { page }, the call to should automatically uses the page variable supplied by Capybara (Section 3.2.1).

So where does “page” come from? I am looking around the Capybara docs, and on http://rubydoc.info/github/jnicklas/capybara/file/README.md I see this:
Full reference: Capybara::Node::Matchers

Capybara has a rich set of options for querying the page for the existence of certain elements, and working with and manipulating those elements.

page.has_selector?(‘table tr’)
page.has_selector?(:xpath, ‘//table/tr’)
page.has_no_selector?(:content)

page.has_xpath?(‘//table/tr’)
page.has_css?(‘table tr.foo’)
page.has_content?(‘foo’)

After some googling and some digging, and it looks like “page” is part of the Capybara::DSL module:
http://rubydoc.info/github/jnicklas/capybara/master/Capybara/DSL

It looks like it returns a Capybara::Session object.

At some point I will make a separate page or post with just the methods that pop out of nowhere, and whether they are RSpec or Capybara.

POST 2:

I made some progress on this.

If something is a class, like “page” in the Hartl tutorial (like on say spec/requests/static_pages_spec.rb)
you could just do

puts "Here is page.class: #{page.class}"

which would give you

Here is page.class: Capybara::Session

I don’t know why I didn’t think of that before.

In that file he also calls some voodoo methods. In before do he has:

sign_in FactoryGirl.create(:user)

and

visit users_path

sign_in and visit are methods. You can get these by doing this:

meth = self.method(:sign_in)
puts "Here is method of sign_in: #{meth.owner}"
meth2 = self.method(:visit)
puts "Here is method of visit: #{meth2.owner}"

or you could do that on one line each like this:

puts "Here is method of sign_in: #{self.method(:sign_in).owner} "
puts "Here is method of visit: #{self.method(:visit).owner} "

Which will give you:

Here is method of sign_in: Object
Here is method of visit: Capybara::DSL

Granted, getting “Object” is not too helpful. But it is some progress.

Someone on the Rails core team has a post about finding methods here.

POST 3:

In two previous posts, I wrote about my frustrations with methods in Rails tests that just seem to float in space and appear out of nowhere, and that the Hartl tutorial mixes RSpec and Capybara, and that it would be nice to know which is which.

In the last post, I wrote that sometimes when you try to find which class contains a method you get “Object”, which is not very helpful.

puts "Here is method of sign_in: #{self.method(:sign_in).owner} "
puts "Here is method of visit: #{self.method(:visit).owner} "
Here is the output:
Here is method of sign_in: Object
Here is method of visit: Capybara::DSL
The “sign_in” method is from one of the tests in the Hartl tutorial. I was explaining this to someone about an hour ago, and I realized why self.method says that  “sign_in” is part of the “Object” class: Because it is not defined in a class. In the application, Hartl defines it in a module, but in the tests it is simply defined in a file that contains neither  a class or a module.

In the root of the Rails tutorial app, you can run a grep command to find that method:

grep -rn 'def sign_in' *
This will give you the following result
app/helpers/sessions_helper.rb:3:  def sign_in(user)
spec/support/utilities.rb:3:def sign_in(user)

So here is the file spec/support/utilities.rb:

include ApplicationHelper

def sign_in(user)
  visit signin_path
  fill_in "Email",    with: user.email
  fill_in "Password", with: user.password
  click_button "Sign in"
  # puts "Here is method of click_button: #{self.method(:click_button).owner} - "
  # Sign in when not using Capybara as well.
  cookies[:remember_token] = user.remember_token
end

As I stated, in app/helpers/sessions_helper.rb the method is in a module called  SessionsHelper

 

Image from Pericopes Book of Henry II, an 11th century manuscript housed at Bavarian State Library, webpage information here, image from World Document Library, image assumed allowed under Fair Use.

 

Ruby Announcements

They are not announcements about Ruby in general, just about me.

First off, I submitted two proposals to speak at Lone Star Ruby Conf in Austin, Texas in August. One was accepted, and one was rejected. I started work on my presentation. I may also start the other presentation later at some point.

Also: The RSpec Study Group that I keep talking about is finally getting off the ground. The first day will be July 9th. Expect more details soon. It may be known at the Chicago Ruby Testing Group, since we will talk about more than just RSpec. We will still focus on Ruby testing technologies, so Python, PHP, dot NET and Java people will be out of luck. I am working on this with another Code Academy alum, with some help from a couple of Code Academy mentors.

Image from an 11th century manuscript housed at Bavarian State Library, webpage information here, image from World Document Library, image assumed allowed under Fair Use.

 

Coding Without Testing – just for now

Since I got done with Code Academy, I have not done as much coding as I should be doing.

I am still working on getting the Ruby Testing Group off the ground. I am going through The RSpec Book, and I am going through The Well Grounded Rubyist. I am still going through all my stuff (I am amazed at how much I have accumulated).

I am still learning new stuff. I think now that I have perhaps subconsciously inhibited myself from coding because I am not ready to test all parts of a Rails app from the beginning. I still want to be a great coder, and I know that requires writing tests, but I think that I need to start building. Even if that means not writing tests right now.

Image from Sacramentary of Henry II, an early 11th century manuscript housed at Bavarian State Library, webpage information here, image from World Document Library, image assumed allowed under Fair Use.

Notes On Making a Gem


I decided to make a gem for a bit of practice. I did some googling, and I found a good RailsCast on it.

He uses bundler, which takes care of a lot of the heavy lifting. All I did was run

bundle gem states

This will create a directory with the same name as whatever you called the gem. Then to add RSpec, cd to the directory that was created. Then run

rspec --init

I wanted to make a gem with a few layers in the directory tree. Java package names tend to have multiple levels, while most Ruby gems seem to only go one level deep. Perhaps I will never write a gem that has too many levels, but I wanted to make one with a few levels anyway.

I decided to start with a state in the first level. I added

require "states/hawaii"

to lib/states.rb
Then add a file: lib/states/hawaii.rb

module States
  class Hawaii
    def initialize
      puts "in hawaii"
    end
  end
end

Then I added a test file. Then in spec/spec_helper.rb, add

require 'states'

I added the  file spec/states/hawaii_spec.rb

require "spec_helper"
module States
  describe Hawaii do
    it "should do something" do
      hawaii = Hawaii.new
    end

  end
end

There is another way to recognize the module levels in the RSpec file:

require "spec_helper"

describe States::Hawaii do
  it "should do something" do
    hawaii = States::Hawaii.new
  end

end

I put

require 'spec_helper'

in each spec file.

I also added a class lib/states/illinois.rb, and a test file in spec/states/illinois_spec.rb.

I then tried to add a few classes for Champaign County and Urbana. I tried to put them in a directory lib/states/illinois and in spec/states/illinois.

I got this error:

  lib/states/illinois/champaign_county.rb:2:in `<module:States>': Illinois is not a module (TypeError)

But I changed the directory name to illini, and I updated the files accordingly, and it worked. I changed it all back to “Illinois”, and it stopped working again. So now the module is back to “Illini”. I do not know if Ruby or RSpec will not allow a directory and a class to have the same name, or if I just needed to put illinois.rb in a higher directory. There is a states.rb and a states directory. Perhaps the gem name is an exception to the uniqueness rule. But in the future I will stick with using different names.

So, to summarize, I ran

bundle gem states

Then to add RSpec, I ran

rspec --init

For every class that I made, I put a file in lib, a corresponding file in spec, and I put a require statement in the states.rb file.
And the class file names must not be the same as the directory names.

ericm:/states$ tree
.
├── Gemfile
├── lib
│   ├── states
│   │   ├── hawaii.rb
│   │   ├── illini
│   │   │   ├── champaign
│   │   │   │   └── urbana.rb
│   │   │   └── champaign_county.rb
│   │   ├── illinois.rb
│   │   └── version.rb
│   └── states.rb
├── LICENSE
├── notes.txt
├── Rakefile
├── README.md
├── spec
│   ├── spec_helper.rb
│   └── states
│       ├── hawaii_spec.rb
│       ├── illini
│       │   ├── champaign
│       │   │   └── urbana_spec.rb
│       │   └── champaign_county_spec.rb
│       └── illinois_spec.rb
└── states.gemspec

8 directories, 17 files


I am sure that for a lot of Ruby people, this post will be review. I tried making a gem using some of the code from the RSpec book as a basis, and I could not get it to work. I did the guy thing by trying something without reading the directions. I am thinking of proposing a talk for Lone Star Ruby Conf, and I need to be able to get a gem to work.

Update On RSpec Group 2012-05-20

There has been a smidge of progress for the RSpec Study Group. Part of the issue is I am not clear how to go about it. I talked with The Fonso and Ginny Hendry about it, and they gave me a few ideas. Even though I am calling it the “RSpec Study Group”, we will cover other frameworks as well. The RSpec book covers Cucumber for a couple of chapters before it gets to RSpec.

Perhaps we will have a meeting a week.

One week will be going through a chapter in the RSpec book.

Another week could be a hack night where we write tests for someone’s project.

Another week could be a lecture from someone in the community. Ginny pointed out that people have pretty set opinions on testing, and it would be good to expose people to multiple viewpoints. I talked to one of the developers of gathers.us if they would be willing to share their ideas about testing. One of the reasons they made gathers.us was to get experience with Cucumber and Capybara.

Image from Book of the Passion of Saint Margaret the Virgin, with the Life of Saint Agnes, and Prayers to Jesus Christ and to the Virgin Mary, a manuscript made in Bologna in the late 13th century. Image from World Document Library, assumed allowed under Fair Use.

 

Update On RSpec

I do not think there will be a meeting of the RSpec group this weekend. I plan on meeting my non-technology friends.

I was going through the Hartl tutorial while in Code Academy. I was planning using some of his tests in our app, but I could not get it to work. So I realized I should probably go through the RSpec book and learn me some more RSpec. As well as some Cucumber and Webrat or Capybara.

I plan on going through the RSpec book myself before really getting rolling with the RSpec group. I will put the code up to Github. I do not know if I will get all the way through it, or if I will skip around. The book talks about Webrat to simulate the browser. It seems like the world has moved on to Capybara. But I will make a valiant attempt.

Image from Wikimedia, assumed allowed under Fair Use. Image from the St Augustine Gospels, a 6th century manuscript made in Italy in the 6th century, brought to Britain by the Other Saint Ausgustine.