<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6973124</id><updated>2025-11-30T19:47:38.346-08:00</updated><category term="rails cache-money sinatra"/><title type='text'>Java The Hutt</title><subtitle type='html'>Et tu Ruby?</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default?alt=atom&amp;redirect=false'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default?alt=atom&amp;start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>62</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6973124.post-1727221356590824141</id><published>2009-12-03T16:11:00.001-08:00</published><updated>2009-12-03T16:20:11.005-08:00</updated><title type='text'>Rails realities part 29 - Salesforce and rails integration, the easy way</title><content type='html'>In honor of Dreamforce and RubyConf both being in San Francisco at the same time a couple of weeks ago today&#39;s post is about making the two of them work together. &lt;br /&gt;If you do ever need to integrate Salesforce.com with your rails app there&#39;s really one game in town, (well really two but one depends on the other, you&#39;ll see shortly) and while it works great once you get things working I think the documentation around the process could use a little help so today we&#39;re going to have a little tutorial and go through the process of integrating Salesforce into an existing rails application.&lt;br /&gt;&lt;br/&gt;So first off the assumptions:&lt;ol&gt;&lt;br /&gt;&lt;li&gt; You have a rails 2.3.x app (I&#39;m sure this works with older 2.x versions but for my app I&#39;m running 2.3.4 to be exact)&lt;/li&gt;&lt;br /&gt;&lt;li&gt; You&#39;d like to integrate with Salesforce but the entirety of your app is not driven by Salesforce.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;What are your options? Well there are currently two projects that seem to be the default and have the most momentum for connecting to SF:&lt;br /&gt;&lt;ol&gt;&lt;li&gt; &lt;a href=&quot;http://rforce.rubyforge.org/&quot;&gt;rForce&lt;/a&gt; - A simple &#39;low level&quot; API access library to get at your SF data. &lt;/li&gt;&lt;br /&gt;&lt;li&gt; &lt;a href=&quot;http://activesfdc.rubyforge.org/&quot;&gt;ActiveSalesforce&lt;/a&gt; - An ActiveRecord extension that allows you to interact with your SF data using model objects. It uses rForce to make the API calls.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;rForce is really simple to use and makes the assumption that you are familiar with the SF API. There&#39;s a great tutorial here on how to get that up and running:&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://oldfartdeveloper.blogspot.com/2009/09/rforcesalesforce-setup-for-dummies.html&quot;&gt;http://oldfartdeveloper.blogspot.com/2009/09/rforcesalesforce-setup-for-dummies.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That&#39;s the article that got me &quot;unstuck&quot; trying to figure out my way through the world of Salesforce integration. If you&#39;d like to get up and running with rForce have a look at that tutorial. If you&#39;re interested in ActiveSalesforce read on....&lt;br /&gt;&lt;br /&gt;So if you didn&#39;t read old fart&#39;s tutorial above and create a SF developer account then you&#39;re gonna wanna do that before we get started. The short of it is:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt; Go to &lt;a href=&quot;http://developer.force.com/&quot;&gt;http://developer.force.com/&lt;/a&gt; and sign up&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt; You will receive an email with your username (Your email address is your username) and a temporary password.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt; Either click on the embedded link in the email to login or visit &lt;a href=&quot;https://login.salesforce.com/&quot;&gt;https://login.salesforce.com/&lt;/a&gt; and login from there with your email and password. (Once logged in you&#39;ll want to change your password to something more memorable than the random string that was generated for you)&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt; Once you&#39;ve logged in you&#39;re taken to the home page of your personal CRM sandbox. At the top of the page you&#39;ll want to click on the &quot;Setup&quot; link.&lt;br /&gt;&lt;br /&gt;&lt;img src=&#39;http://grab.by/wer&#39; height=400/&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt; Now we have to obtain your security token that&#39;s used to login to the API. To do that click on the &quot;Setup&quot; link at the top of the page.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt; Once on your setup page you should see a section on the left side navigation titled &quot;Personal Setup&quot;. In that section there&#39;s a node named &quot;My Personal Information&quot;. Expand that node. You should see something like this:&lt;br /&gt;&lt;br /&gt;&lt;img src=&#39;http://grab.by/weO&#39;/&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Click on the &quot;Reset Security Token&quot; button to have Salesforce send you an email with your security token.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;Once that&#39;s completed we&#39;re ready to dig into some ruby and get our application talking with the API.&lt;br /&gt;&lt;br /&gt;Let&#39;s get started!&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt; First let&#39;s add a configuration entry in environment.rb in our rails app for the activesalesforce gem. I&#39;m using the johnreilly version on github.&lt;br /&gt;&lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;    config.gem &quot;johnreilly-activerecord-activesalesforce-adapter&quot;, &lt;br /&gt;             :lib =&gt; &#39;activerecord-activesalesforce-adapter&#39;, :source =&gt; &#39;http://gems.github.com&#39;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Once you have that entry in your environment.rb file you can install the gem by running the following rake command from the root of your application&lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;sudo rake gems:install&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;OK so let&#39;s create our first SF related model, a base class that will be used for all SF model classes. So we generate:&lt;br /&gt;&lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;ruby script/generate model Salesforce::SfBase&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;After that is generated we add some code to connect to SF and end up with something like the following:&lt;br /&gt;&lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;class Salesforce::SfBase &lt; ActiveRecord::Base  &lt;br /&gt;  self.abstract_class = true&lt;br /&gt;  # create a connection to Salesforce for the given user&lt;br /&gt;  def self.login(user, pass, token)&lt;br /&gt;    params = {:adapter  =&gt; &quot;activesalesforce&quot;,&lt;br /&gt;                              :url     =&gt; &quot;https://login.salesforce.com/services/Soap/u/16.0&quot;,&lt;br /&gt;                              :username =&gt; user,&lt;br /&gt;                              :password =&gt; pass + token}&lt;br /&gt;    self.establish_connection(params)    &lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Next let&#39;s generate an SF class that represents a user.&lt;br /&gt;&lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;ruby script/generate model Salesforce::User&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Modify that newly created user class to look as follows:&lt;br /&gt;&lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;class Salesforce::User &lt; Salesforce::SfBase&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Now we&#39;re ready to test our connection to SF and retrieve a user in their system via the API. Let&#39;s create a test in the Salesforce::UserTest as follows:&lt;br /&gt;&lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;class Salesforce::UserTest &lt; ActiveSupport::TestCase&lt;br /&gt;  def test_should_return_sf_user&lt;br /&gt;    user = &#39;yourSFemail@yourdomain.com&#39;&lt;br /&gt;    password = &#39;yourSFpassword&#39;&lt;br /&gt;    key = &#39;your SF security token&#39;&lt;br /&gt;    Salesforce::SfBase.login(user, password, key)&lt;br /&gt;    u = Salesforce::User.first&lt;br /&gt;    assert_not_nil u&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;If all went well you should see a successful test run and have a user from the SF system. The code simply logs into SF via the login method defined in our base class. This sets the connection for any ActiveRecord classes that derive from SfBase for the rest of the request. Then we simply use our SF User class the same way we would any ordinary ActiveRecord class.&lt;br /&gt;As a side not you&#39;ll probably want to store the SF credential information in a config file somewhere or if your SF support is on a per user basis somewhere in your users or accounts table.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Extra credit: You can also use related objects in the standard ActiveRecord way as well. For example we could change our User class as follows:&lt;br /&gt;&lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;class Salesforce::User &lt; Salesforce::SfBase&lt;br /&gt;  has_many :contacts, :class_name =&gt; &quot;Salesforce::Contact&quot;, :foreign_key =&gt; &#39;owner_id&#39;&lt;br /&gt;  has_many :cases, :class_name =&gt; &#39;Salesforce::Case&#39;, :foreign_key =&gt; &#39;owner_id&#39;&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Having these relations defined allows us to use relations in the normal rails way:&lt;br /&gt;&lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;user = Salesforce::User.first&lt;br /&gt;user.contacts&lt;br /&gt;user.cases&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Of course we&#39;ll need to generate a Salesforce::Contact and Salesforce::Case class but you get the idea. ActiveSalesforce will automatically match up any of the built in classes with your properly namespaced salesforce class. The key is that your classes do need to be namespaced at &quot;Salesforce::&quot; as far as I know. Perhaps you can override that behavior but I found it to be exactly what I&#39;d want to do myself. &lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;That should do it. Easy integration of Salesforce as another data source into your existing rails app. I should point out that this is not production tested code so it should be pointed out that things like ensuring the connection to Salesforce isn&#39;t causing any leaks should be investigated before deploying to production.&lt;br /&gt;&lt;br /&gt;Enjoy!</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/1727221356590824141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2009/12/rails-realities-part-29-salesforce-and.html#comment-form' title='19 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/1727221356590824141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/1727221356590824141'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2009/12/rails-realities-part-29-salesforce-and.html' title='Rails realities part 29 - Salesforce and rails integration, the easy way'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>19</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-8425003676428164059</id><published>2009-11-10T17:41:00.000-08:00</published><updated>2009-11-10T17:42:33.656-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="rails cache-money sinatra"/><title type='text'>Rails realities part 28 - Sinatra holdin&#39; up the cache-money</title><content type='html'>For those of you looking to integrate the cache-money write through caching within your rails app and you&#39;re using Sinatra to create some metals beware.&lt;br /&gt;&lt;br /&gt;It all started with this command on the rails console:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&gt;&gt; a = User.find(1)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Which resulted in this error message:&lt;br /&gt; &lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;NoMethodError: You have a nil object when you didn&#39;t expect it!&lt;br /&gt;The error occurred while evaluating nil.key?&lt;br /&gt; from /Library/Ruby/Gems/1.8/gems/sinatra-0.9.4/lib/sinatra/base.rb:768:in &#39;route&#39;&lt;br /&gt; from /Library/Ruby/Gems/1.8/gems/sinatra-0.9.4/lib/sinatra/base.rb:754:in &#39;get&#39;&lt;br /&gt; from (__DELEGATE__):2:in &#39;send&#39;&lt;br /&gt; from (__DELEGATE__):2:in &#39;get&#39;&lt;br /&gt; from /Library/Ruby/Gems/1.8/gems/nkallen-cache-money-0.2.5/lib/cash/transactional.rb:27:in &#39;send&#39;&lt;br /&gt; from /Library/Ruby/Gems/1.8/gems/nkallen-cache-money-0.2.5/lib/cash/transactional.rb:27:in &#39;method_missing&#39;&lt;br /&gt; from /Library/Ruby/Gems/1.8/gems/nkallen-cache-money-0.2.5/lib/cash/accessor.rb:22:in &#39;fetch&#39;&lt;br /&gt; from /Library/Ruby/Gems/1.8/gems/nkallen-cache-money-0.2.5/lib/cash/accessor.rb:31:in &#39;get&#39;&lt;br /&gt; from /Library/Ruby/Gems/1.8/gems/nkallen-cache-money-0.2.5/lib/cash/query/abstract.rb:65:in &#39;hit_or_miss&#39;&lt;br /&gt; from /Library/Ruby/Gems/1.8/gems/nkallen-cache-money-0.2.5/lib/cash/query/abstract.rb:18:in &#39;perform&#39;&lt;br /&gt; from /Library/Ruby/Gems/1.8/gems/nkallen-cache-money-0.2.5/lib/cash/query/abstract.rb:7:in &#39;perform&#39;&lt;br /&gt; from /Library/Ruby/Gems/1.8/gems/nkallen-cache-money-0.2.5/lib/cash/finders.rb:24:in &#39;find_every&#39;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Huh? Uhh, OK... WTF is the code doing in Sinatra? After some investigation I came across this very similar problem from someone using the ruby redis client &lt;a href=&quot;https://sinatra.lighthouseapp.com/projects/9779/tickets/251-sinatra-collision-with-redis-client&quot;&gt;https://sinatra.lighthouseapp.com/projects/9779/tickets/251-sinatra-collision-with-redis-client&lt;/a&gt;. Since that stack trace looked familiar I looked a little more closely. Turns out this bit of documentation is the key:&lt;br/&gt;&lt;br/&gt;&lt;br /&gt;&quot;The methods available to Sinatra::Base subclasses are exactly as those available via the top-level DSL. Most top-level apps can be converted to Sinatra::Base components with two modifications:&lt;br /&gt;&lt;br /&gt; * Your file should require sinatra/base  instead of sinatra;&lt;br /&gt;   otherwise, all of Sinatra&#39;s DSL methods are imported into the main namespace.&quot;&lt;br /&gt;&lt;br /&gt;Read more here:&lt;br /&gt;&lt;a href=&quot;http://github.com/sinatra/sinatra/commit/536033334f33c6822acb64e18b6cdb4eee2f85fe#L0R515&quot;&gt;http://github.com/sinatra/sinatra/commit/536033334f33c6822acb64e18b6cdb4eee2f85fe#L0R515&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Turns out the rails app I was working on which has some metals had included sinatra instead of sinatra/base. Simply changing that require fixed the problem with cache-money. Hopefully this saves someone else that same headache that cost me more time than it should&#39;ve.</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/8425003676428164059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2009/11/rails-realities-part-28-sinatra-holdin.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/8425003676428164059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/8425003676428164059'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2009/11/rails-realities-part-28-sinatra-holdin.html' title='Rails realities part 28 - Sinatra holdin&#39; up the cache-money'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-1871619463906796237</id><published>2009-10-30T17:32:00.001-07:00</published><updated>2009-10-30T17:32:32.380-07:00</updated><title type='text'>Tivo your code</title><content type='html'>Lately I&#39;ve been working on a project with some other developers and we were having discussions about development methodology choices and the role of testing in software development. I know that this topic has been covered to death but I personally always find it fun and rewarding to come up with new analogies for thinking about software, or anything for that matter, that helps educate and clarify the meaning or impact of a given concept, behavior, or pattern. &lt;br /&gt;&lt;br /&gt;So while I&#39;m not going to step back to the question of &quot;What is meaning of life?&quot;, I am going to pose a high level question of &quot;What is the process of writing software?&quot; What is it you are actually doing when you&#39;re typing away in that text editor? &lt;br /&gt;&lt;br /&gt;You&#39;re telling a story. A story of a software&#39;s journey. You&#39;re giving that story a plot line and characters and ideally it&#39;s going to go somewhere interesting. Not all software does, and there&#39;s a lot of reruns out there. Now you might be creating a really simple children&#39;s story like &quot;The Little Iterator That Could&quot; or something more involved like &quot;The Passion of the Load Balancer: Timeouts Edition&quot; &lt;br /&gt;&lt;br /&gt;Whatever you&#39;re writing, every time you do so you&#39;re creating or building on an existing story. Your first &quot;audience&quot; for that story is your computer. Now computers are really patient but at the same time pretty intolerant listeners. They will sit there and listen to your story, no matter how good or bad, whenever you want. Like your mom they have an unending supply of patience and can endure the most boring of stories because, well, they have to. On the other hand just like many moms they&#39;re very active listeners and will critique your story until they understand every last detail, and it can get annoying because sometimes you just wish they&#39;d implicitly know what you&#39;re trying to tell in your story. You can find yourself saying things like: &quot;No, no, no... it doesn&#39;t go to &#39;find_the_dud&#39;, come on you know I meant &#39;find_the_dude&#39;&quot; So yeah it can be a bit annoying, but they really help keep your story straight for when you&#39;re ready to move on to the big time.&lt;br /&gt;&lt;br /&gt;Speaking of the big time... it looks like your story was just optioned for a spot in the latest upcoming code repository! Oh joy! You can&#39;t wait to share your entire story with the world. You can&#39;t wait for the first episode to air with your new audience members, people. Your mom, err computer, loved the story and was able to understand it, surely your code is destined to be the next &quot;Seinfeld&quot; of the software world.&lt;br /&gt;&lt;br /&gt;So it&#39;s opening night, your new episode is about to air, but then something strange happens. You continue telling your story and your audience is confused. They&#39;re not following your plot. They don&#39;t understand who the characters are, the roles they play, and generally what&#39;s going on and where things are going. Hmm... this is a problem. How is anyone going to love and adore your story if they aren&#39;t able to follow what&#39;s going on? And yeah, they&#39;re all coming into your story after it&#39;s begun. It might be episode #3 in your series of stories, or perhaps this is your Treehouse of Terror XX, the 20th installment in an entire series of stories.&lt;br /&gt;&lt;br /&gt;So how the heck are you going to get your audience up to speed on your plot and characters so that they can follow your amazing story from here on out? And how are you going to ensure that they can always keep up to date on your series if they can&#39;t be there to watch/listen as you&#39;re creating this poetic genius?&lt;br /&gt;&lt;br /&gt;You do what we all do when there&#39;s something we want to watch/follow but don&#39;t have time to do so &quot;live&quot;, you Tivo it. Ahh yes Tivo. No longer do we don&#39;t have to have the show&#39;s writers sitting next to us on our couch, or more commonly, a friend explaining to us what happened on last week&#39;s episode of &quot;As the Kernel Dumps&quot;. We can go get caught up at our leisure by simply watching the old episode on our trusty Tivo, and we&#39;ll be up to date with the latest plot when a new episode airs. Heck, we could even stand in for the writers and create our own next episodes of the show if we wanted to or had to in the event of a strike.&lt;br /&gt;&lt;br /&gt;Fast forward a bit and now based on your smashing success of your last project you&#39;ve just landed a role as a writer for a hot new Abobe Flex sitcom involving some charts, data, and other things that are sure to be instant hilarity, I mean what&#39;s not funny about charts and data? Hmm, but you still have to crank out new episodes of your other ongoing series. Guess you&#39;ll have to find some other writers to bring onboard to help with that. Hmm, luckily you&#39;ve been Tivoing all your episodes so that this new writer can go back and watch all the old episodes to get up to speed and be able to create meaningful new stories that add to the existing plotline in a meaningful way. Oh and Tivoing these stories allows them to serve as a &quot;sanity check&quot; or &quot;regression check&quot; for any new plot lines this new writer comes up with. It&#39;s easy to go back and see if what they&#39;re coming up with fits within the historical boundaries of the series and if not fix the story accordingly.&lt;br /&gt;&lt;br /&gt;Unfortunately not everyone out there has seen the light with regards to Tivoing their code. Throngs of software stories are out there being spoken into the ether with nary a chance at them truly being understood. Unless you were there from the firing of the opening brace or shortly thereafter you&#39;re not likely to understand what the heck is going on without some help from someone else that&#39;s been listening to the story or by talking to the authors themselves. The problem is that talking to the authors or even others in attendance doesn&#39;t really scale so well and it&#39;s kind of annoying to have to do for all parties. You as the story creator become the bottleneck. Imagine if every author out there had to tell their novels in person. We wouldn&#39;t be much further along than Shakespeare right now.&lt;br /&gt;&lt;br /&gt;Of course if you haven&#39;t figured it out by now I&#39;m talking of course about writing tests for your code and some of the advantages of doing so and the drawbacks of not. Without them you&#39;re delivering half a script as to what story the software is trying to tell. Tivoing your code is always a great idea, even if you&#39;re the only one that&#39;s ever going to be &quot;listening&quot; to these software stories. I promise you that in 6 months from now you&#39;ll come back to your series and you&#39;ll be plenty grateful that you have those old episodes Tivo&#39;d to help you advance that storyline.&lt;br /&gt;&lt;br /&gt;The world is waiting to hear your great stories! Now if you&#39;ll excuse me I have to go see &quot;what&#39;s playing&quot; in my git repository! &lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/1871619463906796237/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2009/10/tivo-your-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/1871619463906796237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/1871619463906796237'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2009/10/tivo-your-code.html' title='Tivo your code'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-446998148742725523</id><published>2009-06-30T19:08:00.001-07:00</published><updated>2009-07-02T08:27:43.070-07:00</updated><title type='text'>Mo simple sortable tables in rails</title><content type='html'>&lt;p&gt;&lt;br /&gt;     A long time ago I wrote a &lt;a href=&quot;http://javathehutt.blogspot.com/2006/11/rails-realities-part-20-sortable.html&quot;&gt;blog posting&lt;/a&gt; on a plugin I created that would allow you to create a sortable table for your rails models with minimal work. Well, 2.5 years later I&#39;m taking the time to write yet another blog post on a revamped version of that plugin that does more with less and is about 10x easier to set up and use. If you refer back to my old posting you&#39;ll see that I set out to create a plugin that would allow you to create a non-ajax sortable and paginated table. It certainly worked but involved too much configuration and understanding by you the developer in order to use it. The goal here is the same and the motivation is largely to make it braindead easy to get a table up and running without having to know much of anything. I use this plugin in my apps in user facing pages as well as the starting point for all of my admin pages, completely replacing the ever fragile &lt;a href=&quot;http://activescaffold.com/&quot;&gt;ActiveScaffold&lt;/a&gt;. (Sorry you guys, it totally rocks when it works but it just kept breaking too much for me and I didn&#39;t need all the bells and whistles) Over the past couple of years I&#39;ve completely revamped how this plugin works so let&#39;s a have a look at &quot;sortable reloaded&quot; OK let&#39;s get started:&lt;br /&gt;   &lt;/p&gt;&lt;br /&gt;   &lt;ol&gt;&lt;br /&gt;     &lt;li&gt;First You either create or use an existing a rails app (2.2.2 is the version I&#39;m using still, not positive but this should work with 2.3.x or any rails 2.x apps without a problem).&lt;br /&gt;     &lt;/li&gt;&lt;br /&gt;     &lt;li&gt;Next we need to install the will_paginate gem. Assuming you&#39;re familiar with specifying gems for your app in your environment.rb file here&#39;s my entry for will_paginate:&lt;br /&gt;       &lt;blockquote&gt;&lt;pre  class=&quot;brush:ruby&quot;&gt;  config.gem &#39;mislav-will_paginate&#39;,&lt;br /&gt;            :lib =&amp;gt; &#39;will_paginate&#39;,&lt;br /&gt;            :source =&amp;gt; &#39;http://gems.github.com&#39;,&lt;br /&gt;            :version =&amp;gt; &#39;~&amp;gt; 2.3.6&#39;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;br /&gt;     &lt;li&gt;Now that we&#39;ve got the pagination gem in place it&#39;s time to install the plugin itself. We can do that with:&lt;br /&gt;       &lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;ruby script/plugin install git://github.com/kovacs/sortable.git&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;br /&gt;     &lt;li&gt;Next up I&#39;m going to assume that you have a model for whose objects you&#39;d like to create a paginated, sortable table. You&#39;re going to need a model as well as a controller with an entry in your routes.rb file. For example:&lt;br /&gt;in user.rb&lt;br /&gt;       &lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;&lt;br /&gt;class User &amp;lt; ActiveRecord::Base&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;in users_controller.rb&lt;br /&gt;&lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;&lt;br /&gt;class UsersController &amp;lt; ApplicationController &lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;in routes.rb&lt;br /&gt;&lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;&lt;br /&gt;map.resources :users&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;br /&gt;     &lt;li&gt;Assuming you have that set up configured the simplest possible way to use sortable to create a sortable, paginated, searchable table of your objects is like this:&lt;br /&gt;       &lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;&lt;br /&gt;class UsersController &amp;lt; ApplicationController&lt;br /&gt; sortable_table User&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;After you add that snippet to your controller go and hit: http://localhost:3000/users and watch the magic happen. Pretty cool for a one line declaration. The magic happening behind the scenes is that the declaration &quot;sortable_table User&quot; is generating an &#39;index&#39; action in your UsersController and is using a default index.erb template file for the view of that action. Here&#39;s a look at that code: In sortable.rb (vendor/plugins/sortable/lib/sortable.rb)&lt;br /&gt;       &lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;&lt;br /&gt;def index&lt;br /&gt; get_sorted_objects(params) &lt;br /&gt; render :template =&amp;gt; &#39;sortable/index&#39;&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;in the view for index (vendor/plugins/sortable/views/sortable/index.erb)&lt;br /&gt;       &lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;&lt;br /&gt;&amp;lt;%= sortable_table %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;Everything is customizable but this is just demonstrating the simplest table you can create with the plugin.&lt;br /&gt;     &lt;/li&gt;&lt;br /&gt;     &lt;li&gt;By default you&#39;ll notice that the plugin uses all the attributes on your model when it builds the table. I can hear it already: &quot;Dude, I don&#39;t want it to show XYZ attribute on my model&quot; to which I&#39;d say &quot;Pfft... way ahead of you dawg&quot;. Specify what columns you want displayed in the table by default like this:&lt;br /&gt;       &lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;&lt;br /&gt;class UsersController &amp;lt; ApplicationController&lt;br /&gt; sortable_table User, :display_columns =&amp;gt; [&#39;id&#39;, &#39;name&#39;, &#39;email&#39;, &#39;created_at&#39;, &#39;timezone&#39;, &#39;state&#39;] &lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Of course this example assumes that you have the attributes on your User model. Replace with your attributes as needed. What you&#39;ll end up seeing is this: &lt;img src=&quot;http://img.skitch.com/20090701-8bsjqeu9xqrh1fip73dcsi5erk.jpg&quot; /&gt;&lt;br /&gt;&lt;br /&gt;     &lt;/li&gt;&lt;br /&gt;     &lt;li&gt;Of course there&#39;s a ton of flexibility in the plugin that allows you to place a sortable table on any page you&#39;d like as opposed to having it only show up on an index page that lists all your objects. You can also show a table that sorts, searches, and paginates over more than one object type. So if you wanted to show all your users and one or more attributes from a related object or objects you can easily do that with a few attributes in your sortable_table declaration. You can also easily customize the L&amp;amp;F of the table and turn off searching if you don&#39;t want/need it. See more details in sortable.rb and sortable_helper.rb where it outlines all of the options. If there&#39;s something that it doesn&#39;t do feel free to fork the code and add it yourself and send me a pull request.&lt;br /&gt;     &lt;/li&gt;&lt;br /&gt;     &lt;li&gt;The basic mechanics on how to make use of the plugin in your app is that you want to call:&lt;br /&gt;       &lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;&lt;br /&gt;get_sorted_objects(params, sortable_options)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;This call will populate a few variables for you to use:&lt;br /&gt;       &lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;&lt;br /&gt;@objects  # The collection of objects that you can display in a table&lt;br /&gt;@headings  # The collection of table header objects that are used to build the header and links.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;Then in your view you&#39;ll just call:&lt;br /&gt;       &lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;&lt;br /&gt;&amp;lt;%= sortable_table %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;Wherever you&#39;d like that sortable table to appear. It&#39;s really that simple. You can easily override the template that&#39;s being used to build the table with a parameter to the helper call. For example:&lt;br /&gt;       &lt;blockquote&gt;&lt;pre class=&quot;brush:ruby&quot;&gt;&lt;br /&gt;&amp;lt;%= sortable_table :partial =&amp;gt; &#39;loans/loan_table&#39; %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;Have a look at vendor/plugins/sortable/views/sortable/_table.html.erb for an idea of how to build a table for your objects if you want to have more flexibility than the standard template gives you.&lt;br /&gt;     &lt;/li&gt;&lt;br /&gt;   &lt;/ol&gt;&lt;br /&gt;   &lt;p&gt;&lt;br /&gt;     If you find this plugin useful and especially if you use it on a site that&#39;s a project that you&#39;re intending to make money with please donate something as it did require time and effort to clean up, document, and package this plugin for general consumption. Your donation will go towards improving this plugin and inspire me to release other plugins that I know would be generally useful to other rails developers. You might want to note that unlike most open sores projects this plugin comes with example code, documented code, tests, and has 100% test coverage as well. It&#39;s also being used in production on a real site that charges real money for its products so it&#39;s not just someone&#39;s hobby project that&#39;s going to be abandoned. Think about that while you&#39;re busting out your credit card and making a suggested donation of $20 (or whatever you&#39;d like) here:&lt;br /&gt;   &lt;/p&gt;&lt;br /&gt;   &lt;center&gt;&lt;br /&gt;     &lt;form action=&quot;https://www.paypal.com/cgi-bin/webscr&quot; method=&quot;post&quot;&gt;&lt;br /&gt;       &lt;input type=&quot;hidden&quot; name=&quot;cmd&quot; value=&quot;_s-xclick&quot;&gt; &lt;input type=&quot;hidden&quot; name=&quot;encrypted&quot; value=&quot;-----BEGIN PKCS7-----MIIHNwYJKoZIhvcNAQcEoIIHKDCCByQCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYBp1/UtvW07FsS6DtXAm7Wu8ai5Jhy7ejbRMmrfghLVocjfFtQVdaoiAV43Z6zaihkAaBzaSFgommCeU1Bscoh4YbMIe8lV4F2DiuG5RsmZNwNOzAlYL0zRU7PiDtOiv8Mrg39Zobsbm2457okIPbjjt6N21Ctv+yHru2DbP9DpIzELMAkGBSsOAwIaBQAwgbQGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIECR8kKIoEoKAgZDAFj81qps0xZYjmvnbLiaxgH6JP45W9W9nwWoXgrjpK8pXvVo/FuT0Gu/rStPesbS4/M3KXmgE0NjjejSDnt0w/1x/Ql9Jaugz9XJtT9Z7QrOTq0i/Lgggugn57gP1IcLHVVsu2jPh2NpPAESUPyOxckYti7vqOKICoi/NYd/HwDt0A0gaVqPxQ4LFpEMS4yugggOHMIIDgzCCAuygAwIBAgIBADANBgkqhkiG9w0BAQUFADCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20wHhcNMDQwMjEzMTAxMzE1WhcNMzUwMjEzMTAxMzE1WjCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMFHTt38RMxLXJyO2SmS+Ndl72T7oKJ4u4uw+6awntALWh03PewmIJuzbALScsTS4sZoS1fKciBGoh11gIfHzylvkdNe/hJl66/RGqrj5rFb08sAABNTzDTiqqNpJeBsYs/c2aiGozptX2RlnBktH+SUNpAajW724Nv2Wvhif6sFAgMBAAGjge4wgeswHQYDVR0OBBYEFJaffLvGbxe9WT9S1wob7BDWZJRrMIG7BgNVHSMEgbMwgbCAFJaffLvGbxe9WT9S1wob7BDWZJRroYGUpIGRMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAIFfOlaagFrl71+jq6OKidbWFSE+Q4FqROvdgIONth+8kSK//Y/4ihuE4Ymvzn5ceE3S/iBSQQMjyvb+s2TWbQYDwcp129OPIbD9epdr4tJOUNiSojw7BHwYRiPh58S1xGlFgHFXwrEBb3dgNbMUa+u4qectsMAXpVHnD9wIyfmHMYIBmjCCAZYCAQEwgZQwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tAgEAMAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0wOTA3MDEwMDE5MDNaMCMGCSqGSIb3DQEJBDEWBBQjJVsINh2sPalzMU/jL+Jq3FqdTDANBgkqhkiG9w0BAQEFAASBgKDC3/rGF5dND+Jh3OX+oOjIxBj0z6a77wtRnDyDCujXqNhHYo1c+JxWPWAkbT73J06vpbnFum6ICvFfWwnuuq9K+hDByHNr6WH7867Mkx4352HWkWIlknifwExpdGgcSBoagOGwJYbKzxFyJ9TbDKu3Y54DDdHb2jDEz0eTNHeL-----END PKCS7----- &quot;&gt; &lt;input type=&quot;image&quot; src=&quot;https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif&quot; border=&quot;0&quot; name=&quot;submit&quot; alt=&quot;PayPal - The safer, easier way to pay online!&quot;&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;https://www.paypal.com/en_US/i/scr/pixel.gif&quot; width=&quot;1&quot; height=&quot;1&quot; /&gt;&lt;br /&gt;     &lt;/form&gt;If you aren&#39;t going to donate or are using it for a non-profit project I&#39;d really appreciate a link to my company site: &lt;a href=&quot;http://www.cablecarsoftware.com/&quot;&gt;http://www.cablecarsoftware.com&lt;/a&gt;. Thanks everyone and hope you enjoy it and find it useful! Oh and finally, get the code &lt;a href=&quot;http://github.com/kovacs/sortable&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;   &lt;/center&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/446998148742725523/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2009/06/mo-simple-sortable-tables-in-rails.html#comment-form' title='43 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/446998148742725523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/446998148742725523'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2009/06/mo-simple-sortable-tables-in-rails.html' title='Mo simple sortable tables in rails'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>43</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-7142521275349843438</id><published>2009-05-19T12:45:00.001-07:00</published><updated>2009-05-19T12:45:43.974-07:00</updated><title type='text'>Production deployments from the friendly skies</title><content type='html'>This past weekend I flew to NY to attend my youngest sister&#39;s graduation from Hofstra. Once again I flew Virgin America like I always try to when I fly to NY. Power outlets at each seat mean that I can either work or play on my mac the entire time turning a 5 hour flight into nothing more than just another day at the office or a coffee shop :-) The only thing that&#39;s ever been missing of course is internet access. Well for $12.95 on Virgin you can now get high speed internet access. I forgot to test the speed but for browsing it was fine. I did notice lag when streaming a video but that&#39;s to be expected. Simply having it at all and having it usable is a huge win.&lt;br /&gt;&lt;br /&gt;So there I was working on some fixes for &lt;a href=&quot;http://www.lendingkarma.com&quot;&gt;LendingKarma&lt;/a&gt; and was ready to deploy. Then the realization that I was about to embark upon a production deployment from 30K feet hit me. What if there&#39;s a problem and the wifi goes out? I can&#39;t rollback thus leaving the site in whatever state caused by my deployment gone wrong. After posing the question to some fellow engineers via a twitter/facebook status update which of course resulted in &quot;do it man!&quot;, because they&#39;re not the ones that have to deal with the fallout of a failure :-), I pushed ahead with my deployment. Wouldn&#39;t you know it, there was a problem and I immediately rolled back. Phew! Murphy&#39;s Law strikes again! I fixed the problem quickly and then redeployed successfully. Wow... I just did a production deployment from an airplane. Pretty damn cool :-)&lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/7142521275349843438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2009/05/production-deployments-from-friendly.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/7142521275349843438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/7142521275349843438'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2009/05/production-deployments-from-friendly.html' title='Production deployments from the friendly skies'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-3829169596677381854</id><published>2009-05-04T15:31:00.001-07:00</published><updated>2009-05-04T15:41:10.492-07:00</updated><title type='text'>And.... we&amp;#39;re back</title><content type='html'>Phew! That was a long commercial break. I always said I wanted to take a year off in my 30s. I guess a year off from blogging is about the closest thing I&#39;ve come to that year off :-) Quite a bit&#39;s happened in the year since I last wrote. I helped a client launch, http://www.newrelic.com, went on a vacation to Europe (Budapest, Prague, and Berlin) and most recently launched a new venture of mine, &lt;a href=&quot;http://www.lendingkarma.com&quot;&gt;http://www.lendingkarma.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For the folks that still have me in their feed reader after nearly a year without a peep, I say thanks for being so lazy about removing me :-) Considering that the majority of folks that do read this blog are interested in ruby and rails development I do have a few things that I can talk about that might be of interest.&lt;br /&gt;&lt;br /&gt;So as you could probably guess LendingKarma is built on rails, but it&#39;s also built using a base app that is comprised of numerous plugins that make it really easy to get a base application up and running. Some of the plugins are:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://github.com/kovacs/comatose/tree/master&quot;&gt;Comatose&lt;/a&gt; - A lightweight CMS plugin for easy creation of static content. It also has an easy way to drop in dynamic content as well.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://github.com/kovacs/active_merchant/tree/master&quot;&gt;Active Merchant&lt;/a&gt; - The most commonly used plugin for adding e-commerce support to your rails applications. This version of ActiveMerchant includes a patch to support recurring payments through Paypal Web Payments Pro.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://github.com/kovacs/in_place_editing/tree/master&quot;&gt;In place editing&lt;/a&gt; - An updated in_place_editor plugin that supports RESTful routes and includes support for inplace editing of select boxes. I&#39;ll post more about how this plugin works later.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://github.com/kovacs/restful-authentication/commits/master&quot;&gt;Restful Authentication&lt;/a&gt; - At the time I started creating this application none of the new sexy plugin authentication mechanisms were ready or there yet so I stuck with Restful Auth for now. This probably deserves a second look now that there are some plugin based solutions out there.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://github.com/kovacs/suspenders/tree/master&quot;&gt;Suspenders&lt;/a&gt; - Suspenders is the base app from the guys over at &lt;a href=&quot;http://www.thoughtbot.com&quot;&gt;Thoughtbot&lt;/a&gt;. The guys who also created Factory Girl and Shoulda which I use as well in my projects now, though not in this base app&#39;s code base.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://github.com/kovacs/uberkit/tree/master&quot;&gt;Uberkit&lt;/a&gt; - A plugin to help ease the pain of creating forms and fields. I enhanced this plugin to make use of another plugin I use to make it easy to create tooltips.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://github.com/timcharper/bundle-fu/tree/master&quot;&gt;Bundle Fu&lt;/a&gt; - An asset packaging plugin whose only requirement is a closure around the assets you&#39;d like to bundle into a single .css or .js file. Really nice!&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I also have a few plugins I created that aren&#39;t on Github at the moment but are part of my base app:&lt;br /&gt;&lt;br /&gt;OrderSystem - Order system is a plugin for e-commerce that&#39;s focused on selling digital products. It makes it brain dead easy to add any of the ActiveMerchant gateways as well as making it trivial to setup and test paypal standard or web payments pro as your gateway. It even has support for subscriptions using web payments pro. Subscription support for non-Paypal web payments pro is coming but for LendingKarma we are using Paypal so that was done first. I&#39;m thinking of releasing this plugin in the same fashion as the RailsKit software. I looked at that software and wasn&#39;t happy with the product so I ended up creating my own which I think is an easier fit for integrating into an existing rails app. Anyway, more to come on that. Let me know if you&#39;d like more information on that plugin.&lt;br /&gt;&lt;br /&gt;Tooltip - A plugin that makes it easy to declaratively add tooltips to your site.&lt;br /&gt;&lt;br /&gt;Sortable - A plugin that makes it easy to create a sortable, paginated table over your objects that is also very flexible.&lt;br /&gt;&lt;br /&gt;ListEditor - List Editor allows you to declaratively create CRUD lists that use a modal dialog and ajax for the CRUD operations. &lt;br /&gt;&lt;br /&gt;More on these plugins in future posts. &lt;br /&gt;&lt;br /&gt;The end result of this work is a rails app that out of the box comes with user reg/auth, e-commerce support, and a CMS to manage the site&#39;s static pages. A great first step to many projects out there. I&#39;m also just thinking about bundling the entire app itself for release as a base starter app.&lt;br /&gt;&lt;br /&gt;Stay tuned as I plan on posting more than once this year :-)&lt;br /&gt; </content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/3829169596677381854/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2009/05/and-we-back.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/3829169596677381854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/3829169596677381854'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2009/05/and-we-back.html' title='And.... we&amp;#39;re back'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-2031148970332700701</id><published>2008-05-08T17:03:00.001-07:00</published><updated>2008-05-08T17:03:20.360-07:00</updated><title type='text'>JavaOne 2008 - Scala</title><content type='html'>Between &lt;a href=&quot;http://artists.letssingit.com/jack-johnson-lyrics-sitting-waiting-wishing-l297xdv&quot;&gt;working, waiting, wishing&lt;/a&gt; for my &lt;a href=&quot;http://youbeenblinded.com/wp-content/uploads/2007/08/wii-drinking-jumping.jpg&quot;&gt;Wii&lt;/a&gt; to arrive (yay!) I&#39;ve finally managed to make it to my first talk at &lt;a href=&quot;http://java.sun.com/javaone/sf/index.jsp&quot;&gt;JavaOne&lt;/a&gt;. Because my good friend &lt;a href=&quot;http://blog.lostlake.org/&quot;&gt;David Pollak&lt;/a&gt; has been bugging me to check out &lt;a href=&quot;http://liftweb.net/index.php/Main_Page&quot;&gt;lift&lt;/a&gt; (written in &lt;a href=&quot;http://www.scala-lang.org/&quot;&gt;Scala&lt;/a&gt;) I decided to go and check out &lt;a href=&quot;http://macros2000.com/m/hes-the-guy-behind.htm&quot;&gt;the guy behind the guy behind the guy&lt;/a&gt; (&lt;a href=&quot;http://en.wikipedia.org/wiki/Martin_Odersky&quot;&gt;Martin Odersky&lt;/a&gt;) The creator of &lt;a href=&quot;http://www.scala-lang.org/&quot;&gt;Scala&lt;/a&gt;. (Enough &lt;a href=&quot;http://www.w3.org/TR/html4/struct/links.html&quot;&gt;links&lt;/a&gt; in there for ya?)&lt;br /&gt;&lt;br /&gt;What&#39;s scala? Well it&#39;s a fully JVM compliant language that integrates functional and object-oriented language features. Boy that sounds to me like it&#39;s gonna get complicated or bloated real fast. From Martin&#39;s presentation today:&lt;br /&gt;&lt;br /&gt;Is Scala a kitchen sink language?&lt;br /&gt;Roughly comparable to java, smaller than C++/#&lt;br /&gt;&lt;br /&gt;Two design principles:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt; focus on abstraction and composition so that users can implement their own specialized features&lt;/li&gt;&lt;br /&gt;&lt;li&gt; have the same constructs work for small as well as large programs&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;Scala adds:&lt;br/&gt;&lt;br /&gt;pure object system - everything is an object unlike Java and Ruby&lt;br/&gt;&lt;br /&gt;operator overloading&lt;br/&gt;&lt;br /&gt;closures - Rubyists take note&lt;br/&gt;&lt;br /&gt;mixins - Rubyists take note&lt;br/&gt;&lt;br /&gt;existential types&lt;br/&gt;&lt;br /&gt;abstract types&lt;br/&gt;&lt;br /&gt;pattern matching&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Removes:&lt;br/&gt;&lt;br /&gt;statics - it adds its own static of sorts with a singleton object (called a companion object) where you can define methods&lt;br/&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Sample(x: Int, val p: Int) {&lt;br /&gt;  def instMeth(y: Int) = x + y&lt;br /&gt;}&lt;br /&gt;object Sample { &lt;-- companion object... contains statics&lt;br /&gt;  def staticMeth(x: Int, y: Int) = x * y&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;primitives&lt;br/&gt;&lt;br /&gt;break,continue&lt;br/&gt;&lt;br /&gt;special treatment of interfaces&lt;br/&gt;&lt;br /&gt;wildcards&lt;br/&gt;&lt;br /&gt;raw types&lt;br/&gt;&lt;br /&gt;enums&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;There&#39;s a good beginner intro &lt;a href=&quot;http://www.scala-lang.org/docu/files/ScalaTutorial.pdf&quot;&gt;here.&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;It seems like the biggest thing that most people object to (myself included the first time I saw it) is the syntax of the language. Martin referred to it at today&#39;s talk:&lt;br /&gt;&lt;br /&gt;x: Int instead of int x&lt;br /&gt;&lt;br /&gt;why?&lt;br /&gt;&lt;br /&gt;works better with type inference&lt;br /&gt;works better for large type expressions&lt;br /&gt;  val x: HashMap[String, (String, List[Char])] = ...&lt;br /&gt;  &lt;br /&gt;  instead of&lt;br /&gt;  &lt;br /&gt;  public final HashMap&lt;String, Pair&lt;String, List&lt;Char&gt;&gt;&gt; x = ...&lt;br /&gt;&lt;br /&gt;OK so this is all fine and good but what about the thing all Java devs care about... tool support. Well it turns out that there&#39;s some stuff in the works and out there for Scala:&lt;br /&gt;&lt;br /&gt;scalac&lt;br/&gt;&lt;br /&gt;shell: scala&lt;br/&gt;&lt;br /&gt;testing:&lt;br/&gt;&lt;br /&gt;sunit, scalacheck, specs&lt;br /&gt;&lt;br /&gt;eclipse plugin v2 in beta&lt;br/&gt;&lt;br /&gt;in the works:&lt;br/&gt;&lt;br /&gt;intellij plugin&lt;br/&gt;&lt;br /&gt;netbeans plugin (caoyuan)&lt;br /&gt;&lt;br /&gt;OK so that&#39;s my nickel tour (hey you get what you pay for) of Scala. For those of you around SF after Friday checkout &lt;a href=&quot;http://scalaliftoff.com/liftoff/&quot;&gt;Scala lift off&lt;/a&gt; on Saturday morning at 9AM. Unfortunately I can&#39;t make it myself due to a trip I had planned but if I weren&#39;t out of town I&#39;d definitely go check it out.</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/2031148970332700701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2008/05/javaone-2008-scala.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/2031148970332700701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/2031148970332700701'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2008/05/javaone-2008-scala.html' title='JavaOne 2008 - Scala'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-3516231330265300628</id><published>2008-04-26T12:45:00.001-07:00</published><updated>2008-04-26T12:45:33.309-07:00</updated><title type='text'>So long TextMate?... Hello NetBeans? Really? Yeah, really.</title><content type='html'>I&#39;ll admit it, I&#39;m one of many folks that used to treat NetBeans as a whipping boy. Questioning why Sun would bother dumping money into the horse that so obviously lost the race to Eclipse and IntelliJ to win the hearts and minds of Java developers around the world.&lt;br /&gt;&lt;br /&gt;Over the years NetBeans has flirted with me by introducing various features that sounded great on the surface and taken by itself usually was a pretty good feature. Like the new debugger and profiler that was introduced a couple years back. Or the first to implement JEE 5.0 tools, or Matisse - the Swing GUI toolkit. The list goes on and on. &lt;br /&gt;&lt;br /&gt;But each and every time I&#39;d download NetBeans and try it out no matter how good that one feature might&#39;ve been it was surrounded by basic editing and development features that were laughable. There&#39;s no way anyone could use this tool on a daily basis and be productive.&lt;br /&gt;&lt;br /&gt;Well over the past year and a half or so the NetBeans teams has been cranking away on support for ruby and rails development. Every once in awhile I&#39;d take a look and see what kind of progress they&#39;d made and always conclude that it wasn&#39;t there yet. Well, the other day I had need to hunt for a good javascript editor that would do code completion for me and so knowing NetBeans has support for javascript editing and code completion I decided to see how far the ruby and rails support in NetBeans has come as well.&lt;br /&gt;&lt;br /&gt;I grabbed a nightly build of 6.1 and installed it. Right away I noticed that they made a special build for ruby where they&#39;ve stripped it down to where it is focused on supporting ruby and rails apps. They added a theme that looks similar to textmate to make me feel more at home. Many keybindings are similar to Textmate (though not all but they are easily configurable). You can easily debug your rails apps with the graphical debugger. The generators work. Code completion works okay at times. API docs are easily visible inline during code completion. Navigating around the project is now easy where before that was the single biggest outage that kept me from even considering it. You can easily jump to type definitions. Simple refactoring is supported. Basically it&#39;s welcome to 2001 for anyone in the ruby world that came from Java. Regardless it&#39;s great to have some of these high leverage tools while working in the ruby world. &lt;br /&gt;&lt;br /&gt;I haven&#39;t completely ditched TextMate. If I know I have to do some quick edits and know that I&#39;m not going to have to do any heavy duty debugging or dev work and don&#39;t have the project open in NetBeans I&#39;ll still use it.&lt;br /&gt;&lt;br /&gt;Anyway, great job team NetBeans! Thanks so much for the great dev tool.</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/3516231330265300628/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2008/04/so-long-textmate-hello-netbeans-really.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/3516231330265300628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/3516231330265300628'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2008/04/so-long-textmate-hello-netbeans-really.html' title='So long TextMate?... Hello NetBeans? Really? Yeah, really.'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-3262790962867278497</id><published>2008-03-20T04:46:00.001-07:00</published><updated>2008-03-20T04:46:09.020-07:00</updated><title type='text'>Dave Chappelle was the man at Punchline tonight!</title><content type='html'>Wow! I was lucky enough to score a pair of tickets to Wednesday night&#39;s surprise performance at the &lt;a href=&quot;http://www.livenation.com/artist/getArtist/artistId/8951&quot;&gt;Punchline&lt;/a&gt; here in SF and man what an amazing show! The show was supposed to start at 11 but nothing happened until 11:30. That&#39;s when Dave came on. For the next 4.5 hours, yeah that&#39;s right, 4.5 hours, he delighted the crowd with topics ranging from Eddie Veder&#39;s singing voice (a recurring theme all night), to a stripper in the audience, to a guy that was in Afghanistan who stumbled upon a cave with a bunch of hash, cocaine, and steroids and managed to get himself kicked out of the military for smoking too much. Hell, he even managed a Police Academy reference, mentioning the Blue Oyster when someone suggested an eatery in the Castro when asking for a late night restaurant after the show.&lt;br /&gt;&lt;br /&gt;Dude opens and closes his show and is on stage for 4.5 hours straight! No breaks, nothing. Two packs of cigarettes and about 6 coffees later it ended and my throat is sore from laughing.&lt;br /&gt;&lt;br /&gt;What a fantastic night! Thanks Dave for a memorable time. Hope to have the privilege of seeing you again sometime. Hope you enjoyed that Grubsteak or Mel&#39;s. Come back to SF soon.</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/3262790962867278497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2008/03/dave-chappelle-was-man-at-punchline.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/3262790962867278497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/3262790962867278497'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2008/03/dave-chappelle-was-man-at-punchline.html' title='Dave Chappelle was the man at Punchline tonight!'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-5572947687915525228</id><published>2008-02-20T01:02:00.001-08:00</published><updated>2008-02-20T01:02:41.909-08:00</updated><title type='text'>Opensocial observations (Part 1 - Data types available in MySpace v0.6 and Orkut v0.7)</title><content type='html'>For anyone brave enough to dive into the world of opensocial you&#39;ll quickly find that there&#39;s a lot of stuff around to read but not much in the way of examples and demos showing the lay of the land.&lt;br /&gt;&lt;br /&gt;I won&#39;t go into great detail here about how opensocial apps are architected but what I will say is that you have to define javascript in any opensocial app just to get the thing off the ground. On some containers you need to do an XML situp as well. I&#39;ve only experimented on &lt;a href=&quot;http://sandbox.orkut.com&quot;&gt;Orkut&lt;/a&gt; and &lt;a href=&quot;http://developer.myspace.com&quot;&gt;MySpace&lt;/a&gt; thus far with varying degrees of success and confusion.&lt;br /&gt;&lt;br /&gt;Basically if you&#39;re using v0.7 and on Orkut you create an XML file that contains your app definition. Here&#39;s an example:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;br /&gt;&amp;lt;Module&amp;gt;&lt;br /&gt;  &amp;lt;ModulePrefs title=&quot;Data type inspector&quot;&amp;gt;&lt;br /&gt;    &amp;lt;Require feature=&quot;opensocial-0.7&quot;/&amp;gt;&lt;br /&gt;  &amp;lt;/ModulePrefs&amp;gt;&lt;br /&gt;  &amp;lt;Content type=&quot;html&quot;&amp;gt;&lt;br /&gt;    &amp;lt;![CDATA[&lt;br /&gt;      &amp;lt;script src=&quot;http://www.pitchwire.com/javascripts/openSocialTestV0.7.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;      &amp;lt;script&amp;gt;&lt;br /&gt;        gadgets.util.registerOnLoadHandler(init);&lt;br /&gt;      &amp;lt;/script&amp;gt;&lt;br /&gt;      &amp;lt;div id=&#39;snoop&#39;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;    ]]&amp;gt;&lt;br /&gt;  &amp;lt;/Content&amp;gt;&lt;br /&gt;&amp;lt;/Module&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;You need to put this XML file somewhere that Orkut can get to it and load it. For example: &lt;a href=&quot;http://www.pitchwire.com/opensocialTestV0.7.xml&quot;&gt;http://www.pitchwire.com/opensocialTestV0.7.xml&lt;/a&gt; In fact you can simply add an app in Orkut and when it asks for the URL simply point to this XML file I have hosted if you don&#39;t wish to create these files and host them yourself. &lt;br /&gt;&lt;br /&gt;You can see that in the XML file an external javascript file is referenced. That file contains the code I whipped up today that tells you what data types are available in a given container. &lt;br /&gt;&lt;br /&gt;This code works for Orkut and any v0.7 opensocial containers:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;function inspectEnv() {&lt;br /&gt;  var env = opensocial.getEnvironment();&lt;br /&gt;  html = new Array();&lt;br /&gt;  camera1 = &#39;b3c7f1&#39;;&lt;br /&gt;  camera2 = &#39;fff&#39;;&lt;br /&gt;  last_camera = camera1;&lt;br /&gt;  &lt;br /&gt;  html.push(&#39;&amp;lt;br/&amp;gt;Domain: &#39; + env.getDomain() );&lt;br /&gt;  html.push(&#39;&amp;lt;table style=&quot;border: 1px solid black;&quot;&amp;gt;&#39;);&lt;br /&gt;  html.push(&#39;&amp;lt;tr style=&quot;background-color: c8eaa9;&quot;&amp;gt;&amp;lt;td&amp;gt;Type&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Field&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Supported?&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#39;);&lt;br /&gt;  &lt;br /&gt;  var fieldType = opensocial.Environment.ObjectType.ACTIVITY;&lt;br /&gt;  var fields = [opensocial.Activity.Field.TITLE, &lt;br /&gt;                opensocial.Activity.Field.TITLE_ID, &lt;br /&gt;                opensocial.Activity.Field.BODY, &lt;br /&gt;                opensocial.Activity.Field.BODY_ID, &lt;br /&gt;                opensocial.Activity.Field.EXTERNAL_ID, &lt;br /&gt;                opensocial.Activity.Field.ID, &lt;br /&gt;                opensocial.Activity.Field.MEDIA_ITEMS, &lt;br /&gt;                opensocial.Activity.Field.POSTED_TIME, &lt;br /&gt;                opensocial.Activity.Field.PRIORITY, &lt;br /&gt;                opensocial.Activity.Field.STREAM_FAVICON_URL,&lt;br /&gt;                opensocial.Activity.Field.STREAM_TITLE,&lt;br /&gt;                opensocial.Activity.Field.STREAM_SOURCE_URL,  &lt;br /&gt;                opensocial.Activity.Field.STREAM_URL, &lt;br /&gt;                opensocial.Activity.Field.TEMPLATE_PARAMS, &lt;br /&gt;                opensocial.Activity.Field.URL, &lt;br /&gt;                opensocial.Activity.Field.USER_ID, &lt;br /&gt;                opensocial.Activity.Field.APP_ID];&lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;&lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.ACTIVITY_MEDIA_ITEM;&lt;br /&gt;  fields = [opensocial.Activity.MediaItem.Field.MIME_TYPE,&lt;br /&gt;            opensocial.Activity.MediaItem.Field.TYPE,&lt;br /&gt;            opensocial.Activity.MediaItem.Field.URL];&lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;&lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.ADDRESS;&lt;br /&gt;  fields = [opensocial.Address.Field.COUNTRY,&lt;br /&gt;            opensocial.Address.Field.EXTENDED_ADDRESS,&lt;br /&gt;            opensocial.Address.Field.LATITUDE,&lt;br /&gt;            opensocial.Address.Field.LOCALITY,&lt;br /&gt;            opensocial.Address.Field.LONGITUDE,&lt;br /&gt;            opensocial.Address.Field.PO_BOX,&lt;br /&gt;            opensocial.Address.Field.POSTAL_CODE,&lt;br /&gt;            opensocial.Address.Field.REGION,&lt;br /&gt;            opensocial.Address.Field.STREET_ADDRESS,&lt;br /&gt;            opensocial.Address.Field.TYPE,&lt;br /&gt;            opensocial.Address.Field.UNSTRUCTURED_ADDRESS];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;  &lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.BODY_TYPE;&lt;br /&gt;  fields = [opensocial.BodyType.Field.BUILD,&lt;br /&gt;            opensocial.BodyType.Field.EYE_COLOR,&lt;br /&gt;            opensocial.BodyType.Field.HAIR_COLOR,&lt;br /&gt;            opensocial.BodyType.Field.HEIGHT,&lt;br /&gt;            opensocial.BodyType.Field.WEIGHT];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;&lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.EMAIL;&lt;br /&gt;  fields = [opensocial.Email.Field.ADDRESS,&lt;br /&gt;            opensocial.Email.Field.TYPE];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;  &lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.FILTER_TYPE;&lt;br /&gt;  fields = [opensocial.DataRequest.FilterType.ALL,&lt;br /&gt;            opensocial.DataRequest.FilterType.HAS_APP];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;&lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.MESSAGE;&lt;br /&gt;  fields = [opensocial.Message.Field.BODY,&lt;br /&gt;            opensocial.Message.Field.TITLE,&lt;br /&gt;            opensocial.Message.Field.TYPE];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;  &lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.MESSAGE_TYPE;&lt;br /&gt;  fields = [opensocial.Message.Type.EMAIL,&lt;br /&gt;            opensocial.Message.Type.NOTIFICATION,&lt;br /&gt;            opensocial.Message.Type.PRIVATE_MESSAGE,&lt;br /&gt;            opensocial.Message.Type.PUBLIC_MESSAGE];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;&lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.NAME;&lt;br /&gt;  fields = [opensocial.Name.Field.ADDITIONAL_NAME,&lt;br /&gt;            opensocial.Name.Field.FAMILY_NAME,&lt;br /&gt;            opensocial.Name.Field.GIVEN_NAME,&lt;br /&gt;            opensocial.Name.Field.HONORIFIC_PREFIX,&lt;br /&gt;            opensocial.Name.Field.HONORIFIC_SUFFIX,&lt;br /&gt;            opensocial.Name.Field.UNSTRUCTURED];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;&lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.ORGANIZATION;&lt;br /&gt;  fields = [opensocial.Organization.Field.ADDRESS,&lt;br /&gt;            opensocial.Organization.Field.DESCRIPTION,&lt;br /&gt;            opensocial.Organization.Field.END_DATE,&lt;br /&gt;            opensocial.Organization.Field.FIELD,&lt;br /&gt;            opensocial.Organization.Field.NAME,&lt;br /&gt;            opensocial.Organization.Field.SALARY,&lt;br /&gt;            opensocial.Organization.Field.START_DATE,&lt;br /&gt;            opensocial.Organization.Field.SUB_FIELD,&lt;br /&gt;            opensocial.Organization.Field.TITLE,&lt;br /&gt;            opensocial.Organization.Field.WEBPAGE];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;&lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.PERSON;&lt;br /&gt;  fields = [opensocial.Person.Field.ABOUT_ME,&lt;br /&gt;            opensocial.Person.Field.ACTIVITIES,&lt;br /&gt;            opensocial.Person.Field.ADDRESSES,&lt;br /&gt;            opensocial.Person.Field.AGE,&lt;br /&gt;            opensocial.Person.Field.BODY_TYPE,&lt;br /&gt;            opensocial.Person.Field.BOOKS,&lt;br /&gt;            opensocial.Person.Field.CARS,&lt;br /&gt;            opensocial.Person.Field.CHILDREN,&lt;br /&gt;            opensocial.Person.Field.CURRENT_LOCATION,&lt;br /&gt;            opensocial.Person.Field.DATE_OF_BIRTH,          &lt;br /&gt;            opensocial.Person.Field.DRINKER,&lt;br /&gt;            opensocial.Person.Field.EMAILS,&lt;br /&gt;            opensocial.Person.Field.ETHNICITY,&lt;br /&gt;            opensocial.Person.Field.FASHION,&lt;br /&gt;            opensocial.Person.Field.FOOD,&lt;br /&gt;            opensocial.Person.Field.GENDER,&lt;br /&gt;            opensocial.Person.Field.HAPPIEST_WHEN,&lt;br /&gt;            opensocial.Person.Field.HEROES,&lt;br /&gt;            opensocial.Person.Field.ID,&lt;br /&gt;            opensocial.Person.Field.INTERESTS,&lt;br /&gt;            opensocial.Person.Field.JOB_INTERESTS,&lt;br /&gt;            opensocial.Person.Field.JOBS,&lt;br /&gt;            opensocial.Person.Field.LANGUAGES_SPOKEN,&lt;br /&gt;            opensocial.Person.Field.LIVING_ARRANGEMENT,&lt;br /&gt;            opensocial.Person.Field.LOOKING_FOR,&lt;br /&gt;            opensocial.Person.Field.MOVIES,&lt;br /&gt;            opensocial.Person.Field.MUSIC,&lt;br /&gt;            opensocial.Person.Field.NAME,&lt;br /&gt;            opensocial.Person.Field.NICKNAME,&lt;br /&gt;            opensocial.Person.Field.PETS,&lt;br /&gt;            opensocial.Person.Field.PHONE_NUMBERS,&lt;br /&gt;            opensocial.Person.Field.POLITICAL_VIEWS,&lt;br /&gt;            opensocial.Person.Field.PROFILE_SONG,&lt;br /&gt;            opensocial.Person.Field.PROFILE_URL,&lt;br /&gt;            opensocial.Person.Field.PROFILE_VIDEO,&lt;br /&gt;            opensocial.Person.Field.QUOTES,&lt;br /&gt;            opensocial.Person.Field.RELATIONSHIP_STATUS,&lt;br /&gt;            opensocial.Person.Field.RELIGION,&lt;br /&gt;            opensocial.Person.Field.ROMANCE,&lt;br /&gt;            opensocial.Person.Field.SCARED_OF,&lt;br /&gt;            opensocial.Person.Field.SCHOOLS,&lt;br /&gt;            opensocial.Person.Field.SEXUAL_ORIENTATION,&lt;br /&gt;            opensocial.Person.Field.SMOKER,&lt;br /&gt;            opensocial.Person.Field.SPORTS,&lt;br /&gt;            opensocial.Person.Field.STATUS,&lt;br /&gt;            opensocial.Person.Field.TAGS,&lt;br /&gt;            opensocial.Person.Field.THUMBNAIL_URL,&lt;br /&gt;            opensocial.Person.Field.TIME_ZONE,&lt;br /&gt;            opensocial.Person.Field.TURN_OFFS,&lt;br /&gt;            opensocial.Person.Field.TURN_ONS,&lt;br /&gt;            opensocial.Person.Field.TV_SHOWS,&lt;br /&gt;            opensocial.Person.Field.URLS];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;&lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.PHONE;&lt;br /&gt;  fields = [opensocial.Phone.Field.NUMBER,&lt;br /&gt;            opensocial.Phone.Field.TYPE];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;  &lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.SORT_ORDER;&lt;br /&gt;  fields = [opensocial.DataRequest.SortOrder.NAME,&lt;br /&gt;            opensocial.DataRequest.SortOrder.TOP_FRIENDS];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;&lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.URL;&lt;br /&gt;  fields = [opensocial.Url.Field.ADDRESS,&lt;br /&gt;            opensocial.Url.Field.LINK_TEXT,&lt;br /&gt;            opensocial.Url.Field.TYPE];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;  html.push(&#39;&amp;lt;/table&amp;gt;&#39;);&lt;br /&gt;  document.getElementById(&#39;snoop&#39;).innerHTML = html.join(&#39;&#39;);&lt;br /&gt;}&lt;br/&gt;&lt;br /&gt;function inspectType(env, fieldType, fields) {&lt;br /&gt;  for(j = 0; j &lt; fields.length; j++) {&lt;br /&gt;    supports = env.supportsField(fieldType, fields[j]);&lt;br /&gt;    display = supports ? &#39;style=&quot;font-weight: bold;&quot;&#39; : &#39;&#39;&lt;br /&gt;    html.push(&#39;&amp;lt;tr style=&quot;background-color: &#39; + last_camera + &#39;&quot;&amp;gt;&amp;lt;td&amp;gt;&#39; + fieldType + &#39;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&#39; + fields[j] + &#39;&amp;lt;/td&amp;gt;&amp;lt;td &#39; + display + &#39;&amp;gt;&#39; + supports + &#39;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#39;);     &lt;br /&gt;    last_camera = last_camera == camera1 ? camera2 : camera1&lt;br /&gt;  }&lt;br /&gt;}&lt;br/&gt;&lt;br /&gt;function init() {&lt;br /&gt;  inspectEnv();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt; &lt;br /&gt;&lt;br /&gt;Not so bad once you get your bearings and understand how things work. I will say that it hasn&#39;t been the smoothest development environment in the world but compared to MySpace it&#39;s a dream. Speaking of MySpace the current situation there is so awful at the moment it&#39;s almost as if they don&#39;t want people to write apps for their platform.&lt;br /&gt;&lt;br /&gt;The current state of affairs there is that they expect you to paste your HTML and javascript code into a textarea on their developer site. They too suffer from some of the same confusion that Orkut does where it&#39;s not clear what the oder of operations are and where key links are missing when trying to navigate around the sandbox. Also on MySpace your app has a MySpace profile as if it&#39;s another user. It can have friends, etc. Yeah.. that seems about right for MySpace :-)&lt;br /&gt;&lt;br /&gt;Because I&#39;m apparently a glutton for punishment I decided to try and run my container introspection code on MySpace. Turns out V0.6 is much smaller in terms of data types than V0.7 with only 3 defined.&lt;br /&gt;&lt;br /&gt;Here&#39;s the code that you can paste into your canvas textarea once you&#39;ve created an app on MySpace:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;div id=&#39;snoop&#39; style=&#39;height: 500px; overflow: scroll;&#39;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;script type=&quot;text/javascript&quot; language=&quot;javascript&quot;&amp;gt;&lt;br /&gt;function init() {&lt;br /&gt;  inspectEnv();&lt;br /&gt;}&lt;br/&gt;&lt;br /&gt;function inspectEnv() {&lt;br /&gt;  var env = opensocial.getEnvironment();&lt;br /&gt;  html = new Array();&lt;br /&gt;  camera1 = &#39;b3c7f1&#39;;&lt;br /&gt;  camera2 = &#39;fff&#39;;&lt;br /&gt;  last_camera = camera1;&lt;br /&gt;  &lt;br /&gt;  html.push(&#39;&amp;lt;br/&amp;gt;Domain: &#39; + env.getDomain() );&lt;br /&gt;  html.push(&#39;&amp;lt;table style=&quot;border: 1px solid black;&quot;&amp;gt;&#39;);&lt;br /&gt;  html.push(&#39;&amp;lt;tr style=&quot;background-color: c8eaa9;&quot;&amp;gt;&amp;lt;td&amp;gt;Type&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Field&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Supported?&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#39;);&lt;br/&gt;&lt;br /&gt;  var fieldType = opensocial.Environment.ObjectType.ACTIVITY;&lt;br /&gt;  var fields = [opensocial.Activity.Field.TITLE, &lt;br /&gt;                opensocial.Activity.Field.TITLE_ID, &lt;br /&gt;                opensocial.Activity.Field.BODY, &lt;br /&gt;                opensocial.Activity.Field.BODY_ID, &lt;br /&gt;                opensocial.Activity.Field.EXTERNAL_ID, &lt;br /&gt;                opensocial.Activity.Field.ID, &lt;br /&gt;                opensocial.Activity.Field.MEDIA_ITEMS, &lt;br /&gt;                opensocial.Activity.Field.POSTED_TIME, &lt;br /&gt;                opensocial.Activity.Field.PRIORITY, &lt;br /&gt;                opensocial.Activity.Field.STREAM_FAVICON_URL,&lt;br /&gt;                opensocial.Activity.Field.STREAM_TITLE,&lt;br /&gt;                opensocial.Activity.Field.STREAM_SOURCE_URL,  &lt;br /&gt;                opensocial.Activity.Field.STREAM_URL, &lt;br /&gt;                opensocial.Activity.Field.TEMPLATE_PARAMS, &lt;br /&gt;                opensocial.Activity.Field.URL, &lt;br /&gt;                opensocial.Activity.Field.USER_ID, &lt;br /&gt;                opensocial.Activity.Field.APP_ID];&lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br/&gt;&lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.ACTIVITY_MEDIA_ITEM;&lt;br /&gt;  fields = [opensocial.Activity.MediaItem.Field.MIME_TYPE,&lt;br /&gt;            opensocial.Activity.MediaItem.Field.TYPE,&lt;br /&gt;            opensocial.Activity.MediaItem.Field.URL];&lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br/&gt;&lt;br /&gt;  fieldType = opensocial.Environment.ObjectType.PERSON;&lt;br /&gt;  fields = [opensocial.Person.Field.ABOUT_ME,&lt;br /&gt;            opensocial.Person.Field.ACTIVITIES,&lt;br /&gt;            opensocial.Person.Field.ADDRESSES,&lt;br /&gt;            opensocial.Person.Field.AGE,&lt;br /&gt;            opensocial.Person.Field.BODY_TYPE,&lt;br /&gt;            opensocial.Person.Field.BOOKS,&lt;br /&gt;            opensocial.Person.Field.CARS,&lt;br /&gt;            opensocial.Person.Field.CHILDREN,&lt;br /&gt;            opensocial.Person.Field.CURRENT_LOCATION,&lt;br /&gt;            opensocial.Person.Field.DATE_OF_BIRTH,          &lt;br /&gt;            opensocial.Person.Field.DRINKER,&lt;br /&gt;            opensocial.Person.Field.EMAILS,&lt;br /&gt;            opensocial.Person.Field.ETHNICITY,&lt;br /&gt;            opensocial.Person.Field.FASHION,&lt;br /&gt;            opensocial.Person.Field.FOOD,&lt;br /&gt;            opensocial.Person.Field.GENDER,&lt;br /&gt;            opensocial.Person.Field.HAPPIEST_WHEN,&lt;br /&gt;            opensocial.Person.Field.HEROES,&lt;br /&gt;            opensocial.Person.Field.ID,&lt;br /&gt;            opensocial.Person.Field.INTERESTS,&lt;br /&gt;            opensocial.Person.Field.JOB_INTERESTS,&lt;br /&gt;            opensocial.Person.Field.JOBS,&lt;br /&gt;            opensocial.Person.Field.LANGUAGES_SPOKEN,&lt;br /&gt;            opensocial.Person.Field.LIVING_ARRANGEMENT,&lt;br /&gt;            opensocial.Person.Field.LOOKING_FOR,&lt;br /&gt;            opensocial.Person.Field.MOVIES,&lt;br /&gt;            opensocial.Person.Field.MUSIC,&lt;br /&gt;            opensocial.Person.Field.NAME,&lt;br /&gt;            opensocial.Person.Field.NICKNAME,&lt;br /&gt;            opensocial.Person.Field.PETS,&lt;br /&gt;            opensocial.Person.Field.PHONE_NUMBERS,&lt;br /&gt;            opensocial.Person.Field.POLITICAL_VIEWS,&lt;br /&gt;            opensocial.Person.Field.PROFILE_SONG,&lt;br /&gt;            opensocial.Person.Field.PROFILE_URL,&lt;br /&gt;            opensocial.Person.Field.PROFILE_VIDEO,&lt;br /&gt;            opensocial.Person.Field.QUOTES,&lt;br /&gt;            opensocial.Person.Field.RELATIONSHIP_STATUS,&lt;br /&gt;            opensocial.Person.Field.RELIGION,&lt;br /&gt;            opensocial.Person.Field.ROMANCE,&lt;br /&gt;            opensocial.Person.Field.SCARED_OF,&lt;br /&gt;            opensocial.Person.Field.SCHOOLS,&lt;br /&gt;            opensocial.Person.Field.SEXUAL_ORIENTATION,&lt;br /&gt;            opensocial.Person.Field.SMOKER,&lt;br /&gt;            opensocial.Person.Field.SPORTS,&lt;br /&gt;            opensocial.Person.Field.STATUS,&lt;br /&gt;            opensocial.Person.Field.TAGS,&lt;br /&gt;            opensocial.Person.Field.THUMBNAIL_URL,&lt;br /&gt;            opensocial.Person.Field.TIME_ZONE,&lt;br /&gt;            opensocial.Person.Field.TURN_OFFS,&lt;br /&gt;            opensocial.Person.Field.TURN_ONS,&lt;br /&gt;            opensocial.Person.Field.TV_SHOWS,&lt;br /&gt;            opensocial.Person.Field.URLS];          &lt;br /&gt;  inspectType(env, fieldType, fields);&lt;br /&gt;  html.push(&#39;&amp;gt;/table&amp;gt;&#39;);&lt;br /&gt;  document.getElementById(&#39;snoop&#39;).innerHTML = html.join(&#39;&#39;);&lt;br /&gt;}&lt;br/&gt;&lt;br /&gt;function inspectType(env, fieldType, fields) {&lt;br /&gt;  for(j = 0; j &lt; fields.length; j++) {&lt;br /&gt;    supports = env.supportsField(fieldType, fields[j]);&lt;br /&gt;    display = supports ? &#39;style=&quot;font-weight: bold;&quot;&#39; : &#39;&#39;&lt;br /&gt;    html.push(&#39;&amp;gt;tr style=&quot;background-color: &#39; + last_camera + &#39;&quot;&amp;gt;&amp;gt;td&amp;gt;&#39; + fieldType + &#39;&amp;gt;/td&amp;gt;&amp;gt;td&amp;gt;&#39; + fields[j] + &#39;&amp;gt;/td&amp;gt;&amp;gt;td &#39; + display + &#39;&amp;gt;&#39; + supports + &#39;&amp;gt;/td&amp;gt;&amp;gt;/tr&amp;gt;&#39;);     &lt;br /&gt;    last_camera = last_camera == camera1 ? camera2 : camera1&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;init();&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Mind you this only shows you the supported datatypes for what&#39;s in the opensocial V0.6 spec. MySpace has a few extension of their own that are available for you to use. I won&#39;t cover that here, you can go check out their &lt;a href=&quot;http://developer.myspace.com/community/myspace/myopenspace.aspx&quot;&gt;API docs&lt;/a&gt; for that. The word is that they&#39;ll be upgrading to V0.7 soon. I sure hope so but I also wish that Orkut would implement the full spec too. You&#39;ll see how much is still missing when you install the inspector app.&lt;br /&gt;&lt;br /&gt;That&#39;s it for now. I&#39;m sure I&#39;ll have lots more I could post about on this topic as well as Facebook development.&lt;br /&gt;&lt;br /&gt;Enjoy!</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/5572947687915525228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2008/02/opensocial-observations-part-1-data.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/5572947687915525228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/5572947687915525228'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2008/02/opensocial-observations-part-1-data.html' title='Opensocial observations (Part 1 - Data types available in MySpace v0.6 and Orkut v0.7)'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-7284793420036969975</id><published>2008-01-31T23:22:00.001-08:00</published><updated>2008-03-04T23:59:30.400-08:00</updated><title type='text'>Rails realities part 27 (Facebook and Bebo sittin in an app)</title><content type='html'>Long time no post. Way too long. I&#39;m not a big fan of too much noise so I try to post when I have something that I think is important to share. &lt;br /&gt;&lt;br /&gt;Anyway, today I&#39;ve got something to share that all you web2.0-facebook-bebo-social-networking-rails-app-building monkeys have been clamoring for but so far have only had a half baked solution to.... Running your Facebook apps on Bebo using RFacebook.&lt;br /&gt;&lt;br /&gt;&quot;Wait a minute, you CAN do that right now dude, catch up!&quot; Ahh yes my little ruby fanboy there IS a solution out there right now, the &lt;a href=&quot;http://blog.tierrabyte.net/2008/01/rfacebook-on-bebo-plugin.html&quot;&gt;RFacebook on Bebo plugin&lt;/a&gt;, BUT that only allows you to run the same app on EITHER Facebook or Bebo. That means you need to setup another VHost and another cluster of mongrels which you may not want to do (I don&#39;t). &lt;br /&gt;&lt;br /&gt;&quot;Dude, you&#39;re still behind man, that wizard Chad Fowler done started his own Facebook integration project called &lt;a href=&quot;https://rubyforge.org/projects/facebooker/&quot;&gt;Facebooker&lt;/a&gt;.&quot; Yeah I know about that thing too and while it is said RFacebook is not long for this world, right now I&#39;ve got a &quot;legacy&quot; (hehe) rails facebook app and at the moment upgrading to Facebooker isn&#39;t as attractive of an option for a live app vs. modifying the existing plugin/gem that&#39;s being used.&lt;br /&gt;&lt;br /&gt;I&#39;ve done the dirty work of hacking through RFacebook 0.9.8 and performing the necessary surgery to make RFacebook work on any network that&#39;s compatible with the Facebook API. In my case I&#39;ve added support for Bebo. (The only other &quot;facebook compatible&quot; network I know of) &lt;br /&gt;&lt;br /&gt;How about some code?&lt;br /&gt;In the RFacebook GEM in facebook_session.rb...&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;module RFacebook&lt;br /&gt;  # TODO: better handling of session expiration&lt;br /&gt;  # TODO: support Bebo&#39;s API&lt;br /&gt;  HOST_CONSTANTS = { &#39;facebook&#39; =&gt; { :api_version               =&gt; &quot;1.0&quot;,&lt;br /&gt;                                     :api_host                  =&gt; &quot;api.facebook.com&quot;,&lt;br /&gt;                                     :api_path_rest             =&gt; &quot;/restserver.php&quot;,&lt;br /&gt;                                     :www_host                  =&gt; &quot;www.facebook.com&quot;,&lt;br /&gt;                                     :www_path_login            =&gt; &quot;/login.php&quot;,&lt;br /&gt;                                     :www_path_add              =&gt; &quot;/add.php&quot;,&lt;br /&gt;                                     :www_path_install          =&gt; &quot;/install.php&quot;},                                     &lt;br /&gt;                     &#39;bebo&#39;     =&gt; { :api_version               =&gt; &quot;1.0&quot;,&lt;br /&gt;                                     :api_host                  =&gt; &quot;apps.bebo.com&quot;,&lt;br /&gt;                                     :api_path_rest             =&gt; &quot;/restserver.php&quot;,&lt;br /&gt;                                     :www_host                  =&gt; &quot;bebo.com&quot;,&lt;br /&gt;                                     :www_path_login            =&gt; &quot;/SignIn.jsp&quot;,&lt;br /&gt;                                     :www_path_add              =&gt; &quot;/add.php&quot;,&lt;br /&gt;                                     :www_path_install          =&gt; &quot;/c/apps/add&quot;}}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;If there were another network to come along all you&#39;d need to do is add a couple of constants in the RFacebook GEM for a new network and modify the config file for your new network. Now I don&#39;t know of any other &quot;Facebook compatible&quot; social networks out there besides Bebo at the moment but here&#39;s where you&#39;d add their information if there were.&lt;br /&gt;&lt;br /&gt;Now there are two burdens on you the user:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt; The plugin determines what network requests are coming from by checking for a subdomain (i.e. &lt;b&gt;http://bebo.mkovacs.com, http://facebook.mkovacs.com&lt;/b&gt;). Therefore you have to tell Facebook and Bebo your callback address is one that begins with the subdomain you&#39;re on.&lt;br /&gt;&lt;li&gt; There is a slight change in the facebook.yml config file. Example:&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;development:&lt;br /&gt;  facebook:&lt;br /&gt;    key: (key)&lt;br /&gt;    secret: (secret)&lt;br /&gt;    canvas_path: /pitchwire/&lt;br /&gt;    callback_path: /facebook/&lt;br /&gt;    tunnel:&lt;br /&gt;      username: user&lt;br /&gt;      host: pitchwire.com&lt;br /&gt;      port: 1099&lt;br /&gt;      local_port: 3000&lt;br /&gt;  bebo:&lt;br /&gt;    key: (key)&lt;br /&gt;    secret: (secret)&lt;br /&gt;    canvas_path: /pitchwire/&lt;br /&gt;    callback_path: /facebook/&lt;br /&gt;test:&lt;br /&gt;  facebook:&lt;br /&gt;    key: (key)&lt;br /&gt;    secret: (secret)&lt;br /&gt;    canvas_path: /pitchwire/&lt;br /&gt;    callback_path: /facebook/&lt;br /&gt;  bebo:&lt;br /&gt;    key: (key)&lt;br /&gt;    secret: (secret)&lt;br /&gt;    canvas_path: /pitchwire/&lt;br /&gt;    callback_path: /facebook/&lt;br /&gt;production:&lt;br /&gt;  facebook:&lt;br /&gt;    key: (key)&lt;br /&gt;    secret: (secret)&lt;br /&gt;    canvas_path: /pitchwire/&lt;br /&gt;    callback_path: /facebook/&lt;br /&gt;  bebo:&lt;br /&gt;    key: (key)&lt;br /&gt;    secret: (secret)&lt;br /&gt;    canvas_path: /pitchwire/&lt;br /&gt;    callback_path: /facebook/&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;So as you can see it&#39;s pretty much the same except that for each environment there&#39;s a facebook: and a bebo: setting. &lt;br /&gt;&lt;br /&gt;&quot;OK great, gimme, gimme, gimme!!&quot; Hmmm... well I&#39;ve contacted the RFacebook project owner to provide him with the changes so he can integrate them and probably do a point release, but in this instant-gratification-web2.0-gotta-have-it-now-gimme-so-I-can-get-dugg world I&#39;ll put the files up on my rinky dink shared hosting site until there&#39;s an update to the codebase and a release.&lt;br /&gt;&lt;br /&gt;Now for the disclaimer. This comes with the &#39;&lt;a href=&quot;http://sam.zoy.org/wtfpl/&quot;&gt;WTFPL&lt;/a&gt;&#39; license and DIY support :-)  &lt;br /&gt;&lt;br /&gt;Update: I&#39;ve checked the modified rfacebook code into the rfacebook project in a branch. For more information and to pickup the code go here: &lt;a href=&quot;http://rfacebook.rubyforge.org/svn/branches/rfacebo/&quot;&gt;http://rfacebook.rubyforge.org/svn/branches/rfacebo/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Simply:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt; Replace your installed RFacebook-0.9.8 GEM (or 0.9.7) with the contents of the GEM zip. &lt;br /&gt;&lt;li&gt; Replace your installed rfacebook plugin (If you have 0.9.7 you can delete rfacebook_on_rails in your plugin directory) in your app with the zipped up plugin.&lt;br /&gt;&lt;li&gt; Modify your facebook.yml file to match the format above and include your settings for Facebook and Bebo in whatever environment you choose.&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;(For you folks using the RFacebook on Bebo plugin you can go ahead and remove that)&lt;br /&gt;&lt;br /&gt;After that you should be able to hit your application from either Bebo or Facebook without having to setup different mongrel instances. Let me know if I&#39;ve missed something and I&#39;ll update this post or the zips. Or join the discussions on the &lt;a href=&quot;http://groups.google.com/group/rfacebook&quot;&gt;google group&lt;/a&gt;. (I&#39;d say to use the groups on the RFacebook site but the app is currently broken). &lt;br /&gt;&lt;br /&gt;Enjoy!</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/7284793420036969975/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2008/01/rails-realities-part-27-facebook-and.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/7284793420036969975'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/7284793420036969975'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2008/01/rails-realities-part-27-facebook-and.html' title='Rails realities part 27 (Facebook and Bebo sittin in an app)'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-7637429929191903627</id><published>2007-10-25T10:03:00.001-07:00</published><updated>2007-10-25T10:07:37.809-07:00</updated><title type='text'>MicroPlace</title><content type='html'>I&#39;ve been quite busy over the last several months and have neglected my blog for too long. So while I don&#39;t have a rails reality to post today I will make mention of a couple of things that I&#39;ve been up to over the past few months. &lt;br /&gt;&lt;br /&gt;In early June I started contracting with a small startup within eBay called &lt;a href=&quot;http://www.microplace.com&quot;&gt;MicroPlace&lt;/a&gt;. Josh just blogged about the launch &lt;a href=&quot;http://blog.hasmanythrough.com/2007/10/24/microplace-launch&quot;&gt;yesterday&lt;/a&gt;. So rather than repeat what he said go read his writeup :-) Shortly after I started with MicroPlace Josh came on board and working with the great team from MicroPlace we began to gel as a team and things came together well.&lt;br /&gt;&lt;br /&gt;When I started the team was pretty deep into using agile development processes as a guiding principal to their work. Test first was highly touted and code coverage was closely watched (&gt;97% when I left). It made coming in as a consultant much easier because I was able to make sweeping changes to the code when needed and be confident that I could know what was impacted as a result. It was my first time really being in an environment where everyone had bought into the value of testing *mostly* first and it definitely makes things less stressful and more enjoyable.&lt;br /&gt;&lt;br /&gt;Though it was a quick 3 month engagement I really am grateful for the great connections that I made with the MicroPlace team and am very proud of the job we were able to do in such a short time of getting something launched, with quality, that is for the greater good of mankind. Best of luck to MicroPlace!&lt;br /&gt;&lt;br /&gt;After finishing up with MicroPlace in early/mid September I went on a long overdue vacation for a few weeks, to Italy. While I haven&#39;t posted them all you can check out my photos from the trip on &lt;a href=&quot;http://www.flickr.com/photos/mkovacs/&quot;&gt;Flickr&lt;/a&gt;. I just got back last Thursday night and while I&#39;m still getting over the jetlag (waking up at 5-6AM has been great for getting the day started with a run down to the Marina green :-) I&#39;ll back on pacific time fairly soon.&lt;br /&gt;&lt;br /&gt;Oh and a final note about my beloved Indians who found a new way to falter as I arrived back to the US (I think I&#39;ll stay overseas next year if they make the playoffs again), Go Rockies!! ;-) Thanks for a great season tribe and for the chance to watch you in the playoffs!</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/7637429929191903627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/10/microplace.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/7637429929191903627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/7637429929191903627'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/10/microplace.html' title='MicroPlace'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-986358806862538289</id><published>2007-06-30T09:30:00.001-07:00</published><updated>2007-06-30T09:30:42.115-07:00</updated><title type='text'>iPhone activation blues for TDMA customers</title><content type='html'>&lt;div style=&#39;text-align: center;&#39;&gt;&lt;br /&gt;&lt;img src=&#39;http://www.grooveking.com/blog/uploaded_images/g-741710.jpg&#39;/&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That&#39;s right kids. Falling under &lt;a href=&quot;http://beust.com/weblog/archives/000354.html&quot;&gt;mass hypnosis&lt;/a&gt; yet again, I waltzed down to the Apple store in downtown SF at about 8PM last night to see if the hypothesis would be true that I could walk right in and pick one up instead of camping out overnight. Sure enough there was no line around the corner. The line I waited in had maybe 10 people and I waited maybe 5 minutes. &lt;br /&gt;&lt;br /&gt;Tons of phones, no problems, people all around, San Francisco&#39;s finest outside standing guard just in case.&lt;br /&gt;&lt;br /&gt;Then it&#39;s time to go home and activate this thing before going out for the evening. Ahh yes. This is where you get a nice reminder that AT&amp;T is the provider for this phone.&lt;br /&gt;&lt;br /&gt;So to give a bit of history, I&#39;ve been holding out for quite some time for a phone that seemed worthy of giving up my old Motorola V.60c on the old AT&amp;T wireless TDMA network but hadn&#39;t found a worthy successor so I just kept kickin it old school. TDMA&#39;s signal reach is much further and when I&#39;d go camping I was the only one with a phone that worked because it also was cell compatible.&lt;br /&gt;&lt;br /&gt;So basically I&#39;ve been living in the cell phone &quot;stone age&quot;. Everytime I&#39;d decide to go on a &quot;date&quot; in a Cingular, TMobile store, etc, the folks that worked there would always remark &quot;Wow I haven&#39;t seen that phone in YEARS. How about a nice crappy new phone that has a weaker signal strength that won&#39;t work in your apartment?&quot;&lt;br /&gt;&lt;br /&gt;&quot;No thanks&quot; I&#39;d say as I&#39;d walk out with my old tattered TDMA phone and wonder how much longer I&#39;d have it around. I mean after 3+ years it&#39;s just starting to get a little long in the tooth ;-) The battery lasts about a day now with any sort of usage.&lt;br /&gt;&lt;br /&gt;A few months ago AT&amp;T gave me an ultimatum over a text message. &quot;Upgrade or die.&quot; They are turning off the old TDMA wireless network in Feb. 2008. Hmm... well I guess I have no choice now. Hopefully they&#39;ve got more GSM coverage than the last time I looked and hopefully it works in my apt.&lt;br /&gt;&lt;br /&gt;So back to last evening. I got home, hooked it up to the mac that I purchased during my last &quot;mass hypnosis&quot; episode in Jan. 2006. I updated iTunes, hooked up the phone, and started the registration process. It all was going pretty smoothly until I reached the end. AT&amp;T then informs me that more time is needed to activate my phone and that I will receive an email once it&#39;s completed. &lt;br /&gt;&lt;br /&gt;&quot;Sigh. They&#39;re not able to handle this volume.&quot; But I suspected that my being on TDMA might have something to do with it. I spoke with two representatives last night that ensured me that wasn&#39;t a problem and that it was just due to volume and that they were backlogged. &quot;By 7AM EDT your activation will have gone through sir.&quot; What a pain but OK I guess that&#39;s the way it&#39;s gotta be. &lt;br /&gt;&lt;br /&gt;Fast forward to this morning. No activation, no email, nothing. I call up again. Each time I called I made it a point to tell them I&#39;m on the TDMA network because for some reason the person on the other end of the line doesn&#39;t seem to have that information. This time the woman says &quot;Oh! Yeah that&#39;s gonna be a problem. Can you please hold?&quot; After 10-15 minutes of holding she comes back, apologizes and informs me that they can&#39;t help me over the phone. I now need to go down to the AT&amp;T wireless store where they will convert my account to GSM by giving me a fake SIM. Then I have to go back home and activate my phone. Fun. Why this can&#39;t be done over the phone I don&#39;t know.&lt;br /&gt;&lt;br /&gt;Anyway for all you old TDMA users, all 1% of your in the AT&amp;T customer base, be prepared for this nonsense when you finally upgrade. Unless you convert to one of the other carriers which almost seems like the least painful way to go. If that blackberry curve with wifi was ready to roll on TMobile I might consider that instead solely based on AT&amp;T&#39;s crappy service.&lt;br /&gt;&lt;br /&gt;Time for this caveman to get unfrozen down at the local AT&amp;T wireless store.&lt;br /&gt;&lt;br /&gt;&lt;div style=&#39;text-align: center;&#39;&gt;&lt;br /&gt;&lt;img src=&#39;http://chucksconnection.com/encino/encino01.jpg&#39;/&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/986358806862538289/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/06/iphone-activation-blues-for-tdma.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/986358806862538289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/986358806862538289'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/06/iphone-activation-blues-for-tdma.html' title='iPhone activation blues for TDMA customers'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-42496416000808468</id><published>2007-05-21T22:27:00.001-07:00</published><updated>2007-05-21T22:27:43.400-07:00</updated><title type='text'>Rails realities part 26 (I&amp;#39;m in ur app breakin cascading saves)</title><content type='html'>OK I only posted once so far from my experience at RailsConf. I may post some more about some of the sessions I attended but overall it was a great time and I learned a few new things (namely some cool functionality that I didn&#39;t know firebug had :-)&lt;br /&gt;&lt;br /&gt;One thing I was sporadically working on was adding a new feature to &lt;a href=&quot;http://www.pitchwire.com&quot;&gt;PitchWire&lt;/a&gt; and as I went further down the rabbit hole it became apparent that to add this new feature that it&#39;s probably best that I finally bite the bullet and upgrade from rails 1.1.6 to rails 1.2.3. &lt;br /&gt;&lt;br /&gt;I&#39;m actually still in the process of upgrading but I thought I&#39;d blog about a couple of things that have tripped me up thusfar.&lt;br /&gt;&lt;br /&gt;The first one that tripped me up was after updating rails and trying to run my tests I received tons of weird command line errors that I don&#39;t have anymore unfortunately but basically my rubygems was too old (.8.something) and I needed to upgrade to the latest (.9.something). I actually can&#39;t take credit for figuring it out. My new friend Jimmy (he doesn&#39;t have a blog yet but he should) thought of it as we were sitting there pair programming as he&#39;d already gone through the upgrade exercise. &lt;br /&gt;&lt;br /&gt;So after updating rubygems with:&lt;br /&gt;&quot;gem update system&quot;&lt;br /&gt;&lt;br /&gt;I reran my tests and was down to a total of 7 failures from 120something prior. I went to the first failure and it was an application failure. For some reason my profile update action test wasn&#39;t passing.&lt;br /&gt;&lt;br /&gt;As it turns out the problem turns out to be my reliance on behavior that was deemed to be a bug: &lt;a href=&quot;http://dev.rubyonrails.org/changeset/4690&quot;&gt;http://dev.rubyonrails.org/changeset/4690&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;I was using cascading save operations to update multiple objects on a single action because on my profile page I have properties that belong to 3 different objects, user, contact_info, and company. Now one could argue that I could either have separate pages for each or only provide an AJAX style update to the properties of these objects where you can only update one at a time. I may do that in the future but for now I&#39;m not going to refactor my application for the sake of upgrading rails.&lt;br /&gt;&lt;br /&gt;What does all this mean? Basically when designing your rails apps don&#39;t rely on cascading save operations anywhere. Explicitly save each object whose properties you have updated in the process of a request. And since it&#39;s not really desirable to update and save multiple objects per request the best approach is to keep the data in your request confined to a single object if you can which means using fine grained AJAX style field updates using inline editors everywhere or only showing a form that edits fields for a single object. &lt;br /&gt;&lt;br /&gt;Unfortunately this doesn&#39;t always map very well to the business logic of your app so you may have to do something like:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;User.transaction do &lt;br /&gt;  @user.save&lt;br /&gt;  @user.contact_info.save&lt;br /&gt;  @user.contact_info.company.save&lt;br /&gt;end&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Where as if you can rely on saves being cascaded down through a relationship hierarchy you can just write:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;@user.save&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I can&#39;t say I&#39;m psyched to either patch rails back to the &quot;broken&quot; way or revamp my app to undo anywhere I&#39;m relying on cascading saves but I&#39;m a little scared at what else I might stumble across. Hopefully my tests are comprehensive enough to catch anything else, I&#39;m glad they caught this one.&lt;br /&gt;&lt;br /&gt;Be careful out there.</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/42496416000808468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/05/rails-realities-part-26-i-in-ur-app.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/42496416000808468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/42496416000808468'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/05/rails-realities-part-26-i-in-ur-app.html' title='Rails realities part 26 (I&amp;#39;m in ur app breakin cascading saves)'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-5913395200260464334</id><published>2007-05-18T21:12:00.001-07:00</published><updated>2007-05-18T21:36:26.504-07:00</updated><title type='text'>RailsConf 2007 - Day 1? Day 0?</title><content type='html'>Many geeks have descended upon an unsuspecting Portland for a few days of geekery about some software thingy most have never heard of. Many of these poor luddites have never even heard of &lt;a href=&quot;http://www.twitter.com&quot;&gt;Twitter&lt;/a&gt; and appear uncertain of the herds of geeks wearing shirts that say &quot;[Skip Intro]&quot;, &quot;He broke the build&quot;, and &lt;a href=&quot;http://www.powerset.com&quot;&gt;&quot;Powerset&quot;&lt;/a&gt;. I think I overheard some guy asking one of the crew if Powerset was that new gym over on 13th. &lt;br /&gt;&lt;br /&gt;So today was Day 1 of RailsConf. I saw another blogger posting an entry titled &quot;RailsConf Day 2&quot;. I don&#39;t know if he was working on tomorrow&#39;s posting or what but any way you slice it today is Day 1. Today was the first full day of the conference and yesterday was just all day tutorial sessions, so that means day 1. Or if you want to be a geek and make the argument that yesterday was the first day, well then you have to be a geek all the way and realize that yesterday was Day 0.&lt;br /&gt;&lt;br /&gt;This morning started of with the big keynote. Folks were ready with their buzzword bingo cards, giddy like school kids waiting for the dirty words. Fresh off my &quot;Geek retreat&quot; last weekend in Vegas I went to the sports book down in the vendor area with odds on swear word usage. The over/under was 5. Counting on a kindler/gentler talk I bet $100 on the under. &lt;br /&gt;&lt;br /&gt;Turns out DHH was a big teddy bear today and I&#39;m $30 richer. There was no real big Earth shattering news that was revealed today, though he did lay out 9 things that are interesting that are going into Rails 2.0.&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Breakpoints are back - ruby-debug is integrated into rails 2. The big win here is being able to put a simple statement into your action, stop the request in flight, inspect and change things and then continue the action.&lt;br /&gt;&lt;li&gt;HTTP perf and asset packaging - &lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;javascript_include_tag :all, :cache =&gt; true&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt; will package all js into one file for delivery. The same can also be done for stylesheets. You can also setup an environment configuration to create virtual asset servers to overcome the browser behavior of serially requesting images 2 at a time from the same host. Read more at &lt;a href=&quot;http://www.chadfowler.com/2007/2/18/edge-rails-goody-distributed-asset-hosts&quot;&gt;Chad&#39;s blog&lt;/a&gt;.&lt;br /&gt;&lt;li&gt;query cache - AR has query caching that you get for free and works by matching exact SQL calls. You don&#39;t need to turn this on it just works. It will be interesting to see how big mongrel processes are going to get as a result of this.&lt;br /&gt;&lt;li&gt;action.mimetype.renderer - separate the mime type from the template type so that you can request a file type and it can be rendered easily by any template type without a special naming convention. Examples he gave: people/index.html.erb people/index.xml.builder index.rss.erb index.atom.builder&lt;br /&gt;&lt;li&gt;config/initializers - To slim down the environment configuration you can put ruby files into the &quot;initializers&quot; dir that get run automatically on init&lt;br /&gt;&lt;li&gt;sexy migrations - flip name -&gt; type declaration to type -&gt; name which can allow you to declare more than one column on a line and simpler timestamp declarations. Check out Chris&#39; post &lt;a href=&quot;http://errtheblog.com/post/2381&quot;&gt;here&lt;/a&gt;&lt;br /&gt;&lt;li&gt;HTTP auth - Basic auth plugin is moved to core. &lt;br /&gt;&lt;li&gt;The MIT assumption - default license file for plugin generation&lt;br /&gt;&lt;li&gt;Spring cleaning - removal of deprecated stuff&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;Of all the things he mentioned I think breakpoint being back is probably the best news for rails devs, especially those that are new and trying to learn the framework. The query cache is interesting as well. It&#39;s appears simple and will likely help perf for many apps which do the same queries again and again, especially for those of us that load the user data on each request from the id stored in the session. He didn&#39;t show how to expire entries in the cache though.&lt;br /&gt;&lt;br /&gt;The keynote demo displayed the restful stuff and he mentioned that you get search for free with the stuff in edge. The convention that is put forth with the REST approach will make writing and reading existing app code that much easier to deal with.&lt;br /&gt;&lt;br /&gt;The talks have been very good and the ones that are popular are ridiculously packed. I approached the &quot;Standing on the shoulders of giants&quot; talk which was a guided tour through the code of several ruby/rails projects that were considered to be good code examples.  &lt;br /&gt;&lt;br /&gt;At the entrance a couple of middle aged ladies were guarding the doors and fending off hordes of geeks salivating at the code porn being shown just beyond those doors. I made my way through the crowd to the front and one of the lady&#39;s was like &quot;Sorry it&#39;s full&quot;. Hmm.... but I&#39;m here as press damnit, I have an obligation to the geek community. I figured &quot;what the hell?&quot; and I asked &quot;Does this get me in?&quot; as I lift up my press pass. &quot;Nope&quot;. OK, time to move on to &quot;bouncer&quot; number 2. &quot;Hi, I&#39;m press and I&#39;d like to get in&quot;. &quot;OK go on&quot;. Sweet! I&#39;m in! Holy crap there&#39;s a ton of people in here! Luckily I found a seat and we proceeded to be taken on a tour of Rick Olson&#39;s handywork for the most part. Adam did a good job of walking through the code and picking out good examples. He also did a good job of describing his process of &quot;code spelunking&quot; as he put it. I don&#39;t think I need to tell all you SouthPark fans out there why that&#39;s funny.&lt;br /&gt;&lt;br /&gt;Alright I&#39;m off to see about a BOF or if those Powerset guys are wandering the streets of Portland helping Rocko find his gym. If only there were something out there that Rocko could use, in his own natural language to tell him where to find his gym. Oh well, I&#39;m sure something&#39;s bound to come out soon, like this year. In the meantime it&#39;s very gracious of them to perform user searches with such a personal touch.</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/5913395200260464334/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/05/railsconf-day-1-keynote.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/5913395200260464334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/5913395200260464334'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/05/railsconf-day-1-keynote.html' title='RailsConf 2007 - Day 1? Day 0?'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-3573965283233739548</id><published>2007-05-10T23:55:00.001-07:00</published><updated>2007-05-10T23:57:34.465-07:00</updated><title type='text'>JavaOne 2007 Day 3 - My groovy redux</title><content type='html'>I still remember the first time I was exposed to groovy. &lt;a href=&quot;http://macstrac.blogspot.com/&quot;&gt;James Strachan&lt;/a&gt; stood on stage (I think it was 2003 or 2004) and with his very smooth and soothing voice dazzled everyone in the room with this new language that allowed you to get more done with less. In the period since that time groovy has had its ups and downs but lately it really seems to be coming of age since there&#39;s finally a release (1.0 was released in &lt;a href=&quot;http://www.infoq.com/news/2007/01/groovy-10&quot;&gt;January&lt;/a&gt; of this year), there&#39;s the &lt;a href=&quot;http://grails.org/&quot;&gt;grails&lt;/a&gt; project, and the popularity of ruby and rails has at least raised the awareness of dynamic scripting languages to new levels. For java developers that haven&#39;t made the venture outside the confines of Java it appears now is as good a time as any to put a new weapon to your arsenal. Groovy is certainly a natural choice for many java developers that don&#39;t wish to learn a new API with ruby though there&#39;s quite a bit of the groovy API that extends java that appears to be at least partially inspired by ruby. &lt;br /&gt;&lt;br /&gt;Today I attended &lt;a href=&quot;http://www.openlogic.com/blogs/author/rod/&quot;&gt;Rod Cope&#39;s&lt;/a&gt; &quot;Advanced Groovy&quot; talk. So while I&#39;d never written a line of groovy until today (I copied Rod&#39;s numerous examples for today&#39;s post) I felt up to the task of attending an &quot;advanced&quot; talk based on the level of most talks at JavaOne. It turned out I was right, as Rod spewed out code example after code example I felt quite at home with a few minor syntax differences that I will say are less &quot;beautiful&quot; than ruby but that&#39;s probably because I&#39;m used to ruby now. But you could take any ruby developer, give them groovy and they would have no problems working with it based on the examples I saw in today&#39;s talk.&lt;br /&gt;&lt;br /&gt;Let&#39;s look at some of the advanced features from Rod&#39;s examples:&lt;br /&gt;&lt;br /&gt;Safe navigation - Allows safe traversal without getting NPEs and avoid doing null checks. When you call the property with &quot;?&quot; if anything in the chain is null the result is null.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;people = [&#39;rod&#39; : [&#39;age&#39; : 36, &#39;height&#39; : &quot;5&#39;9&quot;]]&lt;br /&gt;people.rod.age&lt;br /&gt;-&gt; 36&lt;br /&gt;people?.joe?.age&lt;br /&gt;-&gt; null&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Expando - a dynamic etch-a-sketch object that you can add methods and properties to on the fly&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;import groovy.util.Expando&lt;br/&gt;&lt;br /&gt;rod = new Expando(name: &#39;Rod&#39;, age: 36)&lt;br /&gt;rod.drinkWater = {num -&gt; num.times { println &quot;yummy&quot; }}&lt;br/&gt;&lt;br /&gt;print rod.age&lt;br /&gt;-&gt; 36&lt;br /&gt;rod.drinkwater(2)&lt;br /&gt;-&gt; yummy&lt;br /&gt;-&gt; yummy&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Template engines - A closure as template engine&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;t = {p -&gt; &quot;${p.name} is ${p.age()}&quot; }&lt;br /&gt;rod = new Person(name: &#39;Rod&#39;, age: 36)&lt;br /&gt;println t(rod)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;He also mentioned the existence of a GStringTemplateEngine. groovy.text.GStringTemplateEngine&lt;br /&gt;&lt;br /&gt;Default parameters - just like ruby it supports default param values in method signatures&lt;br /&gt;&lt;br /&gt;Single object iteration/identity. You can iterate over any object whether a collection or not. If it&#39;s not a collection you&#39;ll get back the object itself once in the block.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;currentCustomer.employees[&#39;joe&#39;].manager.secretary.each { it.bonus = 1000 }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;With identity it&#39;s a way to have an implicit object set in the block. I&#39;m not really clear on why this is such a big win at the moment.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;currentCustomer.employees[&#39;joe&#39;].manager.secretary.identity { &lt;br /&gt;println &quot;salary = $salary&quot;  } &lt;- same as saying secretary.salary&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Currying - This is the process of using functions to manufacture other functions. &lt;br /&gt;First a groovy example:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;c1 = {a, b -&gt; a + b}&lt;br /&gt;c2 = c1.curry(&quot;Hi &quot;)  result = c2 = {b -&gt; &quot;Hi &quot; + b}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Now let&#39;s see the &lt;a href=&quot;http://www.rubyquiz.com/quiz64.html&quot;&gt;same thing&lt;/a&gt; in ruby for folks that have never heard of currying before. The following code isn&#39;t mine it&#39;s taken from the the &lt;a href=&quot;http://www.rubyquiz.com&quot;&gt;ruby quiz&lt;/a&gt; site.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;require &quot;curry&quot;&lt;br/&gt;&lt;br /&gt;scale = lambda { |size, object| object * size }&lt;br /&gt;puts &quot;3 scaleded to a size of 10 is #{scale[10, 3]}.&quot; # 30&lt;br /&gt;puts&lt;br/&gt;&lt;br /&gt;# curry some functions&lt;br /&gt;double = scale.curry(2)&lt;br /&gt;triple = scale.curry(3)&lt;br /&gt;halve = scale.curry(0.5)&lt;br/&gt;&lt;br /&gt;puts &quot;4 doubled is #{double[4]}.&quot; # 8&lt;br /&gt;puts &quot;1 tripled is #{triple[1]}.&quot; # 3&lt;br /&gt;puts &quot;Half of 10 is #{halve[10]}.&quot; # 5.0&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Dynamic language extensions - mixins. Of all the things that were shown the implementation of mixins made me cringe because you have to create a new class and then pollute your implementation code that uses the mixin with the &quot;use&quot; method. The ruby way is seamless and much more elegant to me but the groovy way is arguably a little safer because it&#39;s so explicit and you&#39;d always know that you&#39;re dealing with mixed in implementation. Still, I don&#39;t like it :-)&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;class PropertiesHelper &lt;br /&gt;{&lt;br /&gt;  public static List getProperyNames(Object bean)&lt;br /&gt;  {&lt;br /&gt;    def methodNames = bean.class.methods.name.findAll { it.startsWith(&#39;get&#39;) }&lt;br /&gt;    def goodNames = methodNames - [&#39;getMetaClass&#39;, &#39;getClass&#39;, &#39;getProperty&#39;]&lt;br /&gt;    def propertyNames = goodNames.sort().collect {&lt;br /&gt;      // &quot;getName&quot; -&gt; &quot;n&quot; + &quot;ame&quot; -&gt; &quot;name&quot;&lt;br /&gt;      it[3].toLowerCase() + it[4..-1]&lt;br /&gt;    }&lt;br /&gt;    return propertyNames&lt;br /&gt;  }&lt;br /&gt;}&lt;br/&gt;&lt;br /&gt;rod = new Person(firstName: &#39;Rod&#39;, lastName: &#39;Cope&#39;)&lt;br /&gt;use(PropertiesHelper) {&lt;br /&gt;  for (prop in rod.propertyNames) {&lt;br /&gt;    println &quot;${prop} = ${rod[prop]}&quot;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;-&gt; firstName = Rod&lt;br /&gt;-&gt; lastName = Cope&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Method aliasing &lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;def p = System.out.&amp;println&lt;br /&gt;p(&#39;hi&#39;)&lt;br/&gt;&lt;br /&gt;def doSomething(method) { method(&#39;dog&#39;) }&lt;br /&gt;doSomething(p)&lt;br /&gt;-&gt; dog&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;After these simple examples Rod broke into a couple more complex examples that really showed the power of groovy and to me rivals DHH&#39;s video that made RoR so attractive to so many people. &lt;br /&gt;&lt;br /&gt;Demo of xml-rpc&lt;br /&gt;First start up a server&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;import groovy.net.xmlrpc.*&lt;br/&gt;&lt;br /&gt;server = new XMLRPCServer()&lt;br /&gt;server.testme = {name -&gt; &quot;$name is cool&quot;}&lt;br /&gt;server.startServer(new ServerSocket(9047))&lt;br /&gt;go&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Then create and run the client code&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;import groovy.net.xmlrpc.*&lt;br/&gt;&lt;br /&gt;server = new XMLRPCServerProxy(&#39;http://localhost:9047)&lt;br /&gt;println server.testme(&quot;Groovy&quot;)&lt;br /&gt;go&lt;br /&gt;Groovy is cool&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Going back to the server let&#39;s add a new method to our service:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;server.multiply = {it * 7}&lt;br /&gt;go&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Back to client, let&#39;s call it:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;println server.multiply(3)&lt;br /&gt;go&lt;br /&gt;21&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;No reboots were needed in the above example code which is impressive&lt;br /&gt;&lt;br /&gt;Next up was the ActiveX demo using &lt;a href=&quot;http://danadler.com/jacob&quot;&gt;http://danadler.com/jacob&lt;/a&gt; (Java API to COM)&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;import org.codehaus.groovy.scriptom.ActiveXProxy&lt;br/&gt;&lt;br /&gt;excel = new ActiveXProxy(&quot;Excel.Application&quot;)&lt;br /&gt;excel.visible = true&lt;br /&gt;go&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;This opens excel on your machine&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;book = excel.workbooks.add()&lt;br /&gt;go&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Creates a new workbook in your opened excel instance&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;sheet = book.activesheet&lt;br /&gt;go&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Selects the first sheet in the workbook&lt;br /&gt;&lt;br /&gt;He then proceeded to add data to the sheet programmatically, create charts and add formulas (this code isn&#39;t complete as I wasn&#39;t able to keep up with this section)&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;a1 = sheet.range(&#39;a1&#39;); a2 = sheet.range(&#39;a2&#39;)&lt;br /&gt;co = sheet.chartobjects.add(50,50,400,200)&lt;br /&gt;go&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;After that he demonstrated the SwingBuilder and updated the excel spreadsheet via that UI&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;swing = new groovy.swing.SwingBuilder()&lt;br /&gt;mybutton = swing.button(text: &#39;click me&#39;)&lt;br /&gt;mybutton.actionPerformed = { &lt;br /&gt;  a1.value = new Random().nextFloat() * 500&lt;br /&gt;  chart.export(&#39;graphname.gif)&lt;br /&gt;  mybutton.icon = new javax.swing.ImageIcon(&#39;graphname.gif&#39;) &lt;br /&gt;}&lt;br/&gt;&lt;br /&gt;frame = swing.Frame(title: &quot;The frame&quot;)&lt;br /&gt;frame.show()&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;The above code shows the swing GUI and when you click the button the chart is updated both in excel and in the button that you&#39;ve just clicked. The speed was fast with no noticeable slowness.&lt;br /&gt;&lt;br /&gt;A couple final examples that were thrown in at the end&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&quot;cmd /c dir&quot;.execute().text -&gt; execute a system process&lt;br /&gt;Thread.start { any code } -&gt; firing off a thread, this is just like ruby&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;It&#39;s great to see groovy finally coming into its own. Performance isn&#39;t bad and will only get better with optimization and for java devs that want to get into scripting or a ruby dev that needs to work in java and can&#39;t use jruby groovy&#39;s a really comfortable choice for all but the most religious ruby zealots :-)</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/3573965283233739548/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/05/javaone-day-3-my-groovy-redux.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/3573965283233739548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/3573965283233739548'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/05/javaone-day-3-my-groovy-redux.html' title='JavaOne 2007 Day 3 - My groovy redux'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-4178246920453690170</id><published>2007-05-10T15:35:00.001-07:00</published><updated>2007-05-10T21:50:57.881-07:00</updated><title type='text'>JavaOne 2007 Day 2 Newbie enterprise on rails</title><content type='html'>Day 2 of Javathehutt&#39;s ruby coverage at JavaOne. Huh? Yeah that&#39;s right. Next week at Railsconf I may just have to talk about all the java related discussions that are occurring there. So what happened on day 2 that would be of interest to the ruby faithful? Well today there was &quot;Ruby on Rails Meets the World of Enterprise Applications&quot; given by Daniel McWeeney from Colgate-Palmolive. I walked into another pretty good sized room that was full, perhaps about half the size of the room for the JRuby session. &lt;br /&gt;&lt;br /&gt;Daniel was a very charismatic speaker who would lift his arm in the air and bark out &quot;demo&quot; or &quot;slides&quot; to switch from one context to another. He spoke about his company&#39;s need to create a more user friendly interface to an SAP system. The system is a project/resource management system where they create projects and then assign resources (people, for those in the non-enterprisey world). The current interface is pretty unfriendly to the untrained user and as a result they weren&#39;t seeing a satisfactory level of usage of their SAP system. &lt;br /&gt;&lt;br /&gt;So it was the job of our hero Daniel and his crack team of young energetic developers (actually I think it was just him) to figure out a way to come up with an interface on this system that would be easy to use, do it on zero budget, and with minimal time. He said that when he started he had zero knowledge of ruby and rails, and while it by no means a knock on him it actually was pretty easy to see that it was his first rails app from looking at his code as well as some of the UI that he&#39;d built. He did a pretty good job of walking through his code and explaining exactly what was happening at all times. He made heavy use of RJS and drag and drop, and while there is certainly room for improvement he generally did a pretty good job.&lt;br /&gt;&lt;br /&gt;One thing he made use of that was new to me was a gem called SAP4rails that he used to make calls into SAP to read/write the project data. It looked pretty straightforward to use and I hope I never have to use it :-) &lt;br /&gt;&lt;br /&gt;In non-ruby related news I attended a press/analyst lunch panel on international developer perspectives where I learned that the entire country of Brazil loves java and that the guy from the Philippines was surprised at how much a developer in Singapore makes and was thinking of flying there to work every week. &lt;br /&gt;&lt;br /&gt;I wanted to attend the prototype, scriptaculous, and rico talk but the line was too long and well, I&#39;m likely to already know much of what they&#39;re talking about so I skipped out on that and headed to the press room to linger and talk to some journalists and espouse the great benefits of &lt;a href=&quot;http://www.pitchwire.com&quot;&gt;PitchWire&lt;/a&gt; to them. I actually ended up meeting a couple of coders in there including Tim O&#39;Brien who blogs for &lt;a href=&quot;http://www.oreillynet.com/onjava/blog/2007/05/javaone_olivers_javafx_he_call.html&quot;&gt;O&#39;Reilly&lt;/a&gt; and is into rails development. I gave him a quick rundown of my sortable table plugin and he immediately identified need in his current apps. Always nice to build stuff that people use.&lt;br /&gt;&lt;br /&gt;Later in the day Tim and I headed over to the blogger meetup and then the Google party. I&#39;m going to defer to &lt;a href=&quot;http://www.bileblog.org/?p=331&quot;&gt;Hani&#39;s&lt;/a&gt; coverage which is pretty on target :-)&lt;br /&gt;&lt;br /&gt;I will say that it was great to run into Josh Bloch again after meeting him at last year&#39;s JavaOne. We chatted about his API design talk and he also disclosed to &lt;a href=&quot;http://www.beust.com/blog&quot;&gt;Cedric&lt;/a&gt; and myself that he had now written his first line of ruby code this week :-) Can &quot;Effective Ruby&quot; be far away?&lt;br /&gt;&lt;br /&gt;Oh and top quote overheard during a press event from a member of the press &quot;I was a college professor and I graduated students that could neither read nor write&quot; </content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/4178246920453690170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/05/javaone-2007-day-2-newbie-enterprise-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/4178246920453690170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/4178246920453690170'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/05/javaone-2007-day-2-newbie-enterprise-on.html' title='JavaOne 2007 Day 2 Newbie enterprise on rails'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-1844874992329951741</id><published>2007-05-09T17:20:00.001-07:00</published><updated>2007-05-09T17:20:04.139-07:00</updated><title type='text'>JavaOne 2007 Day 1 - JRuby, Appistry, Layer7, SF &amp;quot;outsourcing&amp;quot;, and shots at the Tangosol party</title><content type='html'>Last year Sun latched on to JRuby and hired the developers that work on the project mostly because of the astuteness of Tim Bray. It&#39;s been amazing to watch this project grow from relative obscurity to headliner in such a short amount of time. Yesterday as I made my way through the halls at Moscone to attend the JRuby talk I was thinking to myself &quot;It shouldn&#39;t be too bad finding a seat here, I mean this is &quot;Java&quot; one, not ruby or jruby one&quot;. While it wasn&#39;t difficult to find a seat I was surprised when I walked through the doors of Gateway 104 to find a large room that was full for this talk. A quick estimate put it somewhere in the neighborhood of at least 1,000 people which is way more than I would&#39;ve thought going in.&lt;br /&gt;&lt;br /&gt;The talk itself was really very introductory. Charles and Tom assumed no prior ruby knowledge and even asked the question &quot;Who here doesn&#39;t know what ruby is?&quot; As I thought to myself &quot;there&#39;s no way... &quot;, I looked around and saw at least 5-6 hands raised in just my visible radius. I didn&#39;t stand up to see the aggregate total of folks who wandered in seemingly off the street with no idea of what they were attending. Later in the afternoon I mentioned this to &lt;a href=&quot;http://www.bileblog.org/&quot;&gt;Hani&lt;/a&gt; and we were theorizing about how that could happen. We proposed various reasons as to how someone could be attending a talk about a different programming language and yet have zero idea of that fact.&lt;br /&gt;&lt;br /&gt;Were they plants in the audience by Sun? Charles&#39; and Tom&#39;s relatives? Though I didn&#39;t see anyone with a &quot;We&#39;re Nutter about you Charles&quot; sign or anything like that. Though I did see one poor soul holding up a &quot;Vote for Sanjaya&quot; sign. I&#39;m pretty sure he had his hand raised during the &quot;Does anyone not know what ruby is?&quot; question. We finally settled on the notion that those people had lost a bet. &quot;OK if you don&#39;t get her number you have to go to the JRuby talk.&quot;&lt;br /&gt;&lt;br /&gt;Charles and Tom did a great job breaking down the features in ruby that would be new to java developers and what makes them interesting, modules, blocks, duck typing, etc. They went over rails and its pieces, calling ActiveRecord an &quot;ORM on steroids&quot;, which I can&#39;t say I agree with. I&#39;d call EJB3 or Hibernate or Kodo an ORM on steroids. ActiveRecord is just an ORM. &lt;br /&gt;&lt;br /&gt;I&#39;m really pleased with the great lengths the JRuby team has gone to make it easy to get working. Simply download the package and run jruby from the command line and pass it your ruby script.&lt;br /&gt;&lt;br /&gt;During the talk they provided a simple example of a JRuby script that was something like the following:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;require &#39;java&#39;&lt;br/&gt;&lt;br /&gt;a = java.util.ArrayList.new&lt;br /&gt;a &lt;&lt; &#39;all your code belong to jruby&#39;&lt;br /&gt;a.each do |el|&lt;br /&gt;  puts el&lt;br /&gt;end&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Pretty neat stuff. As a ruby developer that&#39;s as seamless as one could expect, and for java developers it&#39;s great insurance that they don&#39;t have to leave their world behind. While I didn&#39;t really have a look at perf on the simple example above appeared to be on par with the regular ruby VM.&lt;br /&gt;&lt;br /&gt;During the presentation they created a sample rails app and demonstrated migrations and scaffolding. First they showed the sample app running using webrick, and then they created a WAR file and deployed the same app to glassfish. Unfortunately they only showed the app load once and didn&#39;t actually use the app at all as I would&#39;ve liked to see if there was any noticeable performance change even for a single user in development mode, but still an impressive nonetheless. &lt;br /&gt;&lt;br /&gt;They demonstrated portions of the &quot;Goldspike&quot; project. This is the  project that contains the tools required to build a WAR file containing your rails app and all dependent gems. Basically you create a ruby file that describes your dependencies and you run the tool over your app and it builds a deployable WAR file that you just drop into glassfish, tomcat, etc.&lt;br /&gt;&lt;br /&gt;The only caveats that I can see right now are probably still performance and usage of native libraries, like RMagik. Charles indicated that you&#39;d run into problems with such a library and that there are plans to port them.&lt;br /&gt;&lt;br /&gt;Roaming around the pavilion floor I had a chat with the guys over at &lt;a href=&quot;http://www.appistry.com/&quot;&gt;Appistry&lt;/a&gt; about their application &quot;fabric&quot;. In a nutshell it&#39;s a deployment framework that allows you to scale your applications while you kick back and work on learning rails/grails/sails/snails or level your rogue in WoW. I also stopped by and spoke with &lt;a href=&quot;http://www.layer7tech.com/&quot;&gt;Layer 7 Technologies&lt;/a&gt; about their XML appliance. I have to admit before I went over and talked with them I didn&#39;t think I&#39;d find any of it interesting because I just lumped it in as part of the WS deathstar debacle but they were really pragmatic and intelligent guys. They clearly position their appliance as something for the enterprise and for folks that have fairly complex systems of web services that they need to secure and have a single point of management. Their product basically serves as an entry point and central managing system for an enterprise&#39;s services.&lt;br /&gt;&lt;br /&gt;After the day&#39;s activities I met up with some friends over on the Embarcadero for dinner. The conversation was lively, geeky, and engaging as always. One topic of note was the revelation of companies in London that look to outsource their development work to San Francisco because of how &quot;cheap&quot; it is compared to hiring developers in London. I sure hope they don&#39;t forget to account for the language barrier in their cost analysis ;-)&lt;br /&gt;&lt;br /&gt;After dinner we strolled over to the &lt;a href=&quot;http://www.tangosol.com&quot;&gt;Tangosol&lt;/a&gt; party where there was an open bar. Congrats Cam and his team for a well deserved exit and thanks for the great party! Wednesday night is the blogger party at Thirsty Bear and the Google party. I&#39;m on my way to a session to be named right now. Hopefully it&#39;ll be about something completely foreign to me so that someone else can shake their head in disbelief at my ignorance. </content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/1844874992329951741/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/05/javaone-2007-day-1-jruby-appistry.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/1844874992329951741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/1844874992329951741'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/05/javaone-2007-day-1-jruby-appistry.html' title='JavaOne 2007 Day 1 - JRuby, Appistry, Layer7, SF &amp;quot;outsourcing&amp;quot;, and shots at the Tangosol party'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-15047586790747851</id><published>2007-05-01T13:12:00.001-07:00</published><updated>2007-05-01T13:12:01.510-07:00</updated><title type='text'>Rails realities part 25.1 (Do what you say, but say the right thing)</title><content type='html'>After yesterday&#39;s post about fine grained column updates with update_attribute I was discussing the matter with &lt;a href=&quot;http://www.javarants.com&quot;&gt;Sam Pullara&lt;/a&gt; and &lt;a href=&quot;http://www.jroller.com/page/pcl&quot;&gt;Patrick Linskey&lt;/a&gt; with regards to how Hibernate and Kodo deal with these kinds of updates. &lt;br /&gt;&lt;br /&gt;First off as a reminder of the data and scenarios I&#39;m talking about:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;class Reservation &lt; ActiveRecord::Base&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;# end user action&lt;br /&gt;def edit_reservation&lt;br /&gt;  reservation = Reservation.find(params[:id])&lt;br /&gt;  reservation.update_attributes(params[:reservation])&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;# admin only action&lt;br /&gt;def confirm_reservation&lt;br /&gt;  reservation = Reservation.find(params[:id])&lt;br /&gt;  reservation.update_attribute(&#39;confirmed&#39;, true)&lt;br /&gt;end&lt;br /&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;The desire is to be able to update the &quot;confirmed&quot; field without saving the rest of the record. The update_attribute that is part of ActiveRecord::Base updates the field and saves the whole record which seems wrong. I wanted to be able to &quot;cheat&quot; and not have to add either optimistic concurrency or a new table to support the notion of confirming a reservation and only allowing an admin user to do so.&lt;br /&gt;&lt;br /&gt;Speaking with Patrick he said that Kodo doesn&#39;t allow for explicit partial object flushing as it is fraught with peril. He asserted that optimistic concurrency is the only way to go and it&#39;s really cheap. He actually went as far as to suggest always having an optimistic lock column on all tables. &lt;br /&gt;&lt;br /&gt;Yesterday I said that I felt it was too heavy handed but as I was lying in bed last night at my new apartment, kept awake by the unknown man living above me clearing his throat with great vigor every 20 minutes or so, just long enough intervals to doze off and be abruptly awoken at the next &quot;clearing&quot;, fun... What was I saying? Oh right, heavy handed optimistic concurrency. &lt;br /&gt;&lt;br /&gt;After thinking about it more I realized that Patrick was right (Wow imagine that, the guy who&#39;s been focused on O/R mapping for the past 6 years or so :-). Even doing fine grained updates like I talked about yesterday isn&#39;t a good solution to my particular problem and is probably something that you shouldn&#39;t be doing at all unless you know that you&#39;re never going to have concurrent editing (and we know how often application requirements change so this probably isn&#39;t a good assumption to make and bake into your app). I was so concerned with not forcing the end user to deal with OC errors and thinking &quot;well I just need to update this flag that&#39;s not edited by the user at all&quot;, that I failed to remember that because AR always saves all values that I still have a race condition, only the other way now, where a user could potentially change the &quot;confirmed&quot; value that I&#39;ve so carefully set with my tricked out update_attribute method.  &lt;br /&gt;&lt;br /&gt;So my choices really are:&lt;br /&gt;&lt;br /&gt;1) Add an optimistic lock to the table which has the undesired effect of possibly forcing a user to retry their edit, or&lt;br /&gt;2) Create a new table for the &quot;confirmed&quot; flag which would only be editable by the admin users.&lt;br /&gt;&lt;br /&gt;I think that for my case I&#39;m going to add a new table because I really don&#39;t think it&#39;s appropriate to either have end users retry an operation that should always work, nor do I think it&#39;s a good policy to just try again on their behalf if it fails the first time. The &quot;confirmed&quot; flag is really an admin function and only used internally to the company so while it feels like a bit much to create a table for just that flag I may have to, but will reevaluate if there&#39;s an appropriate design that&#39;s a little more practical and not so &quot;wasteful&quot;.&lt;br /&gt;&lt;br /&gt;Anyway, for the folks that are doing single field updates, don&#39;t believe that the patch I created is something that&#39;s going to safeguard you against concurrency because it won&#39;t. It&#39;s the wrong solution. The update_attribute ability doesn&#39;t even exist on other O/R mappers and I can see why more clearly now. They get around a problem like this by offering users the ability to define lock groups, where only certain fields are used for optimistic concurrency, and more. &lt;br /&gt;&lt;br /&gt;ActiveRecord isn&#39;t as sophisticated so if you&#39;re going to use it know your limitations in terms of what you should or shouldn&#39;t do when designing your schema as it relates to your app&#39;s requirements. So in the end it really doesn&#39;t matter that update_attribute saves the entire record by default because if you&#39;re desiring a fine grained update you&#39;re likely asking for trouble at some point. Time to unhack my hack :-) </content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/15047586790747851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/05/rails-realities-part-251-do-what-you.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/15047586790747851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/15047586790747851'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/05/rails-realities-part-251-do-what-you.html' title='Rails realities part 25.1 (Do what you say, but say the right thing)'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-5561618716683782950</id><published>2007-04-30T10:22:00.001-07:00</published><updated>2007-04-30T10:23:54.512-07:00</updated><title type='text'>Rails realities part 25 (Do what you say. updating activerecord update_attribute)</title><content type='html'>I&#39;ve been working on adding a data field or two on some of my user objects but these fields are really only ever editable by an administrator. You may argue that such fields belong in an entirely different table. Well in the interest of keeping things simple I chose to add it to the existing user object as it is directly applicable.&lt;br /&gt;&lt;br /&gt;Anyway, illustrating by example let&#39;s say I have a reservation system and after a user creates a reservation an admin user needs to perform some manual operations and then update the reservation as being confirmed. Meanwhile some attributes on this reservation are still editable by the end user. &lt;br /&gt;&lt;br /&gt;Ok so let&#39;s look at the active record API and we see there&#39;s a method called &quot;update_attribute&quot; that takes the name of the attribute and the value you&#39;d like to set for the attribute. &lt;br /&gt;&lt;br /&gt;Alright so I just call:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;reservation.update_attribute(&#39;confirmed&#39;, true)&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Right?&lt;br /&gt;&lt;br /&gt;Well yes that does indeed update the targeted attribute, BUT (and you knew there&#39;d be a but otherwise there&#39;s no blog post), it also saves the entire object which updates all attributes.&lt;br /&gt;&lt;br /&gt;Here&#39;s the active record code for update_attribute&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;      def update_attribute(name, value)&lt;br /&gt;        send(name.to_s + &#39;=&#39;, value)&lt;br /&gt;        save&lt;br /&gt;      end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;The send call of course sets the attribute value and save eventually boils down to this:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;      def update&lt;br /&gt;        connection.update(&lt;br /&gt;          &quot;UPDATE #{self.class.table_name} &quot; +&lt;br /&gt;          &quot;SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} &quot; +&lt;br /&gt;          &quot;WHERE #{self.class.primary_key} = #{quote(id)}&quot;,&lt;br /&gt;          &quot;#{self.class.name} Update&quot;&lt;br /&gt;        )&lt;br /&gt;        &lt;br /&gt;        return true&lt;br /&gt;      end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;As you can see update simply updates all attributes for the current object.&lt;br /&gt;The quoted_comma_pair_list simply takes the attribute values and builds up the SQL parameter list, e.g. &quot;id = 15, `confirmed` = 1&quot;, etc&lt;br /&gt;&lt;br /&gt;OK so what&#39;s the problem here? Well none if you never care about concurrent editing of the data. &quot;But what about optimistic/pessimistic concurrency?&quot; you ask. Indeed we could use either of those approaches to solve the race condition of two users editing this data simultaneously, but in this instance it&#39;s really too heavy handed and doesn&#39;t really fit the situation. &lt;br /&gt;&lt;br /&gt;As I mentioned at the outset we have a single column named &quot;confirmed&quot;, that we&#39;d like to have updated by an administrator. Updating this field would never conflict with a user editing the other fields for this object. Ideally what we&#39;d like is to have is some way to update a single attribute&#39;s value... hmm.... perhaps an instance method that when invoked only updates the specified attribute. Hmm... what would we call such a method? Oh, I know, &quot;update_attribute&quot;. Uh oh! Who smells an active record mixin patch? In the words of Matt Puppet &lt;a target=&#39;_new&#39; href=&quot;http://video.yahoo.com/video/play?vid=9b4155e4ff782eb8f77052c42c898b09.910357&amp;amp;vback=Studio&quot;&gt;&quot;I&#39;m about to hack a bitch&quot;&lt;/a&gt;. I don&#39;t think a plugin is the right thing here as I think this is a bug as opposed to a feature.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;# put in lib/active_record_ext/base.rb&lt;br /&gt;# append &quot;require &#39;active_record_ext/base&#39;&quot; to your config/environment.rb&lt;br /&gt; &lt;br /&gt;module ActiveRecord&lt;br /&gt;  class Base &lt;br /&gt;    # Updates a single attribute and saves the record. This is especially useful for boolean flags on existing records.&lt;br /&gt;    # Note: This method is overwritten by the Validation module that&#39;ll make sure that updates made with this method&lt;br /&gt;    # doesn&#39;t get subjected to validation checks. Hence, attributes can be updated even if the full object isn&#39;t valid.&lt;br /&gt;    def update_attribute(name, value)&lt;br /&gt;      send(name.to_s + &#39;=&#39;, value)&lt;br /&gt;      # safely escape the value before we update&lt;br /&gt;      atts = attributes_with_quotes(false)&lt;br /&gt;      connection.update(&lt;br /&gt;        &quot;UPDATE #{self.class.table_name} &quot; +&lt;br /&gt;        &quot;SET #{quoted_comma_pair_list(connection, {name =&gt; atts[name]})} &quot; +&lt;br /&gt;        &quot;WHERE #{self.class.primary_key} = #{quote(id)}&quot;,&lt;br /&gt;        &quot;#{self.class.name} Update&quot;&lt;br /&gt;      )&lt;br /&gt;      &lt;br /&gt;      return true&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;The above is my new implementation of &quot;update_attribute&quot; that performs as advertised. It will only update the specified column value for the given object. I haven&#39;t modified this in the rails codebase and run the tests to see if there&#39;s any breakage but I imagine anything that breaks as a result of this behavior change was using the API incorrectly to begin with as it means there would be reliance on the fact that an entire object save is performed when you update a single attribute value. I can&#39;t think of scenarios where this would be required behavior, please correct me if I&#39;m not thinking of them. &lt;br /&gt;&lt;br /&gt;So now when you add this patch you&#39;ll see &quot;UPDATE reservations SET `confirmed` = 1 WHERE id = 20&quot; instead of an update that includes all attributes.&lt;br /&gt;&lt;br /&gt;I did a search and sure enough there are some others that agree that the behavior change I&#39;ve prescribed is the correct thing to do:&lt;br /&gt;&lt;a href=&quot;http://dev.rubyonrails.org/ticket/8053&quot;&gt;http://dev.rubyonrails.org/ticket/8053&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There is also a recent &lt;a href=&quot;http://groups.google.com/group/rubyonrails-core/browse_thread/thread/e9e9763e96af7175?hl=en&quot;&gt;discussion&lt;/a&gt; on the rails core mailing list on this topic but mostly related to the lack of validation triggering for this call. On that very thread &lt;a href=&quot;http://www.marklunds.com/articles/one/333&quot;&gt;Peter Marklund&lt;/a&gt; discusses his need to write a custom method called &quot;update_column&quot; for the very same purpose I&#39;ve described here.&lt;br /&gt;&lt;br /&gt;Anyway, enjoy and happy updating.</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/5561618716683782950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/04/rails-realities-part-25-do-what-you-say.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/5561618716683782950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/5561618716683782950'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/04/rails-realities-part-25-do-what-you-say.html' title='Rails realities part 25 (Do what you say. updating activerecord update_attribute)'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-8814211665125982656</id><published>2007-04-28T11:01:00.001-07:00</published><updated>2007-04-28T11:05:25.211-07:00</updated><title type='text'>Rails realities part 24 (log files, the lies they tell and tuning MySQL)</title><content type='html'>I&#39;ve read from a couple of folks that the log file data isn&#39;t completely accurate. Well sometimes you really don&#39;t learn just how true something is until you learn it yourself the hard way. &lt;br /&gt;&lt;br /&gt;I&#39;ve been using a VPS provider and for the most part things have been pretty good. Uptime is good, throughput is good, etc. But unfortunately I was experiencing intermittent slowness with my app. And when I say slowness we&#39;re talking about going from X req/sec to 40+ seconds for a single request. The problem would appear suddenly, and with no increased traffic on my box, and then leave just as suddenly.&lt;br /&gt;&lt;br /&gt;With the help of my VPS provider we tracked down the slowness as being tied to heavy I/O usage by other users on the same machine. There were a few times where another user&#39;s xen instance (my host uses xen for virtualization) was completely pegged and hogging all the I/O. They would reboot that user&#39;s instance and suddenly my application would spring back to life.&lt;br /&gt;&lt;br /&gt;Looking at the logfile the time for rendering appeared to be responsible for the entire slowdown and the DB access time looked exactly the same as when the app was performing normally. &lt;br /&gt;&lt;br /&gt;After many weeks of on and off attempts at trying to figure out what&#39;s wrong and thinking that it was somehow related to fetching the template files from disk (even though they should be cached in memory), I believe that the problem may be finally solved with the help of &lt;a href=&quot;http://blog.evanweaver.com/&quot;&gt;Evan Weaver&lt;/a&gt;. I was on IRC and Evan overheard (overread?) me talking about maybe having to switch providers because of the inability to throttle I/O fairly among all users on a machine. &lt;br /&gt;&lt;br /&gt;He asked what was happening and after explaining he said he&#39;d seen this before and asked to see my MySQL configuration. I showed it to him and explained that I had taken one of the template configurations from the MySQL installation as a start. Well as it turns out that template configuration is way off in terms of memory allocation for InnoDB (I used the medium sized deployment template). &lt;br /&gt;&lt;br /&gt;&lt;img src = &quot;http://human-factors.arc.nasa.gov/ihi/research_groups/isis/McCandless/shuttlemeds.jpg&quot; ALT = &quot;Photo of the new Space Shuttle cockpit with the Multifunction Electronic Display System.&quot; height=250 width=333&gt;&lt;br /&gt;&lt;br /&gt;The MySQL configuration options are akin to the cockpit of the space shuttle (or so I&#39;m guessing) but like you&#39;ve seen in many a cartoon even with all those crazy switches and buttons there&#39;s always the one or two buttons that really do something important. Basically Evan took me aside and said &quot;Hey doc, see this big red button right here and this blue one here, just press those.&quot; For me those big buttons were:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;[mysqld]&lt;br /&gt;innodb_buffer_pool_size = 384M&lt;br /&gt;innodb_additional_mem_pool_size = 16M &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Those two were originally set to 16M and 2M respectively. I started with the &quot;my-medium.cfg&quot; template as it prescribed it for systems with 128MB of RAM that also ran a webserver. I figured &quot;well I also have mongrel processes as well as backgroundrb processes so this might be a good starting point for my 512MB VPS&quot;. Boy was that ever wrong.&lt;br /&gt;&lt;br /&gt;I also made a few modifications recommended by the &lt;a href=http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server-after-installation/trackback/&quot;&gt;MySQL performance blog&lt;/a&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;key_buffer = 16M&lt;br /&gt;myisam_sort_buffer_size = 8M&lt;br /&gt;thread_cache = 16&lt;br /&gt;table_cache = 256&lt;br /&gt;innodb_log_file_size = 64M&lt;br /&gt;innodb_log_buffer_size = 8M&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Since I&#39;ve made these changes (about 3 days ago now) there has been no I/O blocking slowdown. I&#39;m running the log file analysis tool &lt;a href=&quot;http://rubyforge.org/projects/rails-analyzer/&quot;&gt;pl_analyze&lt;/a&gt; to look for slow actions and it&#39;s been clean so I&#39;m hopeful that in the end MySQL running with too little memory allocated ends up being the culprit. It does make sense that this would be the case as MySQL would have to go to disk quite a bit since it&#39;s unable to cache much of anything and of course when the disk is getting slammed that&#39;s going to negatively impact performance. We&#39;ll see if this keeps up but I&#39;m optimistic that this was the problem. &lt;br /&gt;&lt;br /&gt;Unfortunately the production log file led me to draw some early and incorrect conclusions about where things were bottlenecking. So add another voice to &quot;the log file stats are inaccurate&quot; with an exclamation mark and further stating that it&#39;s not just req/sec that can&#39;t be trusted it&#39;s the breakdown of DB and rendering time as well. Time to look into &lt;a href=&quot;http://railsexpress.de/blog/articles/2007/04/01/new-railsbench-release-0-9-2&quot;&gt;railsbench&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/8814211665125982656/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/04/rails-realities-part-24-log-files-and.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/8814211665125982656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/8814211665125982656'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/04/rails-realities-part-24-log-files-and.html' title='Rails realities part 24 (log files, the lies they tell and tuning MySQL)'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-9134863115950032155</id><published>2007-04-28T08:34:00.001-07:00</published><updated>2007-04-28T08:36:11.471-07:00</updated><title type='text'>Best regulatory cost recovery fee ever!</title><content type='html'>I&#39;m in the market for a new mobile phone and today while I was shopping on Amazon I added a phone and plan to my cart. While browsing the items in my cart I saw the following link under my phone/plan entry:&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.amazon.com/Regulatory-Cost-Recovery-Fee/dp/B00020KCBK/ref=dp_return_1/102-0955861-5109717?ie=UTF8&amp;amp;n=301185&amp;amp;s=wireless&quot;&gt;http://www.amazon.com/Regulatory-Cost-Recovery-Fee/dp/B00020KCBK/ref=dp_return_1/102-0955861-5109717?ie=UTF8&amp;n=301185&amp;s=wireless&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now if only they&#39;d let you review some of the other fees that get tacked on to various utility bills and bank accounts.&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/9134863115950032155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/04/best-regulatory-cost-recovery-fee-ever.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/9134863115950032155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/9134863115950032155'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/04/best-regulatory-cost-recovery-fee-ever.html' title='Best regulatory cost recovery fee ever!'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-6912328040392400298</id><published>2007-04-23T10:50:00.001-07:00</published><updated>2007-04-23T10:51:29.112-07:00</updated><title type='text'>SVRuby Conf -&gt; JavaOne 2007 -&gt; RailsConf 2007</title><content type='html'>I&#39;m going on a conference bender here in late April to mid-May. This weekend was the &lt;a href=&quot;http://www.sdforum.org/SDForum/Templates/CalendarEvent.aspx?CID=2135&amp;amp;mo=4&amp;yr=2007&quot;&gt;2nd annual SV ruby conference&lt;/a&gt; which was a pretty good conference, despite the influx of vendors this year (SAP seems to run from conference to conference trying to convince people to use their stuff). The most interesting talks to me were Ezra&#39;s talk on merb and the Twitter scaling talk because they are both immediately applicable to me. Merb basically is a way to write parts of your app that require more speed and don&#39;t require all of rails, RSS feeds for example. It works as a mongrel handler which basically works exactly like a servlet in the Java world.&lt;br /&gt;&lt;br /&gt;It was great to finally put some faces with some of the names. There are really some very smart folks working in the ruby community and they are all very friendly and fun to hang out with. I&#39;m looking forward to &lt;a href=&quot;http://conferences.oreillynet.com/rails/&quot;&gt;RailsConf&lt;/a&gt; next month in Portland but next up for me is &lt;a href=&quot;http://www.sun.com/javaone&quot;&gt;JavaOne&lt;/a&gt; and how I&#39;m going is an interesting story.&lt;br /&gt;&lt;br /&gt;The other day I was pitched via my &lt;a href=&quot;http://www.pitchwire.com/&quot;&gt;PitchWire&lt;/a&gt; page (I have one of course but it&#39;s not because I consider myself an influencer and receive tons of PR inquiries, though perhaps times are a changin). It was somebody from Sun&#39;s PR department who presented me with an invitation to this year&#39;s JavaOne conference as a member of the press. I was pretty happy to receive the invite and immediately accepted. I thought for sure this would be the first time in 7 years that I would be unable to attend JavaOne but lady luck smiled upon me with a free invite. Regardless of the conference itself it&#39;s always fun to go and hang out at the parties :-)&lt;br /&gt;&lt;br /&gt;It&#39;s been quite awhile since I&#39;ve had the chance to see what&#39;s really new in the Java world and this is a good opportunity to see what&#39;s happening. Of course I&#39;m well aware of the &lt;a href=&quot;http://jruby.codehaus.org/&quot;&gt;jruby&lt;/a&gt; project and &lt;a href=&quot;http://headius.blogspot.com/&quot;&gt;watch&lt;/a&gt; with great interest as I&#39;m hopeful that the JVM becomes a higher performance deployment option for rails. Interestingly, a quick &lt;a href=&quot;http://www28.cplan.com/cc158/sessions_catalog.jsp?ilc=158-1&amp;amp;ilg=english&amp;isort=&amp;amp;isort_type=&amp;is=yes&amp;amp;amp;icriteria1=+&amp;icriteria2=+&amp;amp;icriteria7=+&amp;icriteria9=&amp;amp;icriteria8=ruby&amp;amp;icriteria3=&quot;&gt;search&lt;/a&gt; through the conference catalog for the word &quot;ruby&quot; yielded nearly a full conference schedule&#39;s worth of sessions to attend.&lt;br /&gt;&lt;br /&gt;Of course there are the obligatory sessions on Swing and threading as well as EJB3 and SOA. I&#39;ll probably end up in a few of the webapp sessions like Gavin and Bob&#39;s webbeans talk, I&#39;m looking forward to the advanced groovy as well as the various rails comparison sessions including what appears to be a real world case study of rails by a large company.&lt;br /&gt;&lt;br /&gt;So if you&#39;re there look for me. I&#39;ll wearing my press pass and walking around lookin for the hot story to blog or &lt;a href=&quot;http://twitter.com/kovacs&quot;&gt;twitter&lt;/a&gt; and basically playing the part of an influencer. I&#39;m also looking forward to meeting legitimate influencers and informing them of PitchWire and helping build the community further. The response we&#39;ve received thus far has been fantastic from both publicists and influencers.</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/6912328040392400298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/04/svruby-conf-javaone-2007-railsconf-2007.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/6912328040392400298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/6912328040392400298'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/04/svruby-conf-javaone-2007-railsconf-2007.html' title='SVRuby Conf -&gt; JavaOne 2007 -&gt; RailsConf 2007'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-117554228738826410</id><published>2007-04-02T12:31:00.000-07:00</published><updated>2007-04-03T11:58:17.936-07:00</updated><title type='text'>Play Ball! PitchWire&#39;s opening day</title><content type='html'>Today&#39;s opening day in MLB and while I&#39;m sure this is finally &quot;next year&quot; for my beloved Indians, today is also opening day for PitchWire. PitchWire is my latest business venture, a product that will help redefine the relationship between publicists and influencers (journalist, analysts, and bloggers).&lt;br /&gt;&lt;br /&gt;The basic premise is that influencers are pitched via email quite a bit and dealing with that volume of information is difficult for a couple of reasons:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;A large segment of email pitches (about 65%) are not relevant to where an influencer&#39;s interests lie.&lt;br /&gt;&lt;li&gt;Email is broken for managing processes, like the development of a story idea between two parties.&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;You can check it out here: &lt;a href=&quot;http://www.pitchwire.com&quot;&gt;http://www.pitchwire.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As you might imagine the site is built entirely on rails (1.1.6 at the moment) and makes use of some of the following wonderful plugins:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://technoweenie.stikipad.com/plugins/show/Acts+as+Attachment&quot;&gt;Acts as attachment&lt;/a&gt; (Soon to be attachment_fu for the s3 goodness)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://backgroundrb.rubyforge.org/&quot;&gt;Backgroundrb&lt;/a&gt; Ezra&#39;s fine background processing creation. I use it for processing incoming emails and file uploads.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://www.redhillonrails.org/&quot;&gt;Foreign Key Migrations&lt;/a&gt; Been using this one for awhile. Used it on LoanBack as well. Very handy.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://www.epiphyte.ca/code/live_tree.html&quot;&gt;Live tree&lt;/a&gt; This fantastic little plugin make displaying and selecting tree based data nice and easy. I ended up doing some javascript hacking to customize behavior I needed but this is a great starting point for anyone requiring a tree for their data.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://blog.codahale.com/2006/05/26/rails-plugin-rails_rcov&quot;&gt;Rails rcov&lt;/a&gt; Should be required for any rails project. In fact it should just come with rails. While rcov doesn&#39;t tell you the quality of your tests it does tell you &quot;hey buddy this section of code here... completely untested&quot;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://sean.treadway.info/svn/plugins/responds_to_parent/&quot;&gt;Responds to parent&lt;/a&gt;This little gem makes it nice and easy to perform file uploads and be able to remain on the same page and track progress and display updates.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://blog.seesaw.it/articles/2006/07/23/the-easiest-way-to-add-tabbed-navigation-to-your-rails-app&quot;&gt;Tabnav&lt;/a&gt; Nice simple plugin that makes it easy to add tab navigation to your app.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://code.google.com/p/sortable/&quot;&gt;Sortable&lt;/a&gt;A plugin that I extracted out of my work with PitchWire. It makes it pretty easy to get a sortable, searchable, filterable, table of data up in a few minutes. And not just for a single object you can traverse relations and sort by attributes on those objects as well. Here&#39;s my &lt;a href=&quot;http://javathehutt.blogspot.com/2006/11/rails-realities-part-20-sortable.html&quot;&gt;blog post&lt;/a&gt; about it.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;I&#39;m also using &lt;a href=&quot;http://developer.yahoo.com/yui/grids/&quot;&gt;YUI grids&lt;/a&gt; as the basis of my app&#39;s layout. It does a pretty good job of working the same across browsers. The only problem I&#39;ve run into really was IE6 and min-width which I managed to fix with a hack.&lt;br /&gt;&lt;br /&gt;I also make heavy use of a modified version of &lt;a href=&quot;http://particletree.com/features/lightbox-gone-wild/&quot;&gt;Lightbox gone wild&lt;/a&gt;. I&#39;m basically using this as a modal dialog for my app in numerous places instead of either going to a new page or showing an inline div which has it&#39;s problems when you&#39;re trying to edit form items. More about my usage in rails can be found &lt;a href=&quot;http://javathehutt.blogspot.com/2006/07/rails-realities-part-15-ajax-modal.html&quot;&gt;in this blog post&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;And finally I also use &lt;a href=&quot;http://tetlaw.id.au/view/blog/really-easy-field-validation-with-prototype&quot;&gt;really easy field validation with Prototype&lt;/a&gt; for my client side validation. It&#39;s really easy to add your own custom validations for the fields in your form. &lt;br /&gt;&lt;br /&gt;I&#39;ve blogged about some of the above in the past but I may get into a little more detail about how to extend and use some of these various plugins if you want to achieve some of the same results that I have in the PitchWire app. In the end there&#39;s certainly more ways than one to achieve some of what I&#39;ve done and in fact I may find that there may be a better way (perhaps using the YUI widget library more extensively) but as it is now I&#39;ve got all the pieces to a small app framework that allows me to easily whip up editable lists using dialogs as well as sortable, searchable, filterable, paginated tables. &lt;br /&gt;&lt;br /&gt;I looked into the various autogeneration projets (streamlined specifically) but at the time I started building my app nothing was really there yet for my needs. I suspect the landscape is much better these days and I&#39;ll have a look to see if there&#39;s anything out there that I can use in conjunction with or as a replacement for what I have now. </content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/117554228738826410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/04/play-ball-pitchwires-opening-day.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/117554228738826410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/117554228738826410'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/04/play-ball-pitchwires-opening-day.html' title='Play Ball! PitchWire&#39;s opening day'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6973124.post-117515723888635901</id><published>2007-03-29T02:33:00.000-07:00</published><updated>2007-03-29T02:33:59.183-07:00</updated><title type='text'>Installing Wordpress with MySQL 4.1 and higher</title><content type='html'>Some 5 minute install that was. Just finished installing Wordpress for our site&#39;s blog and it would&#39;ve been easier if I didn&#39;t have to build and install PHP though that wasn&#39;t hard. The harder part was the lack of information that came out of wordpress when the install script didn&#39;t work.&lt;br /&gt;&lt;br /&gt;Turns out that the password for the user I created in MySQL needed to be hashed in the &quot;old&quot; way for PHP 4.&lt;br /&gt;&lt;br /&gt;The way I figured out the problem was I created a PHP file in the root of my wordpress install that contained the following:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;?php&lt;br /&gt;$username = &quot;blog&quot;;&lt;br /&gt;$password = &quot;passowrd&quot;;&lt;br /&gt;$hostname = &quot;localhost&quot;;&lt;br /&gt;$dbh = mysql_connect($hostname, $username, $password) &lt;br /&gt;        or die(&quot;Unable to connect to MySQL&quot;);&lt;br /&gt;print &quot;Connected to MySQL&lt;br&gt;&quot;;&lt;br /&gt;// you&#39;re going to do lots more here soon&lt;br /&gt;mysql_close($dbh);&lt;br /&gt;?&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Running that page gave me:&lt;br /&gt;&lt;br /&gt;&quot;Client does not support authentication protocol requested by server; consider upgrading MySQL client&quot;&lt;br /&gt;&lt;br /&gt;OK so now we&#39;re getting somewhere. Googling that error eventually led me here:&lt;br /&gt;&lt;a href=&quot;http://www.digitalpeer.com/id/mysql&quot;&gt;http://www.digitalpeer.com/id/mysql&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;going to modify my blog user in the manner prescribed in that posting fixed me right up and my wordpress installation was done. So minus that hangup it really would&#39;ve been a 5 minute install.&lt;br /&gt;&lt;br /&gt;Anyhow, I know most folks reading here are probably using something like mephisto which I considered as well but I decided to go with wordpress for various reasons, one of which was that PHP is going to run a bit faster and take up less memory than a mongrel running rails. Then again nginx would take up much less than Apache but that&#39;s a battle for another day.</content><link rel='replies' type='application/atom+xml' href='http://javathehutt.blogspot.com/feeds/117515723888635901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://javathehutt.blogspot.com/2007/03/installing-wordpress-with-mysql-41-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/117515723888635901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6973124/posts/default/117515723888635901'/><link rel='alternate' type='text/html' href='http://javathehutt.blogspot.com/2007/03/installing-wordpress-with-mysql-41-and.html' title='Installing Wordpress with MySQL 4.1 and higher'/><author><name>Michael Kovacs</name><uri>http://www.blogger.com/profile/07385217126769341366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>