March 25th, 2008 at 10:31 pm
(Rails)
Remember all that joy coding with Rails when you were a wee lad? Things seemed so blissful then, metaprogramming voodoo and that complex object relational mapping stuff were all taken care of behind the scenes.
Alas, whence it doth time to unleash your brilliant social networking app onto the unsuspecting public, your Ruby/Rails world came crashing down faster than FSJ can order a chai latte.
FastCGI, SCGI, Mongrel, Rack, Thin, Pound, Nginx, Apache.
Doing a virgin Rails application deployment would have been a trial by fire where you’ll trawl the Ruby and Rails forums looking for advice on which webserver is best suited to serve your future web application superstar or pray to the One and just deploy on faith.
You’ll settle for Mongrel or Rack if you were lucky enough to come across people who have been there before. Otherwise, be prepared to be regaled with war stories about how some web hosts *COUGH* Dreamhost *COUGH* arbitrarily shutdown your Rails processes for consuming a tad too much resources.
Wouldn’t it be nice if I could just do like what I did for PHP applications? Just upload the files onto the webserver and it just works(tm)?
Now you can! Well, technically only the people at Phusion can at this moment. Lai Hongli breaks the news about modrails, complete with requisite cool screencast.
I think this is a really cool development that makes life a whole lot simpler for people who just want to focus their energies on actual development rather than have to worry about how to configure the deployment environment properly. Even if this is Apache2 only now, it should be possible to port it over to other servers like Nginx, licence restrictions notwithholding.
1 Comment
March 24th, 2008 at 12:20 pm
(Behaviour Driven Development, Ruby)
RSpec allows a developer to specify that an error is raised within a block with the raise_error method. It's a nice expressive way of saying that your code should fail when it needs to.
But my tiny brain has often been confused with using it at times, more so when the error class requires parameters for instantiation and when used in conjunction with the and_raise method on a stub or a mock
Consider the snippet below where my Widget depends on Thingamajig to do its funky thing in order to run. But Thingamajig is rigged to explode in a mass of funkyness and make Widget all useless.
CODE:
-
describe Widget do
-
it "should re-raise errors as a Widget::UnrecoverableError" do
-
# expectations
-
thingamajig = stub(Thingamajig)
-
thingamajig.should_receive(:do_funky_thing).and_raise(Thingamajig::FunkyExplosion.new('The funky thang exploded yo'))
-
-
# our SUT
-
widget = Widget.new(thingamajig)
-
-
#verification
-
lambda { widget.run }.should raise_error(Widget::UnrecoverableError, 'The funky thang exploded yo')
-
end
-
end
Do you notice the inconsistency between the way errors are declared in the expectation and the actual verification?
CODE:
-
# expectations
-
thingamajig.should_receive(:do_funky_thing).and_raise(Thingamajig::FunkyThingExplosion.new('The funky thang exploded yo'))
-
-
#verification
-
lambda { widget.run }.should raise_error(Widget::UnrecoverableError, 'The funky thang exploded yo')
The expectation on the stub, 'thingmajig' needs the exception instantiated first while verification requires the class name and parameters used to instantiate the error instance.
And no, doing it like this doesn't work as expected:
CODE:
-
lambda { widget.run }.should raise_error(Widget::UnrecoverableError.new('The funky thang exploded yo'))
It's an unfortunate impedance mismatch that might be caused due to the way Ruby handles the raising of errors.
Comments
February 2nd, 2008 at 1:09 pm
(Agile, Ruby)
I decided to use cruisecontrol.rb for continuous integration of an application that I'm working on at Bezurk. So I downloaded the 1.2.1 release from RubyForge and proceeded to add the project repository to the local installation of cruisecontrol.rb.
douglas@macbookpro:~$ ./cruise add MyProject --url http://path.to/repository --username 'douglas' --password 'guessable'
douglas@macbookpro:~$ ./cruise build MyProject
Builder for project 'MyProject' started
Logging to: /Users/douglas/Development/Ruby/cruisecontrolrb-1.2.1/log/MyProject_builder.log
Build loop failed
BuilderError: svn: PROPFIND request failed on '/svn/my_project/trunk'
./script/../config/../app/models/subversion.rb:98:in `execute_in_local_copy'
./script/../config/../lib/command_line.rb:86:in `call'
./script/../config/../lib/command_line.rb:86:in `e'
./script/../config/../lib/command_line.rb:84:in `popen'
./script/../config/../lib/command_line.rb:84:in `e'
./script/../config/../lib/command_line.rb:71:in `execute'
./script/../config/../lib/command_line.rb:70:in `chdir'
./script/../config/../lib/command_line.rb:70:in `execute'
./script/../config/../app/models/subversion.rb:89:in `execute_in_local_copy'
./script/../config/../app/models/subversion.rb:85:in `chdir'
./script/../config/../app/models/subversion.rb:85:in `execute_in_local_copy'
./script/../config/../app/models/subversion.rb:44:in `latest_revision'
./script/../config/../app/models/project.rb:228:in `new_revisions'
./script/../config/../app/models/change_in_source_control_trigger.rb:8:in `revisions_to_build'
./script/../config/../vendor/rails/actionpack/lib/../../activesupport/lib/active_support/core_ext/symbol.rb:10:in `__send__'
./script/../config/../vendor/rails/actionpack/lib/../../activesupport/lib/active_support/core_ext/symbol.rb:10:in `to_proc'
./script/../config/../app/models/project.rb:223:in `collect'
./script/../config/../app/models/project.rb:223:in `revisions_to_build'
./script/../config/../app/models/project.rb:202:in `build_if_necessary'
./script/../config/../app/models/polling_scheduler.rb:13:in `run'
./script/builder:79
./script/builder:78:in `catch'
./script/builder:78
./cruise:14:in `load'
./cruise:14:in `builder'
./cruise:68:in `send'
./cruise:68
/opt/local/lib/ruby/1.8/fileutils.rb:121:in `chdir'
/opt/local/lib/ruby/1.8/fileutils.rb:121:in `cd'
./cruise:67
Hmm, what's with the svn: PROPFIND error? Looking at the stracktrace doesn't tell me alot about what's going wrong here, let's try logging errors to the console.
--SNIP--
douglas$ svn --non-interactive info --xml
douglas$ svn --non-interactive log --revision HEAD:20 --verbose --xml
svn: PROPFIND request failed on '/repository/trunk'
svn: PROPFIND of '/repository/trunk': authorization failed (http://svnhost.com)
--SNIP--
It happens that my repository does not have anonymous access and requires a subversion user account to do anything useful. So it should be obvious that cruisecontrol.rb is trying to get log info from the repository but subversion is quitting with authentication errors because no user credentials are being supplied.
I need to have cruisecontrol.rb make use of the --username and --password options when making queries to the repository when I give it the credentials for access.
My first stop is the app/models/subversion.rb. Only the checkout method uses the username and password instance variables. Subversion should only include the --username and --password options when executing svn commands when both the username and password instance variables are present.
RUBY:
-
test/unit/subversion_test.rb
-
-
def test_svn_command_uses_user_password_when_provided
-
svn = Subversion.new(:username => 'jer', :password => "crap")
-
-
svn.expects(:info).with(dummy_project).returns(Subversion::Info.new(10, 10))
-
svn.expects(:execute).with(["svn", "--non-interactive", "log", "--revision", "HEAD:10", "--verbose", "--xml",
-
"--username", "jer", "--password", "crap"],
-
{:stderr => './svn.err'}).yields(StringIO.new(LOG_ENTRY))
-
-
svn.latest_revision(dummy_project)
-
end
-
-
app/models/subversion.rb
-
-
def checkout(target_directory, revision = nil, stdout = $stdout)
-
@url or raise 'URL not specified'
-
-
options = [@url, target_directory]
-
options <<"--revision" <<revision_number(revision) if revision
-
-
# need to read from command output, because otherwise tests break
-
execute(svn('co', options)) do |io|
-
begin
-
while line = io.gets
-
stdout.puts line
-
end
-
rescue EOFError
-
end
-
end
-
end
-
-
def svn(operation, *options)
-
command = ["svn"]
-
command <<"--non-interactive" unless @interactive
-
command <<operation
-
command += options.compact.flatten
-
command += ['--username', @username, '--password', @password] if @username and @password
-
command
-
end
The username and password would then be injected into the project's Subversion instance in the cruise_config.rb file for each project.
RUBY:
-
Project.configure do |project|
-
project.source_control.username = 'douglas'
-
project.source_control.password = 'guessable'
-
end
I've submitted a ticket along with a patch for this on cruisecontrol.rb's tracker. Keep a lookout for it if you happen to encounter the same problem.
2 Comments
January 2nd, 2008 at 6:32 pm
(Ruby)
I needed to be able to save an array of POROs (plain old Ruby objects) to the database on a Rails project that I'm currently working on. That should be easy, right?
This ought to do the job, yes?:
class MyModel < ActiveRecord::Base
serialize attribute_name
end
However, this didn't quite work as advertised, the objects being returned were typed as YAML::Object instead of the actual class being serialized. Turns out that YAML is unable to find the reference to the actual class and so its falling back to using YAML::Object as the generic class type for deserialised objects. The answer to this: Rails ticket #7537.
Take a look at the YAML documentation for all the gory details.
1 Comment