RSS Feed Subscribe to RSS

Good & Cheap Rails Hosting?

Can anyone tell me where to find it?  Does it even exist?

I’ve been looking for a good Rails host recently, one that’s running Apache/Mongrel or something business class.  Apache mod_ruby was a terrible at best, FastCGI was better at handling threads and serving content, but now that we’ve got a native Ruby solution, that seems the best way to go.

But it’s so expensive (at least for a personal blog).  I’ve looked at MediaTemple, which looks like a great option, but the basic Ruby package is $20/month.  In the days of cheap hosts that seems quite a high monthly price.

Then there’s HostingRails which has a basic Ruby package starting at $3.79/month, but if you want the Mongrel package, that’ll cost you $9.79/month.  That’s obviously a better deal, but they claim to be RoR developers since 2005 and their website would suggest otherwise.  It’s not too badly designed, but I typically expect a much better look from a Rails developer.  It’s just not the kinda place that I feel like I could trust with my credit card number.

So have I missed something?  What’s the cheapest Mongrel-running host I can find out there?  Does HostMonster support Mongrel?  I know Bluehost doesn’t.  Does anybody have experience with lunarpagesMidPhase, or An?  Please help me out in the comments below.

Rails & MemcacheD

Well, after spending a few frustrated hours on Saturday, I’ve got a working application that uses memcached. And when I use the word application, I use it very loosely. It’s basically a page that sets the current time into the session.

Now originally I followed this tutorial and installed the necessary gems in order to cache the ActiveRecord objects into memcached. I followed all instructions exactly as instructed, but starting the memcached server in verbose mode, revealed no object calls to and from the cache. If I loaded up the application console, I could access the cache directly and put things in on my own, but the functionality provided by cached_model was not working on my machine for whatever reason.

Being somewhat of a nuby anyway when it comes to Rails, I turned to an alternate solution rather than hopelessly debugging the current problem. I found another tutorial that had instructions on how to cache sessions into memcached.  I used the memcache-client client rather than the Ruby-memcache client going for the speed and the ease of setup.  It works like a charm.

Now rather than just leaving it there, I’ll tell you what I’v discovered over and above what Elliott discovered over at townx.  The ongoing development of memcache-client has apparently made some advancements to the point where it matches the application stability of Ruby-memcache when the memcache server is turned off.

At the time of the post, Elliott observed that when using memcache-client the whole application fell over when the connection to the memcache server was lost, while Ruby-memcache kept the application running with irretrievably broken sessions.  He then wrote a plug-in that monitored the memcache servers and when they came back online would begin using them again (rather than having to restart the application).  My observation as of today is that memcache-client now has both of those functionalities built in.

When the connection to the memcache server is lost, then the sessions are broken, any data stored is inaccessible, however when the memcache servers some back online, the application recognizes that and begins using the sessions again.  If the memcache server was turned off, then any data in them is gone as well, but if the memcache server itself was still running and it was just the connection lost, then the session data should still be available in the memcache servers.

As a sidenote, over at Nuby on Rails, they noted that the the memcached server available on Macs through Darwinports is broken.  I verified this; the calls I made to the cache directly from the console did indeed take 5 seconds to  push through.  However,when running it from my Ubuntu box even over the internet (Sundance to Orem) the application response was pretty snappy.  Not to shabby considering the quality of the internet in Sundance.

Cannot Map {objType} to SOAP/OM

This was a strange exception that I struggled with for several hours this evening, but I have finally prevailed.

The Background
For my Information Architecture class, we’ve got to create a web service provider and a web service requester, this provided the initial impetus for my recent push into web services and the last few posts dedicated to the topic. Now our professor has published a web service that basically dumps his database out into an array of complex data types.

His database is a weather reporting database that has zip code, temperature, humidity, etc. The databse is small (currently 3 entries) and populated with completely fabricated data, this is a learning experience not an accurate forecaster.

