Wednesday, July 30, 2008

how/when resources are reloaded in Ruby/Rails

I'm developing a RoR application and wanted to keep the controller code as clean as possible by putting extra processing code in the /lib. As I made updates to the /lib resources, I noticed I had to keep restarting my server in order for changes to be picked up. No thank you! That's not why I moved to RoR.

One quick way to deal with this is to use 'require_dependency' instead of simply 'require'.

require 'foo'
require_dependency 'foo'

But when it comes time to migrate your code to production, you don't want the 'require_dependency' statement because it could really impact performance.

One solution seemed to suggest adding extra code in environments.rb
Dependencies.load_paths
Dependencies.explicitly_unloadable_constants

I haven't been able to get this to work successfully, so in the meantime, I will temporarily change 'require' to 'require_dependency' when I'm working with code in a library resource.

Another posting provided me with the 'require_dependency' option listed above (giving credit where credit is due).

Tuesday, July 22, 2008

scaffolding tricks

I've been working with a couple of models that have essentially the same column names, but contain data of different types.
Item
Food
PersonalHygiene
I took advantage of the rspec generator to create the scaffolding, but still only use one table for both Food and PersonalHygiene.

script/generate rspec_scaffold item type:string name:string unit:string quantity:string
script/generate rspec_scaffold food name:string unit:string quantity:string
script/generate rspec_scaffold personal_hygiene name:string unit:string quantity:string


Once I did this, I went back and removed the migrations for Food and PersonalHygiene and changed those models to inherit from Item.

rake db:migrate
rake spec

RSpec & ActiveRecord: working with namespaces

Namespaces can be useful when you don't have the freedom to create as many databases for all of your environments and applications as you would like. Who wants to wait for all the migrations associated with a single database to execute every time tests are run?

There's a great thread out there that addressed this issue very well for me.

The two items towards the end address two different issues.

1. ActiveRecord and RSpec don't seem to work well together when it comes to namespaces; one solution is to use the :sql schema_format. As mentioned in the thread, instead of using schema.rb to recreate the test database, use the development database itself to clone the test database.

2. the second solution could be a real time saver, but it could come back to bite you. It simply omits rebuilding the test database. Therefore, you are responsible for its integrity when running 'rake spec'.

3. then there is the case where #1 doesn't seem to work and RSpec seems to still be prepending the prefix onto the table names multiple times. Someone has found a solution for that as well that deals in a small hack to fixtures.rb.

If you wish to use namespaces, update config/environment.rb to include (putting your own prefix in place)

config.active_record.table_name_prefix = "rcp_"

I believe (at least I remember reading) that you can also accomplish the same thing by adding configuration to the config/database.yml

development:
adapter: sqlite3
database: db/development.sqlite3
timeout: 5000
prefix: rcp_


Everything seems to work well until you run rake rspec . Either one of the above solutions should work for that. When running spec spec/controller/items_controller_spec.rb, you shouldn't run into the same problems that you get when using the rake option.


4:05 PM 7/23/2008

Ok; I have another environment that has Oracle 10.2.0.3.0 and activerecord-oracle-adapter-1.0.0 to provide the oracle_adapter.rb. The fixes I made in my first environment with Sqlite3 to get namespace problems resolved doesn't seem to work in my Oracle environment. Here's how I got things running with Oracle:

1. copy oracle_adapter.rb to ./lib/active_record/connection_adapters
1.1. edit file to include def select_rows...

def select_rows(sql, name=nil)
result = select(sql, name)
result.map{ |v| v.values}
end


It appears the adapter was completely missing a method required by the API. Go figure.

2. copy schema_statements.rb to ./lib/active_record/connection_adapters/abstract
2.1. remove the semicolon at the end of line 305; the Oracle driver doesn't like trailing semicolons when it is read in to clone the test database with the development database (this probably is only the case when schema_format == :sql; see config/environment.rb).

Line 305:
migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}')" }

For something interesting, try this out in script/console:

ActiveRecord::Base.connection.execute("INSERT INTO <your table> (<field>) VALUES(<value>);")
ActiveRecord::Base.connection.execute("INSERT INTO <your table> (<field>) VALUES(<value>)")


The first one fails and the second one passes; the only difference is that the second line doesn't have a trailing semicolon.