Our task is to subscribe to his web service, and publish our own that will accept a string parameter as the zip code and return the single weather report for just that zip code. I decided that I’d just subscribe to his web service in my controller, find the appropriate weather report, create my own Struct for my web service, and push it out to my subscribers.

The Problem
Once I had received my professor’s SOAP object back, I stepped into it to retrieve the zip codes from each entry. When I found the matching zip code, I mapped his keys and values to my own with a line of code like this:

return WeatherReport.new(:cityzip => row.cityzip, :temperature => row.temperature, :etc => ad naseum)

There are ten different attributes that my object must return to my subscribers, so it was slightly tedious to put all these things together. I prevailed.

When subscribing to my own web service via WSDL, however, I received the following exception:

Exception: Cannot map WeatherReport to SOAP/OM

WeatherReport is the name of the Struct that I was using as my return type. I began meticulously checking all my code. I had already written code to subscribe directly to my professor’s web service, so I checked the SOAP object coming back from that. I used a copy of the same code to subscribe in my own web service and could not figure out what was going on (hours pass).

I finally ran across this email archive that had a fix, but not an answer.

The Fix
I had to change my code to this:

return WeatherReport.new(:cityzip => "#{row.cityzip}", :temperature => "#{row.temperature}", :etc => "#{ad naseum}")

The “#{row.cityzip}” means that the object inside the {} should be interpreted as a variable and it’s value should appear in the string instead of the variable name. It’s just a shorthand way of concatenating strings with the values stored in string variables (and in case you were wondering, yes, you must use double quotes or it won’t work).

Now the most interesting thing about this error is that row.cityzip == "#{row.cityzip}", meaning that the expression evalutates to true. For all intents and purposes, these two strings are exactly the same.

Peter (the guy with the fix) speculates on what might be the cause, but he was also using the a Struct (via SOAP4R), so I assume that the problem’s source may lie in that class. Given the dearth of readily available information on the topic, I hope you find this useful.

WSDL, Rails, & Complex Data Types

This could also be considered part three of my HowTo: Put WSDL on Rails series, but it’s not really a HowTo in the strictest sense of the word. Therefore, this article is more of a monologue than a set of instructions.

If you’ve stuck with me this far you’ve probably figured out that I’m discovering things on my own shortly before I spew them all out here. In Howto: Put WSDL on Rails we built a simple web service that would accept a string parameter, modify it, and send the modified version back to the user. In Part 2, we subscribed to (and used) that same web service using only the WSDL. At the time I thought I was done, but as I’ve played around a bit more, I realized that there was another major part of web services. So now we’ll cover dealing with complex data types.

I began by wondering what kinds of things besides [:string] you could pass as parameters to and from a web service. I finally happened upon the Ruby on Rails manual that somehow I had not discovered up to this point. Why don’t these pages come up higher in the Google search results? Rails uses ActionWebService to interact with web services of all kinds and you can find the beginning of the manual here. You can find the specific answers to my questions here and here.

After reading this and mulling it over a bit, everything was pretty clear except for the so-called Structured Type parameters. I set out to gain a better understanding of this, and this is what I accomplished. First off, you’ll want to read up an something called a Struct. In essence an ActionWebService::Struct is a special kind of object that can be used for web services, but doesn’t have any ties to a database like an ActiveRecord::Base object.

I first defined a new struct in app/models/weather_report.rb of my WebServiceProvider.

class WeatherReport < ActionWebService::Struct
member :zip, :int
member :temp, :int
member :wind_speed, :int
member :wind_direction, :string
end

I then created the proper method in my API at app/apis/weather_api.rb:

api_method :get_weather, :expects => [:string], :returns => [WeatherReport]

And since I was really just curious to see how this works, I defined a very dynamic method in app/controllers/weather_controller.rb:

def get_weather(zip_code)
return WeatherReport.new(:zip => 84097, :temp => 55, :wind_speed => 5, :wind_direction => 'SW')
end