3. edit config/environment.rb
3.1. set config.active_record.table_name_prefix = <namespace> (e.g., "... = 'jrn_'") to create a namespace in the database for your Rails application
3.2. set config.active_record.schema_format = :sql, especially if you are going to use a namespace. Rake tends to trip up (i.e., rake spec) because of how schema.rb is read in multiple times (you end up with the prefix being applied multiple times -- e.g., 'jrn_jrn_items').

4. of course, make sure to update config/database.yml with the appropriate values

Make sure that your migrations are not in the development and test databases and then run RSpec

rake spec

Friday, July 18, 2008

RSpec MVC boundaries: why I was getting back template locations instead of html

I finally found the rock in my shoe. The reason why response.body wasn't returning html is due to a mechanism in

the RSpec library (gem install) that mocks the interaction with the Views by default, specifically the file controller_example_group.rb. As I surmised before, there are some matching methods that don't make much sense in certain contexts; in fact, as stated in the documentation in the code itself, 'we encourage you to explore using the isolation mode and revel in its benefits'. The ideal RSpec testing truly isolates MVC components from each other.

To override that behavior and have a more 'integrated' test experience, simply declare integrate_views in the spec controller context. I have actually read this in another blog somewhere where the term 'integration mode' was used casually (and I didn't know what it meant at the time).
# == Integration mode
#
# To run in this mode, include the +integrate_views+ declaration
# in your controller context:
#
# describe ThingController do
# integrate_views
# ...
#
# In this mode, controller specs are run in the same way that
# rails functional tests run - one set of tests for both the
# controllers and the views. The benefit of this approach is that
# you get wider coverage from each spec. Experienced rails
# developers may find this an easier approach to begin with, however
# we encourage you to explore using the isolation mode and revel
# in its benefits.
Just to reiterate, according to my understanding of the authors' views, to integrate the View elements would be almost defeating the purpose of RSpec's approach to testing. Model, Controller, and View elements should all be tested within each others' spheres.

That being said, here is the code responsible for overriding the 'preferred' behavior:
# Use this to instruct RSpec to render views in your controller examples (Integration Mode).
#
# describe ThingController do
# integrate_views
# ...
#
# See Spec::Rails::Example::ControllerExampleGroup for more information about
# Integration and Isolation modes.
def integrate_views
@integrate_views = true
end
def integrate_views? # :nodoc:
@integrate_views
end
Below, you see where the check is made to see if the View elements are to be included (i.e., unless integrate_views?). You can see in the block that follows that check the code that gets executed if the declaration isn't there.
# === render(options = nil, deprecated_status = nil, &block)
#
# This gets added to the controller's singleton meta class,
# allowing Controller Examples to run in two modes, freely switching
# from context to context.
def render(options=nil, deprecated_status=nil, &block)
unless block_given?
unless integrate_views?
@template.metaclass.class_eval do
define_method :file_exists? do
true
end
define_method :render_file do |*args|
@first_render ||= args[0]
end
end
end
end

if matching_message_expectation_exists(options)
expect_render_mock_proxy.render(options, &block)
@performed_render = true
else
unless matching_stub_exists(options)
super(options, deprecated_status, &block)
end
end
end
Bottom line, the boundaries between the Model, View and Controller elements should really get you to think about what needs to be tested in the spec'ed element... but it's nice to know there are options.

RSpec:Controllers:can the 'have_tag' be used in Controller testing?

Other sources indicate that one should be getting back html content in the response.body attribute:
- Action Pack 0.7.5: On rails from request to response

* Easy testing of both controller and template result through
TestRequest/Response

class LoginControllerTest < Test::Unit::TestCase
def setup
@request = ActionController::TestRequest.new
@request.host = "http://somewhere"
end

def test_succesful_authentication
@request.action = "authenticate"
@request.request_parameters["user_name"] = "david"
@request.request_parameters["password"] = "secret"

response = LoginController.process_test(@request)

assert_equal(
"http://somewhere/clients/", response.headers["location"])
assert_equal Person.find(1), response.session["person"]
assert(response.body.split("\n").include?(
"<h1>You've been logged in!</h1>"))
end
end

Learn more in link:classes/ActionController/TestRequest.html


It appears that this code snippet from a controller test (even though it's not RSpec) is able to get html from the response.body attribute.

RSpec; what methods and when to use them

In the true nature of a blog, my daily hikes will be somewhat random, driven by much of what I do at work and what tickles my interest at the time. At some point, I will consider consolidation in some organized fashion, but hey... I'm getting ahead of myself.

My current topic deals with RSpec. Suffice to say, I am novice at Ruby/Rails; I love it. You don't need yet another testimonial here, so I won't spend the keystrokes. I really like what I see of RSpec. I am a strong advocate for unit tests. I've spent the last 3 years doing JUnit tests and I will always write unit tests. When I was introduced to RSpec at work, it took me a little time to get my brain around how they worked. It's been somewhat of a challenge to find a comprehensive tutorial on how RSpec works, although there is something out there. A few that I've found useful include:

general RSpec documentation
- http://rspec.info/
- BDD definition and old install instructions for RSpec

tutorials for using RSpec
- an-introduction-to-rspec-part-i
- rspec-tutorial
- developing-a-rails-model-using-bdd-and-rspec-part-1
- rspec-plain-text-story-runner-on-a-fresh-rails-app

reasons for using BDD
- in particular, RSpec
- rspec-and-unit-tests-localizing.html

As I understand it, RSpec is good at
  1. concisely and quickly defining high-level requirements
  2. being easy to read/understand
  3. separating testing dependence from other MVC elements
    1. controller tests never have to touch models or views; you can start testing controller functionality and mock and stub out only the necessary elements of models and views that the controller would interact with in real life
  4. cut down on test repeat (DRY; Don't Repeat Yourself); don't run model tests in the controller when those test are already being run in the model tests

That being said, I think I must be too wet behind the ears still because there are still somethings that I am not fully grasping. There are a whole host of functions that may be used in RSpec test writing. I believe these functions are made available through some Module that is applied by the RSpec gem or plugins.
# example
article = mock_model(Article)
article.should_receive(:author).and_return("Joe")
article.should_receive(:text).and_return("this is the text of the article")
assigns[:article] = article
assigns[:articles] = [article]

One thing that has snagged me in the past is not clearly understanding which of these helper RSpec methods is to be used in a given context. There is a set of helpers that are appropriate to use with Controller tests, another set for View tests, etc. Some might work across all contexts, but I'm finding that not all do (and perhaps don't even make sense).

For example, yesterday I spent a lot of time trying to write RSpec tests for a Controller. I never could figure out why the test didn't work. I was trying to use the 'have_tag' helper.
response.should have_tag('div', /regexp matching expected content/)
I debugged the test and tried to analyze the response object. This object, I believe, is provided by Rails and has nothing to do with RSpec. The response object has a body attribute which I was expecting to contain the generated html that is returned by the application. What I found was the path to the resource instead.
describe "#index" do
it "should return a list of show times" do
get :index
debugger

response.should have_tag("li")
end
end
You will probably need to install support for the ruby debugger if you haven't already in order for the sample above to work. As you would expect, when the test is executed, execution will break when it reaches the line with the string debugger. And all this to explain how I discovered what the value of response.body was when running the Controller test, which was:
"show_times/index"
Why wasn't there html in there? I'm not sure, actually. One theory is that Rails hasn't actually got to the point where it has retrieved the html yet, it's only set where it will pull the content from. What ever the reason is, this whole situation eventually got me thinking, "Do I really want to have that test in the controller anyway?" Isn't that a test of the view element anyway? And we want to be DRY, don't we? Perhaps it is a good thing this test has never worked because it might just be teaching me to pay more attention to what tests I am using and where I am putting those tests.

In fact, when I ran the debugger in the View context, I was getting back html content in the response.body attribute. This would suggest that one should only use have_tag in a View RSpec test.

A good TRail guide to consult would probably be Introduction to Writing Examples using Spec::Rails. After all, when it doubt, read the directions, right?

Getting ready for the hike

I have been dabbling in Ruby/Rails for the last year or so at home. It has been an absolute blast, so much fun, in fact, that I decided to jump from the comfortable waters of Java from my last job to another job steeped in Ruby/Rails. I realize now that I really know very little and have quite a bit to learn regarding the technology.

It's always fun to learn something new... that means I'm having a load of fun right now! At the risk of sounding childish and whiny, the Ruby/Rails technology still shows signs of explosive growth... so much so that it's difficult to find a consolidated set of reference and tutorial documents that reflect how to use the latest gem and plugin options that are available for it.

I hope to provide some good trail logs on my journey that can help other pseudo-novices on the Ruby/Rails trail. It's amazing what a well-placed marker can do and I myself can definitely use as much advice from more veteran hikers on the TRail. Hope to see you at the top.