And that’s really all there is to it. If you’ve got a database driven application you could simply pass in one of the models that corresponds to a table on your database. So instead of an ActionWebService::Struct you could just pass in an ActiveRecord::Base object with the exact same syntax.

Now to see what comes out on the other end. In another application, I subscribed to my web service and in my view put <%= debug @result %> with @result being the result of my GetWeather call to the web service.

The debugged results came out like this.

#<soap::mapping::object:0x14868c6 {}zip="84097" {}wind_direction="SW" {}wind_speed="5" {}temp="55">

Carrying this logical line one step further, if a web service required a complex data type as input, we could build an ActionWebService::Struct object or use an appropriate ActiveRecord::Base object to pass into a third party web service. I see the struct option being much more useful ona day to day basis, but in a B2B environment, you can start to see a place for some real hard-core service interactions passing full-blown database-drive object types around between systems.

As I began to play around with web services, I thought they were pretty neat, but I’m beginning to see the how powerful they could be given the right set of circumstances.

Howto: Put WSDL on Rails [Part 2]

In the first article about WSDL on Rails we created our own web service that accepted a string, modified it, and returned a new string. Now we’ll take a look at creating another application that can consume or subscribe to our web service. This is almost too easy. I figure the best way to demonstrate the simplicity is to keep this article as short as possible.

1. Fire up the old WebServiceProvider application that we created in Part 1

From the application root directory type ./script/server

2. Create a new WebServiceConsumer application

In a new terminal window type rails WebServiceConsumer

3. Create a controller for your service consumer

cd WebServiceConsumer
./script/generate controller consumer

4. Subscribe to your WebServiceProvider using its WSDL

Open up your consumer_controller.rb in app/controllers. It will be empty and it needs to look like this:

class ConsumerController < ApplicationController

require 'soap/wsdlDriver'

def subscribe
if params[:terms] == nil
@service_output = ""
else
url = "http://localhost:3000/subscription/service.wsdl"
factory = SOAP::WSDLDriverFactory.new(url)
service = factory.create_rpc_driver
@service_output = service.Subscribe(params[:terms])
end
end
end

This is where the magic happens. The line require 'soap/wsdlDriver' brings in the needed Ruby library. The subscribe method is simply an action like any other in your application. We’re going to create a form that accepts some user input and then we’ll pass them on to our WebServiceProvider. The url, factory, and service lines could all be done in one line, but I’ve broken them out here to demonstrate.

If the box is left blank, we don’t do anything. If the user inputs some data, then we have a little bit of work to do. We create a new service object based on the WebServiceProvider’s description of itself as defined by its WSDL. Then our local service object acts as a proxy and any method calls we make on the local object are simply passed on to it the actual WebServiceProvider.

We can then define our @service_output as a variable we can then call in our view. Now for testing.

5. Create two views for testing

In app/views/consumer create an index.rhtml file as follows:

<html>
<head>
<title>WebServiceConsumer</title>
</head>
<body>
<h1>WebServiceConsumer</h1>
<p>
Enter your terms below. They will be passed on to our web service and you'll be able to see the response.
</p>

<%= start_form_tag :action=> 'subscribe' %>
<p><label>Terms</label><br/>
<%= text_field 'terms', '' %></p>
<%= submit_tag "Subscribe" %>
<%= end_form_tag %>
</body>
</html>

Also in app/views/consumer create subscribe.rhtml as follows:

<html>
<head>
<title>WebServiceConsumer</title>
</head>
<body>
<h1>WebServiceConsumer</h1>
<p>
The web service returned: <br /><br />
<%= @service_output %>
</p>
</body>
</html>

6. Now fire up your WebServiceConsumer app on a different port

Depending on your particular setup this may be different. I use lighttpd, so you’ll need to open app/config/lighttpd.conf and change the server.port = 3000 to say something like server.port = 3100. Then you can run ./script/server to fire up your app on port 3100.

Now point your browser to http://localhost:3100/consumer

Enter your terms into the text box, click Subscribe, and pat yourself on the back. You’ve just subscribed to a web service.