tag:blogger.com,1999:blog-112029782024-03-06T20:39:39.949-08:00Thinking on thinkingWelcome to my blog on thinking, software, design and intuition. I am collecting some thoughts here on thoughts I like.pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.comBlogger127125tag:blogger.com,1999:blog-11202978.post-36571024515808552302013-02-24T00:47:00.003-08:002013-02-24T00:48:31.907-08:00This blog has moved!<span style="font-size: x-large;"><b>My blog is now hosted via github pages, here: <a href="http://thinkingonthinking.com/">http://thinkingonthinking.com</a></b></span>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-47738675006435456962012-12-18T13:40:00.000-08:002012-12-18T13:48:05.294-08:00Some findings on using Jasmine for DOM feedback with Backbone and RequireJSIn my first attempts to develop frontend interactions with Backbone.js, I discovered some blind spots in my understanding of Backbone views. Especially, I find the different options to organize views with parent and child-views, as well as attaching views to DOM nodes difficult. A nice overview on Backbone pitfalls is given <a href="http://blog.8thlight.com/cymen-vig/2012/12/13/reflections-on-using-backbone-js.html">here</a>.
<br />
<br />
As in many programming matters, thinking about outcomes and tests can help to write better code. This is where <a href="http://jasminejs.org/">Jasmine</a> can help in the development of Backbone applications.
<br />
<br />
First, there are several options to run Jasmine:
<br />
<ul>
<li>The most common option for running Jasmine specs is by having your default web browser loading a test DOM (from e.g. <code>spec/index.html</code> or <code>spec/SpecRunner.html</code>). Within this option you can declare a number of JavaScript dependencies that contain the actual specs, and that will be executed as soon as the Jasmine execution is triggered (with <code>jasmine.getEnv().execute();</code> ).</li>
<li>Another option is to run Jasmine specs through <code>rake</code>. This option seems to be very popular in the Rails community; but as I am thinking more towards development of stand-alone frontend applications, I don't want to have a tight Rails coupling. I could not get <code>rake jasmine</code> to render my specs from the Backbone setup; so, I will postpone this approach for a while. Maybe someone of you has made some more successful experiments?
</li>
<li>
Another interesting attempt to get feedback from the DOM is to run Jasmine through a headless browser. PhantomJS comes naturally to mind in this context, and some interesting article is <a href="http://blog.jphpsf.com/2012/10/31/running-Jasmine-tests-with-Phantom-js-or-Webdriver/http://obtiva.com/blog/112-javascript-specs-with-jasmine-a-primer-for-rubyists-part-1">here</a>.
</li>
</ul>
<br />
<br />
As a first step to testing a Backbone application, I wanted to test some basic Backbone view properties. Now, one of the difficulties that I found was, how to actually load all dependencies into a browser with <code>SpecRunner.html</code> including RequireJS; and, execute some specs.
<br />
<br />
I found two approaches that work for me:
<br />
<br />
<h2>
1. Global declaration of backbone dependencies</h2>
References to JQuery, Underscore and BackboneJS can be declared in a global way in the <span style="font-family: Courier New, Courier, monospace; font-size: x-small;">SpecRunner.html</span> as follows:<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbQqSLZnhKAyZGCCwctk1knQwG5zw5OqphvrS0Kaq5E8tlsXKjFW-xsNaGNHkK5GHx0LFeMs06ObpUtG8WFq2NaHLoNm7t7dib4H7xOEXmcIIJyw5n2qqSKjJKcPdhudgRGgAN/s1600/Bildschirmfoto+2012-12-18+um+22.44.25.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="35" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbQqSLZnhKAyZGCCwctk1knQwG5zw5OqphvrS0Kaq5E8tlsXKjFW-xsNaGNHkK5GHx0LFeMs06ObpUtG8WFq2NaHLoNm7t7dib4H7xOEXmcIIJyw5n2qqSKjJKcPdhudgRGgAN/s400/Bildschirmfoto+2012-12-18+um+22.44.25.png" width="400" /></a></div>
<br />
<br />
This should give access to the Backbone library where you need them. It works good enough, but maybe it's useful to load your dependencies more in a dynamic way if your application grows. For this, the next option might be more interesting.<br />
<h2>
2. Loading Backbone dependencies with RequireJS</h2>
When using several dependencies (including custom views, collections, routers, etc.), requiring every module in the global scope of SpecRunner.html might result into increased editing efforts. Here is an attempt to re-use some module definitions with requirejs that could in principle be shared between your tests and the real application.<br />
<br />
First, to load dependencies with requirejs, the following lines are needed in the <span style="font-family: Courier New, Courier, monospace; font-size: x-small;">specrunner.html</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh265kMIuEUsg1GrAHSM1QsAGqhPKXGwz2t_U9RGyXU_iaZutC5DV8hUVqEsL_X3l6yg4fBEhLOkToRSRCUKDTtciGfYtXY75ezKNxKJjRoSDeMWXaMsh5XYvOEYOVw4snGjeYl/s1600/Bildschirmfoto+2012-12-18+um+22.46.25.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="43" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh265kMIuEUsg1GrAHSM1QsAGqhPKXGwz2t_U9RGyXU_iaZutC5DV8hUVqEsL_X3l6yg4fBEhLOkToRSRCUKDTtciGfYtXY75ezKNxKJjRoSDeMWXaMsh5XYvOEYOVw4snGjeYl/s400/Bildschirmfoto+2012-12-18+um+22.46.25.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
The first line refers to the <a href="https://github.com/scottburch/jasmine-require">jasmine-require project</a> by Scott Burch that helps to require dependencies from within specs. Some example how this can be used with a JavaScript framework is shown <a href="https://github.com/Patternslib/Patterns/blob/master/lib/requireHelper.js">here</a> from the Pattern JS project.<br />
<br />
With Backbone this might look like:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> requireDependencies(["underscore", "backbone"], function(_, Backbone) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> View = Backbone.View.extend({tagName: "li" });</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> view = new View();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> });</span><br />
<br />
<h2>
3. Other approaches</h2>
<br />
Another option to load dependencies with requirejs was described in <a href="https://groups.google.com/forum/?hl=en_US&fromgroups=#!searchin/jasmine-js/requireJS/jasmine-js/7HJYbi705PE/XkpLR2DwQ0sJ">this discussion</a> in the Jasmine user group by using <a href="https://github.com/mattfysh/testr.js"> testr.js</a> However, I did not understand yet, how this is better than the previous option. (Maybe someone wants to comment?)<br />
<br />
Last but not least, there is an interesting Jasmine setup with RequireJS <a href="https://github.com/peeter-tomberg/shortcut/blob/master/tests/runner.html">here</a> by Peter Toomberg's Shortcut project. This one does not require any additional setup declarations, but I did not yet look into this too much.<br />
<br />
<br />
<h2>
Conclusion</h2>
<br />
Before actually running a succesful Jasmine spec for a Backbone view, we need a library to actually match DOM nodes with expected values. The common library for doing this are the <a href="https://raw.github.com/velesin/jasmine-jquery/master/lib/jasmine-jquery.js">Jasmine-JQuery matcher</a>s These allow to express many things, among if the .<span style="font-family: Courier New, Courier, monospace;">el</span> property of a Backbone view actually match a DOM node as follows:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">View = Backbone.View.extend({tagName: "li" });</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> view = new View();</span><br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> it("has el property", function() {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> expect(view.el).toBe("li"); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> });</span><br />
<br />
<br />
My current setup can be found here:<span style="font-family: Courier New, Courier, monospace;"><a href="https://github.com/mulderp/backbone-require-test/tree/view_specs"> https://github.com/mulderp/backbone-require-test/tree/view_specs</a></span><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihd6QqmVUbH0oCDblvA9i0i3zwV2rsPW7sW9f307aoZqZZsjL3gR9cGO-KGruZCiWEhHWFF016aJdEdsMx4YUsvIrpGrrDuvSa5ujR3auY-Md2RLijTxa8T3nj1Ddrv5ruJYo8/s1600/Bildschirmfoto+2012-12-18+um+22.36.15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="52" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihd6QqmVUbH0oCDblvA9i0i3zwV2rsPW7sW9f307aoZqZZsjL3gR9cGO-KGruZCiWEhHWFF016aJdEdsMx4YUsvIrpGrrDuvSa5ujR3auY-Md2RLijTxa8T3nj1Ddrv5ruJYo8/s320/Bildschirmfoto+2012-12-18+um+22.36.15.png" width="320" /></a></div>
<br />
Well, so far my findings. Maybe they are helpful for others. I would be curious to hear what you think? How you approach testing of DOM nodes.pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-92070560660671443492012-12-14T15:04:00.001-08:002012-12-16T08:19:16.017-08:00Some new tools for asset heavy Rails applications
Nowadays mobile browsers and changing use cases for web applications, require programmers to understand detailed DOM abstractions (usually html5 tags, css, js) as well as API's that talk to a number of different client setups. Although Ruby-on-Rails has brought us a long way to easily meet our business goals, I had the feeling to be stuck when it came to use Backbone with Rails.
<br/>
<br/>
There is Sprockets; and as long as I work with JQuery and use Twitter Bootstrap as default assets, Sprockets worked nicely: Sprockets gives some nice abstractions to bundle external asset dependencies, but if you want to develop your own client-side assets (e.g. Backbone programming and work with a Sass precompiler and Compass) Sprockets has some learning curve, and debugging asset problems is often painful. Also, for client-side development dealing with problems through a Rails stack is in my opinion not so ideal.
<br/>
<br/>
Now, over the last months, I've found some options for a new toolchain that allows a better combination of client- and server-side programming. Here are my findings:
<br/>
<br/>
<h3>Rake-Pipeline</h3>
<br />
I've discovered this tool shortly after the great <a href="http://baruco.org/">Baruco conference 2012</a> in Barcelona. After talks from <a href="https://github.com/joshk">Josh Kalderimis</a> and <a href="https://github.com/rkh">Konstantin Haase</a> on software development at Travis, it was a nice discovery to see how Travis manages a modular <a href="http://github.com/travis-ci/travis-assets.git">asset repository</a>. The tool that makes this work is: <b><a href="https://github.com/livingsocial/rake-pipeline">rake-pipeline</a></b>. Here some background information on <a href="https://github.com/livingsocial/rake-pipeline">rake-pipeline</a>:
<ul>
<li> <pre>
The Assetfile
</pre> defines how precompilers, concat and copy commands can be combined to generate your assets as needed from a bunch of asset source files.
</li>
<li>
<pre>
rakep build
</pre>
This command reads the Assetfile definition and performs the actions on the sources. It's the asset build step so to say.
</li>
<li>
<pre>
rakep server
</pre>
Now, when developing your client-side assets, you actually don't need to run rakep build from the command line. <b>rakep server</b> gives you a Sinatra server that nicely serves assets as they change during development.
</li>
<li>
Also, as a nice debugger for rake-pipeline, is a minimalistic Python webserver <b>python -m SimpleHTTPServer</b> that directly can serve all your files from the directory where you are in (e.g. /public). Quite handy if you just need some server, for quick-and-dirty browser debugging and experimentation.
</ul>
So far about building assets, next about serving data that assets want... we'll move on to:
<br />
<br />
<h3><a href="https://github.com/rails-api/rails-api">Rails-Api</a></h3>
<br />
Some weeks ago at <a href="http://rupy.eu/">Rupy in Brno</a>, there was a great melting pot of Ruby, Python and JavaScript programmers, and if you were looking for the lowest common denominator, it might have been JSON and REST. Now, there is some discussion recently headed by <a href="http://designinghypermediaapis.com/">Steve Klabnik</a> on how to interprete Roy Fielding's ideas for modern Rails applications, but in this context, some nice tools are ready for use: The <a href="https://github.com/rails-api/rails-api">Rails-Api</a> stack (and <a href="https://github.com/rails-api/active_model_serializers">ActiveSerializer</a>)
<br />
<br />
The Rails-Api removes the Rails ERB templates and Sprockets from your application. This is nice, because your Rack stack becomes lighter, and you can focus on the thing that matters: Serving data to clients. From first experiments, Rails-API combines very nicely with rake-pipeline. As you can see from my <a href="https://github.com/mulderp/rails-api-backbone">demo-project</a>, the Rails app just servers JSON to client-side code that is built with rake-pipeline from the /source directory.
<br />
<br />
<br />
<h3>Backbone.js, Underscore.js and Require.js</h3>
<br />
Last but not least, for my application design, I want to use a JS framework that allows to structure the interaction with the DOM and with the end-user. This framework is Backbone.js - but maybe first, a step back.
<br />
<br />
As a Ruby programmer, you think JavaScript has some problems: Incompatible browsers with different language implementations, as well as language constructs that leave you alone quite fast. At least part of the language problems are solved by JQuery and Underscore.js (which reminds on Ruby, see the collection stuff and enumerator constructs at <a href="http://underscorejs.org/"> underscorejs.org </a>
<br />
<br />
For the rest, a lot of folks from the Node.js community is an example of disruptive innovation at work; especially it is interesting to see, that the JS community nowadays has a modular requirement setup to manage dependencies: <a href="http://requirejs.org/">require.js</a>. In my view, this will make fancy browser (and maybe one day server) programming fun again.
<br />
<br />
What you need to know as Rails programmer, <a href="http://requirejs.org/">Require.js</a> injects dependencies where they are needed, and as such prevents problems in the global scope. Additionally, you can inject HTML templates into your JS modules, which is very nice too. I'll need to explore this, but you can actually take your Rails ERB templates and inject them 1-1 to Backbone templates, where you need them. Some ideas behind this technique are discussed by Thomas Davis, <a href="http://backbonetutorials.com/">here</a>. A boilerplate for backbone and require-js is <a href="https://github.com/thomasdavis/backbonetutorials/tree/gh-pages/examples/modular-backbone">here</a>. Another nice overview on Backbone development is <a href="https://www.youtube.com/watch?v=PqtYcHyyWJA">here</a> and <a href="http://kilon.org/blog/2012/08/build-backbone-apps-using-requirejs/">here (Backbone and Require.js)</a>.
<br />
<br />
That's all for now.
<br />
<br />
Here some references to my <a href="https://github.com/mulderp/rails-api-backbone">Rake-Pipeline-Rails-Api-BackboneJS-RequireJS experiment</a>. I hope to share some small screencasts soon, to show you why this toolchain is cool. At least for me, these tools make me #happy.pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com2tag:blogger.com,1999:blog-11202978.post-3846101059062609082012-12-10T13:11:00.003-08:002012-12-17T02:25:48.286-08:00An experiment with Vagrant and Neo4JThe RuPy conference 2012 in Brno was very inspiring! Especially, there were some interesting talks on databases and scalable approaches to web development:<br />
<div>
<br /></div>
<div>
* First, the ArangoDB team from Cologne set the tone why #nosql matters (see <a href="http://www.arangodb.org/">http://www.arangodb.org/ </a>) . The triAGENS team has written a database which mixes elements from MongoDB and graph databases. The shell of Arangodb looks very clean, and additionally, the system is based on C++ (= integrates with V8 JS engine and MRuby). </div>
<div>
<br /></div>
<div>
* Another interesting talk was by Mitchell Hashimoto. He showed how Vagrant came into place, and why using isolated, virtual environments make sense for web integration. Some slides (not from Rupy) about this are here <a href="http://slideshare.net/mitchellh/sf-devops-introducing-vagrant">slideshare.net/mitchellh/sf-devops-introducing-vagrant</a></div>
<div>
<br /></div>
<div>
* Andreas Ronge gave a very nice talk on what graphs can do, and SQL can't (well, it can, but not nicely ... ) I can't find his slides from RuPy right now, but he maintains a great blog on Neo4J here: <a href="http://maxdemarzi.com/">http://maxdemarzi.com/ </a>Also, these slides are interesting: <a href="http://slideshare.net/andreasronge/neo4jrb">slideshare.net/andreasronge/neo4jrb</a></div>
<div>
<br /></div>
<div>
So, ok, coming home to Munich with all these interesting thoughts in my mind, it was clear, that I had to start playing with graph databases in isolated environments for new kind of web applications. Fortunately, I had great input for my learnings from Jorge Bianquetti and <a href="http://www.nathenharvey.com/">Nathen Harvey</a>.</div>
<div>
<br /></div>
<div>
First about Vagrant and VirtualBox. It takes a bit of time to download virtual machines, but it's not too difficult to get going. The single, most important command might be:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ vagrant init</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: inherit;">This creates an environment for setting up a virtual machine. It's very cool, because now, you can imagine to setup an Ubuntu, Debian, CentOS, or whatever system, and vagrant will try to go ahead, download or copies the VM and prepares it just that you can use it.</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">Ok, not quite, since next, you must tell Vagrant where to download the box; you do it in the Vagrantfile, e.g.:</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<pre style="background-color: white; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; border: 1px solid rgb(204, 221, 238); color: #444444; font-family: monospace, sans-serif; font-size: 28px; font: inherit; line-height: 35px; margin-bottom: 1em; padding: 1em; position: relative; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word; z-index: auto;"><code style="border: 0px; color: lightslategrey; font-family: monospace, sans-serif; font-size: 28px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">config.vm.box = "opscode-ubuntu-12.04"
config.vm.box_url = "https://opscode-vm.s3.amazonaws.com/vagrant/boxes/opscode-ubuntu-12.04.box" </code></pre>
</div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
It's the standard Ubuntu box from Opscode right now.</div>
<div>
Just do a:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ vagrant up</span></div>
<div>
<br /></div>
<div>
and you would have an Ubuntu box running.</div>
<div>
<br /></div>
<div>
Well, we were charmed by graph databases, weren't we? Ok, so, let's go ahead and add the setup for Neo4J. Some googling gives, that we have a Neo4J cookbook here: <a href="https://github.com/michaelklishin/neo4j-server-chef-cookbook">https://github.com/michaelklishin/neo4j-server-chef-cookbook</a></div>
<div>
<br /></div>
<div>
Hmm.. in this stage, we actually decided already for chef-solo. There is chef-solo and chef-server, and if you want to understand the difference, I suggest you look here: <a href="http://www.nathenharvey.com/blog/2012/12/07/learning-chef-part-2/">http://www.nathenharvey.com/blog/2012/12/07/learning-chef-part-2/</a></div>
<div>
<br /></div>
<div>
Chef-server is the approach you want to use in production. Chef-solo is the approach for quick-and-dirty experiments, like we do here. So, let's assume, chef-solo is ok, and we just need to get the cookbooks dependencies right. Luckily, we have a tool for this: <span style="font-family: Courier New, Courier, monospace;">chef-librarian</span>.</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ chef-librarian init</span></div>
<div>
<br /></div>
<div>
This gives you a Cheffile. It's similar to a Gemfile if you are used to Ruby.</div>
<div>
Let's throw in the Neo4J dependency here:</div>
<div>
<br /></div>
<div>
<pre style="background-color: white; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; border: 1px solid rgb(204, 221, 238); color: #444444; font-family: monospace, sans-serif; font-size: 28px; font: inherit; line-height: 35px; margin-bottom: 1em; padding: 1em; position: relative; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word; z-index: auto;"><code style="border: 0px; color: lightslategrey; font-family: monospace, sans-serif; font-size: 28px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">cookbook 'apt'
cookbook 'neo4j-server', :git => 'http://github.com/michaelklishin/neo4j-server-chef-cookbook'</code></pre>
</div>
<div>
<br /></div>
<div>
And now, similar to <span style="font-family: Courier New, Courier, monospace;">bundle install,</span> we run <span style="font-family: Courier New, Courier, monospace;">librarian-chef install</span></div>
<div>
<br /></div>
<div>
Last, but not least, we need to tell our VM that interaction with chef-solo is needed. You'll do this by adding something into the <span style="font-family: Courier New, Courier, monospace;">Vagrantfile</span> :</div>
<div>
<br /></div>
<div>
<pre style="background-color: white; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; border: 1px solid rgb(204, 221, 238); color: #444444; font-family: monospace, sans-serif; font-size: 28px; font: inherit; line-height: 35px; margin-bottom: 1em; padding: 1em; position: relative; vertical-align: baseline; white-space: pre-wrap; word-wrap: break-word; z-index: auto;"><code style="border: 0px; color: lightslategrey; font-family: monospace, sans-serif; font-size: 28px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = "cookbooks"
chef.add_recipe "apt"
chef.add_recipe "neo4j-server::tarball"
end</code></pre>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Cool, now we only need to build our server, since our ingredients are prepared, and chef is ready for cooking. The magic command is:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ vagrant up</span></div>
<div>
<br /></div>
<div>
You should see something like: </div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">[2012-12-10T20:33:58+00:00] INFO: *** Chef 10.14.4 ***</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">[2012-12-10T20:33:59+00:00] INFO: Setting the run_list to ["recipe[apt]", "recipe[neo4j-server::tarball]"] from JSON</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">[2012-12-10T20:33:59+00:00] INFO: Run List is [recipe[apt], recipe[neo4j-server::tarball]]</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">[2012-12-10T20:33:59+00:00] INFO: Run List expands to [apt, neo4j-server::tarball]</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">[2012-12-10T20:33:59+00:00] INFO: Starting Chef Run for vagrant.vm</span></div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
This takes a while.... </div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Eventually, you end up successfully, and you can do:</div>
<div>
<br /></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;">$ vagrant ssh</span></div>
<div>
<br /></div>
<div>
Now, your VM has Neo4J running on it, and if you enable port forwarding in Vagrant, you might even go to: localhost:7474 and enjoy your fresh Neo4J server.</div>
<div>
<br /></div>
<div>
Some References:</div>
<div>
<br /></div>
<div>
<h3 style="border: 0px; font-family: 'Hoefler Text', Constantia, Palatino, 'Palatino Linotype', 'Book Antiqua', Georgia, serif; font-size: 1.4375em; font: inherit; margin: 0px 0px 0.30435em; padding: 0px; vertical-align: baseline;">
Chef and Neo4J</h3>
<ul style="border: 0px; color: #444444; font-family: 'Gill Sans', 'Gill Sans MT', Calibri, sans-serif; font-size: 28px; font: inherit; line-height: 35px; margin: 0px 0px 1em 2em; padding: 0px; vertical-align: top;">
<li style="border: 0px; font-size: 28px; font: inherit; margin: 0px; padding: 0.25em 0px; vertical-align: middle;">Vimeo screencast: <a href="https://vimeo.com/55085049" style="-webkit-tap-highlight-color: rgb(255, 255, 255); color: #559999; text-decoration: initial;">https://vimeo.com/55085049</a>, see: </li>
<code>
<iframe allowfullscreen="allowfullscreen" frameborder="0" height="281" mozallowfullscreen="mozallowfullscreen" src="http://player.vimeo.com/video/55085049?badge=0" webkitallowfullscreen="webkitallowfullscreen" width="500"></iframe> <a href="http://vimeo.com/55085049">Screencast Install Neo4j-server with Chef</a> from <a href="http://vimeo.com/user15074526">Patrick Mulder</a> on <a href="http://vimeo.com/">Vimeo</a>.<br />
</code>
</ul>
<div>
<span style="color: #444444;"><span style="line-height: 35px;"><a href="http://www.blogger.com/"></a><span id="goog_429538172"></span><span id="goog_429538173"></span><br /></span></span></div>
<ul style="border: 0px; color: #444444; font-family: 'Gill Sans', 'Gill Sans MT', Calibri, sans-serif; font-size: 28px; font: inherit; line-height: 35px; margin: 0px 0px 1em 2em; padding: 0px; vertical-align: top;">
<li style="border: 0px; font-size: 28px; font: inherit; margin: 0px; padding: 0.25em 0px; vertical-align: middle;">Git repo: <a href="https://github.com/mulderp/chef-neo4j" style="-webkit-tap-highlight-color: rgb(255, 255, 255); color: #559999; text-decoration: initial;">https://github.com/mulderp/chef-neo4j</a></li>
</ul>
<h3 style="border: 0px; font-family: 'Hoefler Text', Constantia, Palatino, 'Palatino Linotype', 'Book Antiqua', Georgia, serif; font-size: 1.4375em; font: inherit; margin: 0px 0px 0.30435em; padding: 0px; vertical-align: baseline;">
Chef basic steps with Nathen Harvey from Opscode</h3>
<ul style="border: 0px; color: #444444; font-family: 'Gill Sans', 'Gill Sans MT', Calibri, sans-serif; font-size: 28px; font: inherit; line-height: 35px; margin: 0px 0px 1em 2em; padding: 0px; vertical-align: top;">
<li style="border: 0px; font-size: 28px; font: inherit; margin: 0px; padding: 0.25em 0px; vertical-align: middle;"><a href="http://www.nathenharvey.com/blog/2012/12/06/learning-chef-part-1/" style="-webkit-tap-highlight-color: rgb(255, 255, 255); color: #559999; text-decoration: initial;">Learning Chef Part 1</a></li>
<a href="http://www.nathenharvey.com/blog/2012/12/06/learning-chef-part-1/" style="-webkit-tap-highlight-color: rgb(255, 255, 255); color: #559999; text-decoration: initial;"></a>
<li style="border: 0px; font-size: 28px; font: inherit; margin: 0px; padding: 0.25em 0px; vertical-align: middle;"><a href="http://www.nathenharvey.com/blog/2012/12/06/learning-chef-part-1/" style="-webkit-tap-highlight-color: rgb(255, 255, 255); color: #559999; text-decoration: initial;"></a><a href="http://www.nathenharvey.com/blog/2012/12/07/learning-chef-part-2/" style="-webkit-tap-highlight-color: rgb(255, 255, 255); color: #559999; text-decoration: initial;">Learning Chef Part 2</a></li>
<li><a href="http://www.nathenharvey.com/blog/2012/12/14/learning-chef-part-3/">Learning Chef Part 3</a></li>
</ul>
</div>
<div>
<br /></div>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-77643804214758203082012-04-16T13:18:00.002-07:002012-04-16T23:47:57.533-07:00<b>Small tutorial to using backbonejs with Rails and Backbone-on-Rails-Gem</b><br />
<br />
A demo Todo explanation with the Backbone-on-Rails gem, that is the background of this discussion, is ready for download here: <a href="https://github.com/mulderp/Backbone-on-Rails-todoDemo">https://github.com/mulderp/Backbone-on-Rails-todoDemo</a><br />
<br />
<b>1. From server-side to client-side programming</b><br />
<br />
The Rails framework is well known for its nice interaction of views, controllers and models. How these components work with HTTP and a database, is typically explained using a blog application. Client-side programming poses slightly different programming problems. Client-side programming is influenced by intricacies of web browsers and the DOM, which includes presentation details (HTML/CSS) and logic (Javascript). Similarly as JQuery provides a better API to manipulate simple structues in the DOM, the goal of Backbone is to provide a language that facilitates so called "data-driven programming", where a high amount of data changes and events in the DOM are becoming easier to deal with on the client-side.<br />
<br />
<b>2. Entering client-side programming</b><br />
Typically, client-side programming is explained with the help of a Todo application. There is great demo of a Todo application from <a href="http://jgn.me/">Jérôme Gravel-Niquet</a> , here:<br />
<br />
<a href="http://documentcloud.github.com/backbone/examples/todos/index.html">http://documentcloud.github.com/backbone/examples/todos/index.html</a><br />
<br />
The HTML of a Todo-List is rather simple, and consist of a 'list' that contains a number of 'todos'. For those, who are new to client-side programming, a different toolset is helpful in solving programming problems. These tools and debugging tricks are:<br />
<br />
<br />
<ul>
<li>jsfiddle: An interactive sandbox to play with HTML, CSS and Javascript code. Libraries, such as backbone, can be included too</li>
<li>jslint: This tools helps in finding errors in Javascript or JSON data</li>
<li>the browser console like firebug in Firefox or in the web developer tools of Chrome: The console helps in evaluating small pieces of code and variables, and breakpoints can help to understand which context and scope is currently active.</li>
<li>console-log: With the console.log() function in Javascript, it's possible to monitor the correct flow of data in the application</li>
<li>http://js2coffee.org/ : When using coffeescript, as is advised from Rails 3.1 on, it's helpful to understand the conversion of coffeescript into Javscript</li>
</ul>
<br />
<br />
<br />
<b>3. Fetching data from the server</b><br />
The main mechanism in backbone to fetch data is by extending a Backbone.Collection For a todo list, where 'todos' should be fetched from the server, or written to the server, a Todos collection might look like this:<br />
<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">class BackboneOnRailsTodo.Collections.Todos extends Backbone.Collection </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> model: BackboneOnRailsTodo.Models.Todo</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> url: '/todos'</span><br />
<br />
<br />
The important piece here is the 'url'. Coming from a Rails environment, where an 'url' is only defined in the router, this might be a bit confusing, however, 'routes' in Backbone have a different usage, namely to interact with a client-side URL that is marked by a hashtag (e.g. http://mydomain/todos#list ). As a first test, to see that your collection is working, you can use the browser console and fetch some simple todo json from the server.<br />
<br />
This could look like this:<br />
<br />
<br />
<div class="console-user-command console-adjacent-user-command-result" style="background-color: white; border-bottom-color: initial; border-bottom-style: none; border-bottom-width: initial; box-sizing: border-box; font-family: Menlo, monospace; font-size: 11px; margin-left: 24px; min-height: 16px; padding-bottom: 1px; padding-left: 0px; padding-right: 22px; padding-top: 1px; position: relative;">
<span class="console-message-text source-code" style="box-sizing: border-box; color: #0080ff; white-space: pre-wrap;">todos = new BackboneOnRailsTodo.Collections.Todos()</span></div>
<div class="console-message console-log-level console-user-command-result" style="background-color: white; border-bottom-color: rgb(240, 240, 240); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; font-family: Menlo, monospace; font-size: 11px; margin-left: 24px; min-height: 16px; padding-bottom: 1px; padding-left: 0px; padding-right: 22px; padding-top: 1px; position: relative;">
<span class="console-message-text source-code" style="box-sizing: border-box; white-space: pre-wrap;"><span style="box-sizing: border-box;"><span class="console-formatted-object source-code" style="box-sizing: border-box; display: inline-block; position: relative; vertical-align: top;"></span></span></span><br />
<div class="section" style="box-sizing: border-box; margin-bottom: 0px !important; margin-left: 12px !important; margin-right: 0px !important; margin-top: 0px !important; position: static;">
<div class="header monospace" style="-webkit-background-clip: padding; -webkit-background-origin: padding; background-image: none; border-bottom-style: none; border-color: initial; border-image: initial; border-left-style: none; border-right-style: none; border-top-style: none; border-width: initial; box-sizing: border-box; min-height: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 8px; padding-top: 0px; white-space: nowrap;">
<div class="subtitle" style="box-sizing: border-box; float: right; margin-left: 5px; max-width: 55%; overflow-x: hidden; overflow-y: hidden; text-overflow: ellipsis;">
</div>
<div class="title" style="box-sizing: border-box; line-height: 18px; white-space: normal; word-wrap: break-word;">
<span class="console-message-text source-code" style="box-sizing: border-box; white-space: pre-wrap;"><span style="box-sizing: border-box;"><span class="console-formatted-object source-code" style="box-sizing: border-box; display: inline-block; position: relative; vertical-align: top;">Todos</span></span></span></div>
</div>
</div>
<span class="console-message-text source-code" style="box-sizing: border-box; white-space: pre-wrap;"><span style="box-sizing: border-box;"><span class="console-formatted-object source-code" style="box-sizing: border-box; display: inline-block; position: relative; vertical-align: top;">
</span></span></span></div>
<div class="console-user-command console-adjacent-user-command-result" style="background-color: white; border-bottom-color: initial; border-bottom-style: none; border-bottom-width: initial; box-sizing: border-box; font-family: Menlo, monospace; font-size: 11px; margin-left: 24px; min-height: 16px; padding-bottom: 1px; padding-left: 0px; padding-right: 22px; padding-top: 1px; position: relative;">
<span class="console-message-text source-code" style="box-sizing: border-box; color: #0080ff; white-space: pre-wrap;">todos.fetch()</span></div>
<div class="console-message console-log-level console-user-command-result" style="background-color: white; border-bottom-color: rgb(240, 240, 240); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; font-family: Menlo, monospace; font-size: 11px; margin-left: 24px; min-height: 16px; padding-bottom: 1px; padding-left: 0px; padding-right: 22px; padding-top: 1px; position: relative;">
<span class="console-message-text source-code" style="box-sizing: border-box; white-space: pre-wrap;"><span style="box-sizing: border-box;"><span class="console-formatted-object source-code" style="box-sizing: border-box; display: inline-block; position: relative; vertical-align: top;"></span></span></span><br />
<div class="section" style="box-sizing: border-box; margin-bottom: 0px !important; margin-left: 12px !important; margin-right: 0px !important; margin-top: 0px !important; position: static;">
<div class="header monospace" style="-webkit-background-clip: padding; -webkit-background-origin: padding; background-image: none; border-bottom-style: none; border-color: initial; border-image: initial; border-left-style: none; border-right-style: none; border-top-style: none; border-width: initial; box-sizing: border-box; min-height: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 8px; padding-top: 0px; white-space: nowrap;">
<div class="subtitle" style="box-sizing: border-box; float: right; margin-left: 5px; max-width: 55%; overflow-x: hidden; overflow-y: hidden; text-overflow: ellipsis;">
</div>
<div class="title" style="box-sizing: border-box; line-height: 18px; white-space: normal; word-wrap: break-word;">
<span class="console-message-text source-code" style="box-sizing: border-box; white-space: pre-wrap;"><span style="box-sizing: border-box;"><span class="console-formatted-object source-code" style="box-sizing: border-box; display: inline-block; position: relative; vertical-align: top;">Object</span></span></span></div>
</div>
</div>
<span class="console-message-text source-code" style="box-sizing: border-box; white-space: pre-wrap;"><span style="box-sizing: border-box;"><span class="console-formatted-object source-code" style="box-sizing: border-box; display: inline-block; position: relative; vertical-align: top;">
</span></span></span></div>
<br />
<br />
<br />
Note, the 'new' and '()' in the statement above are important, because otherwise, you get some wrongly initalized object. You can then fill your collection, with todos.fetch()<br />
<br />
<br />
<b>4. Rendering data with help of views and templates</b><br />
Once, data is available, render it with help of views<br />
<br />
a) Views are some kind of containers, where you put data and recipes (templates), how to render the data. In the Backbone-on-Rails gem, you can easily use the ECO type template, which is some kind of ERB in the coffeescript context. Note, you must address view variables with help of @ from the view, like so:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> <%= @todo.get('content') %></span><br />
<br />
<br />
b) Views must be initialized with a model or collection hash, typically looking like this:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> view = new BackboneOnRailsTodo.Views.TodoListIndex(collection: @todos) </span><br />
<br />
c) Views can be rendered, and for this, the render() function is called together with .el(), that actually gives the HTML of the rendered element<br />
<br />
d) In views, unlike as in Ruby, there is not much syntactic sugar by default. A function like 'each' is given by the underscore library, but it's even easier to use the construct for .. in from backbone<br />
<br />
<br />
<b>5. When to render views?</b><br />
<br />
a) The rendering of view can easy be tested for development purposes, by using the browser console.<br />
preload / 'reset' function<br />
<br />
As the rendering of a view, needs to have a model or collection as input, a collection must be initialized first:<br />
<br />
<span style="background-color: white; font-family: Menlo, monospace; font-size: 11px; white-space: pre-wrap;">todos = new BackboneOnRailsTodo.Collections.Todos()</span><br />
<span style="background-color: white; font-family: Menlo, monospace; font-size: 11px; white-space: pre-wrap;">todos.fetch()</span><br />
<span style="background-color: white; font-family: Menlo, monospace; font-size: 11px; white-space: pre-wrap;"><br /></span><br />
<span style="background-color: white; font-family: Menlo, monospace; font-size: 11px; white-space: pre-wrap;">Then, </span><br />
<span style="background-color: white; font-family: Menlo, monospace; font-size: 11px; white-space: pre-wrap;"><br /></span><br />
<span style="background-color: white; font-family: Menlo, monospace; font-size: 11px; white-space: pre-wrap;">view = new BackboneOnRailsTodo.Views.TodoListIndex({collection: todos})</span><br />
<br />
The rendering of a view can be tested with<br />
<br />
view.render()<br />
<br />
b) In our Todo application we work with 2 views. Similar to the demo Todo app by Jérôme NG as above:<br />
<div class="webkit-line-content" style="background-color: white; box-sizing: border-box; padding-left: 2px;">
<br /></div>
<div class="webkit-line-content" style="-webkit-text-size-adjust: none; background-color: white; box-sizing: border-box; font-family: Menlo, monospace; font-size: 11px; line-height: 13px; padding-left: 2px; white-space: pre;">
<span class="webkit-javascript-comment" style="box-sizing: border-box; color: #007400;"> // Todo Item View --></span><span style="color: #007400;"> The DOM element for a todo item...</span></div>
<div class="webkit-line-content" style="-webkit-text-size-adjust: none; background-color: white; box-sizing: border-box; font-family: Menlo, monospace; font-size: 11px; line-height: 13px; padding-left: 2px; white-space: pre;">
<span class="webkit-javascript-keyword" style="box-sizing: border-box; color: #aa0d91;"> var</span> <span class="webkit-javascript-ident" style="box-sizing: border-box;">TodoView</span> = <span class="webkit-javascript-ident" style="box-sizing: border-box;">Backbone</span>.<span class="webkit-javascript-ident" style="box-sizing: border-box;">View</span>.<span class="webkit-javascript-ident" style="box-sizing: border-box;">extend</span>({</div>
<br />
and<br />
<br />
<div class="webkit-line-content" style="-webkit-text-size-adjust: none; background-color: white; box-sizing: border-box; font-family: Menlo, monospace; font-size: 11px; line-height: 13px; padding-left: 2px; white-space: pre;">
<span class="webkit-javascript-comment" style="box-sizing: border-box; color: #007400;"> // The Application --> </span><span style="color: #007400;">Our overall **AppView** is the top-level piece of UI.</span></div>
<div class="webkit-line-content" style="-webkit-text-size-adjust: none; background-color: white; box-sizing: border-box; font-family: Menlo, monospace; font-size: 11px; line-height: 13px; padding-left: 2px; white-space: pre;">
<span class="webkit-javascript-keyword" style="box-sizing: border-box; color: #aa0d91;"> var</span> <span class="webkit-javascript-ident" style="box-sizing: border-box;">AppView</span> = <span class="webkit-javascript-ident" style="box-sizing: border-box;">Backbone</span>.<span class="webkit-javascript-ident" style="box-sizing: border-box;">View</span>.<span class="webkit-javascript-ident" style="box-sizing: border-box;">extend</span>({ .. })</div>
<br />
<br />
c) For the doing the first, startup rendering of a view, a Backbone router can be instructed to initialize the view:<br />
<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">class BackboneOnRailsTodo.Routers.TodoLists extends Backbone.Router</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> routes:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> '': 'index' </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> initialize: -></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> @todos = new BackboneOnRailsTodo.Collections.Todos()</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> @todos.fetch()</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> index: -></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> view = new BackboneOnRailsTodo.Views.TodoListIndex(collection: @todos) </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> $('#todo-list').html(view.render().el)</span><br />
<div>
<br /></div>
It's important to have at least something in a router, otherwise the Backbone router may not have a 'history' state<br />
<br />
There are other ways to initialize views, such as synchronous or asynchronous loading of data and/or view templates. In the example above, the data is provided asynchronous from server side.<br />
<br />
<b>6. Handling user interaction</b><br />
So far, the explanation above can be used to fetch data from the server, and to render it. However, in a rich-client application, events in the DOM, that are issued by user interactions (mouse click, key pressed, etc. ) are importat too.<br />
For having user interaction in the application event binding to DOM elements is used. Event binding events uses either Backbone or JQuery event delegation ('bind' or 'on' functions). To lookup the right DOM elements, the delegation must be bound in the correct context.<br />
<br />
This can be a cause for confusion as discussed here:<br />
<br />
<ul>
<li> <a href="http://stackoverflow.com/questions/5125958/backbone-js-views-delegateevents-do-not-get-bound-sometimes">http://stackoverflow.com/questions/5125958/backbone-js-views-delegateevents-do-not-get-bound-sometimes</a></li>
<li> <a href="http://stackoverflow.com/questions/4909564/backbone-js-why-isnt-this-event-bound">http://stackoverflow.com/questions/4909564/backbone-js-why-isnt-this-event-bound</a></li>
</ul>
<br />
<br />
<ul>
<li>http://stackoverflow.com/questions/9304625/in-backbone-js-how-do-i-bind-a-keyup-to-the-document</li>
</ul>
<div>
In the demo Todo application I use the following strategy to binding to events in the TodoListIndex:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> initialize: -></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> @collection.on('reset', @addAll, this)</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> @collection.on('add', this.addOne, this)</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> $('#new-todo').on "keypress", {collection: @collection}, @keyTodoInput</span></div>
</div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: inherit;">Note, the 'add' event works by using a backbone event binding. The 'keypress' event must use a JQuery binding, because the input form is outside the scope of the TodoIndex view.</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">The event that a new todo is added, is processed with:</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> addOne: (todo) -></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> console.log(todo)</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> view = new BackboneOnRailsTodo.Views.Todo({model: todo})</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> $("#todo-list").append(view.render().el) </span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
The event that an input is made, is processed with:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> keyTodoInput: (e) -></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> # console.log(event.type, event.keyCode)</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> return if (e.keyCode != 13)</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> return if (!this.value)</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> console.log(e.data.collection)</span></div>
</div>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-6011455943420440972011-05-26T10:40:00.000-07:002011-05-26T10:43:51.831-07:00Beauty in programmingAhh... nice day today! Finally, could experience and explore the beauty of programming again after some weeks of social science research. The logics of programming is often hidden behind many doors and dark rooms where light switches must be turned on first.<br />Well, that happened just today: First, taking a class from a C++ project with more than 100 methods, and 5 related classes. Making simplified versions in Ruby. And finally, seeing some relationships between methods and classes.... the hidden code behind abstractions :)<br /><br />Well, I tried to post something on stackexchange to ask fellow software developers about their experience with beauty in programming, but not much response yet.pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com3tag:blogger.com,1999:blog-11202978.post-83785819784346104912011-03-21T14:00:00.001-07:002011-03-23T03:31:58.089-07:00Some models for the design thinking process<div style="text-align: center;"><br /></div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-AmaJWXoy2uTFYknE5rEEwqNHws0ziO-TUJl-kjK7h2cG8xYBHrvERUSMghC2mo8HwBjHXGiAV79i1O4qTGXLrPGx3wk2R9AwpYCTX-LAggh4gcPE44ttI8VkqRBt3BKIRPrX/s1600/dthinking_proc3.png"></a><div>Here is a short list on variations on the design thinking process.</div><div><br /></div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtcWBdT45BCmQjXmcYxlX39oSydnQ-79HKCYfdC07DX4in4UleOO6hC3kTnbnWwh_22fVrU_DvpLDfUltnGjUTJTFGK7ACteE2VxlD_Vjl_rJwoWv5lLAgj3KkwfMtMTeBNXfq/s1600/dthinking_proc1.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 132px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtcWBdT45BCmQjXmcYxlX39oSydnQ-79HKCYfdC07DX4in4UleOO6hC3kTnbnWwh_22fVrU_DvpLDfUltnGjUTJTFGK7ACteE2VxlD_Vjl_rJwoWv5lLAgj3KkwfMtMTeBNXfq/s320/dthinking_proc1.png" alt="" id="BLOGGER_PHOTO_ID_5586641417048264626" border="0" /></a>The first process can be found on webpages at the <a href="http://ldt.stanford.edu/%7Ejimr1/">d.school</a> at Stanford. We see several stages, with variating degree in intensity: Empathize, Define, Ideate, Prototype, Test and Iterate.<div>The process starts with reflections on whom to work for, exploring and selecting perspectives, reflections on learning outcomes and prototyping, as well as evaluation of prototypes.</div><div><br /></div><div>Next, there is a circular model proposed by Tim Brown of Ideo.</div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-AmaJWXoy2uTFYknE5rEEwqNHws0ziO-TUJl-kjK7h2cG8xYBHrvERUSMghC2mo8HwBjHXGiAV79i1O4qTGXLrPGx3wk2R9AwpYCTX-LAggh4gcPE44ttI8VkqRBt3BKIRPrX/s320/dthinking_proc3.png" alt="" id="BLOGGER_PHOTO_ID_5586642219625269954" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 233px; height: 210px; " border="0" /></span></div><div><div style="text-align: center;"><span class="Apple-style-span" style="color:#0000EE;"><br /></span></div><div><div> Here, we see that Inspiration influences ideation and implementation and vice-versa.</div></div></div><div><br /></div><div>An iterative design thinking process that is taught at TU Munich Business School is shown below:</div><div><br /></div><span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGu1phCCHl0ioHTdld8ORbUGMZ0nbl1T5zjU35v9rHDvMEY_En_XmP6JKGRTSGK1wc-U7sEO1NCkqckHpB58QCN42SnSkABlPcW6oZkJv9hB7QmySnnl3-hsuAZMltddzlHcOj/s320/dthinking_proc2.png" alt="" id="BLOGGER_PHOTO_ID_5586642532806315154" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 187px; height: 172px; " border="0" /></span><div><br /></div><div>Here, we start with an analysis phase, a design phase follows, a prototype is build. Then, there is play and review on the experiences.</div><div><br /></div><div>An approach called "customer journey" to service design can be found <a href="http://designforservice.wordpress.com/2010/10/09/customer-journey-canvas/">here</a>. It is also a circular model, starting with a "pre-service" period, a service period, and a post-service period.</div><div><br /></div><div>Another circular model to design thinking is given by Prof. Ranjan from India. He calls his model the <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDZvUuMbjCSKjTUghzWgx6oe7rvAzNlCx51JLkuQT082D7z18ch9itHlztB1JaOjy-gZUrEiCcueg0mJ9N3QpqlxH6DAhTQWTv6e3ioWTYy9Fu69qTSDPVqyqtXu-JjV-1_4nrxg/s1600-h/07_EMERGENT+TECHNOLOGY+-+LR_ss.jpg">"hand-heard-head" model of design</a>. </div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjspT8P1bMDL3VGOhefkrTCavVWzNnEStrgryGJDICFS6jJFLceA7bRdPVP0F0VaOCxCzBdDN7hZ9UvSq3B75450hAwhdww0fg77zFjSU6arTum6ao2FDbjlf_ZKJAY2ofwl89D/s320/Bildschirmfoto+2011-03-21+um+21.59.04.png" alt="" id="BLOGGER_PHOTO_ID_5586644830382799666" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 231px; " border="0" /></span></div><div>Design of 1st order is about form and function. Design on 2nd order is about Function, Feeling, impact and effect. Design of 3rd order is about Meaning and Purpose.</div><div><br /></div><div>Still farther East, I. Nonaka proposes a model for innovation and learning that is somewhat similar to design thinking. It is the SECI model of knowledge creation. Nonaka starts with the aspect of empathy and observation, that he calls "socialisation". Here, knowledge that is difficult to articulate is experienced. Then, the implicit knowledge is made explicit by the process of "externalisation". This is mainly about codification of experiences with symbols or models. Third, externalised knowledge is combined in new ways to generate new concepts and ideas. This is called "combination". Last is the process of internalisation, where explicit knowledge is converted again into implicit knowledge in the form of best practices.</div><div><br /></div><div><br /></div><div> </div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggA_do6BOdbghfQrRzK4vFcwESpPo1p_b2-Au8Ok4qgu8jUPF_0m2rg0RYb7QLE9GksTk86C1e05ccGvaC7BhoeV8IxmMkzaPsWkap9Y8cqko7TsXw2Fm0fmaIs5woFvYewdxO/s320/Bildschirmfoto+2011-03-21+um+22.17.01.png" alt="" id="BLOGGER_PHOTO_ID_5586646379913039954" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 317px; height: 221px; " border="0" /></span></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "><br /></span></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; ">A short overview on design-thinkers can be found <a href="http://www.noisebetweenstations.com/personal/essays/DesignThinking-Business/">here.</a></span></div><div><span class="Apple-style-span" style="color:#0000EE;"><br /></span></div>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com3tag:blogger.com,1999:blog-11202978.post-27978089081384492242011-02-09T01:48:00.000-08:002011-02-18T02:45:45.842-08:00Repertory grid techniqueIn preparation with my MBA thesis at TU Munich on innovation, I have been looking into the repertory grid technique lately.<br />The method originated from T. Kelley who wanted to access subjective information without posing a biased frame of reference when interviewing people. Given a specified context (either minimum or full) by providing elements of interests (observations of phenomena), qualitities (or constructs) about these elements are elicited by participants in the interview.<br /><br />Some web pages that describe the method are:<br /><br />http://azlanadnan.blogspot.com/2003_11_01_archive.html<br /><br />http://www.ischool.utexas.edu/~adillon/Journals/Towards%20a%20classification.htm<br /><br />https://github.com/markheckmann/repgrid<br /><br />http://webspace.ship.edu/cgboer/qualmethfive.html<br /><br />http://www.pcp-net.de/papers/ueberbli.htm<br /><br />http://pages.cpsc.ucalgary.ca/~laf/611/Group/Reperatory_Grids_Exercise.html<br />http://www.personality-project.org/R/<br /><br />http://www.ischool.utexas.edu/~adillon/Journals/Towards%20a%20classification.htm<br /><br /><span style="visibility: visible;" id="search"><span class="b w xsm"><span style="font-weight: bold;"> </span></span><span style="font-weight: bold;font-size:85%;" ><span class="tl" style="font-family:arial;"><span class="std nobr"></span></span></span><div style="font-weight: bold;font-family:arial;" class="s"><span class="f"> </span><br /><span class="f">von L BJÖRKLUND</span> - <span class="f">2005</span> -<br />THE <em>REPERTORY GRID</em> TECHNIQUE. 21 more general dispositions or key competencies. The typical <em>textbook</em> items are, at best, indicators of such “habits of mind” ...<br /><span class="f"><cite>citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.98.3538&rep...</cite></span></div></span><br />http://valeriestewart-repertorygrid.blogspot.com/<br /><br />Next step: What could elements be of the RGT for a web collaboration system?pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-4494376944647289012011-02-07T05:23:00.001-08:002011-02-10T02:29:32.953-08:00The forms of tacit knowledgeSo, I am going to explore the role of tacit knowledge to improve our ways of web communication. As a first step, it is interesting to ask what do we understand "tacit knowledge" is?<br /><br />Here some ideas on tacit knowledge:<br />* TK is related to subjective information or knowledge. Subjective is often used to contrast objective information.<br />* TK is related to the context where information is used<br />* TK and implicit knowledge are related<br />* TK and affective information is related. Affective information is often used in advertising. Advertising relies heavily on images and metaphors. There are several authors that investigate cognitive processes for advertisment purposes. One of them is C. Scheier.<br />* In motivation theory, tacit knowledge might be related to intrinsic rewards versus extrinsic rewards. Some ideas on motivation can be found in the context of gaming, such as here ( <a href="http://usablelearning.wordpress.com/2011/01/05/the-learners-journey/">Usability learning blog</a> )<br />One of the concepts used here is the concept of Journey.<br />* TK is related to emotional communication. How can we share stories to find the deeper motivations?<br />* TK might be related to synthesis and discovery of knowledge rather to analytic knowledge.<br />* TK might be related to dynamic versus static information, behavior and actions.<br />* TK might be related to tastes and patterns<br /><br />What are your ideas on tacit knowledge? Please help!pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-74961750520206515332011-02-04T04:51:00.000-08:002011-02-07T05:27:08.693-08:00Implicit and explicit knowledgeFrom Nonaka's HBR paper "The knowledge-Creating Company", the following insights can be derived.<br />First, Western companies try to make decisions based on quantifiable data that often is put together into key metrics, such as increased efficiency, lower costs, improved return on investments.<br />Japanese companies try to use implicit knowledge for new product development. Here, creating knowledge is not only a matter of processing "objective" information, but depends on subjective insights, intuitions, hunches of individual employees. Often, this requires managers to use images, symbols and metaphors. In this view, a company is not a machine but a living organism. In order to arrive at this view, it takes a shared understanding of what a company stands for, where it is going, what kind of world it wants to live in, and how to make that world a reality. Inventing you knowledge is not the provinence of a specialized R&D department, but a way of behaving. <br />Central to the knowledge creating company is the activity of making personal knowledge available to others. <br />The process of turning implicit knowledge into explicit knowledge and vice-versa are especially valuable for an organization. In Nonaka's view, these transitions are the interfaces where knowledge is created.<br />Explicit knowledge are specification that can easily be communicated and shared in today's web communication systems.<br />For innovation, "tacit" knowledge is often valuable. Tacit knowledge is very subjective and highly personal. As Michael Polanyi said: "We can know more than we can tell."pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-51645186528197145692010-07-18T14:32:00.000-07:002010-07-18T14:33:48.620-07:00interaction and cognitive psychologyonce in a while I stumble across new research on cognitive psychology. this is sad news actually:<br /><br /><a href="http://www.guardian.co.uk/news/2002/feb/08/guardianobituaries.highereducation">Mike Scaife</a>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-29862888572362247572010-04-12T01:16:00.000-07:002010-04-12T01:18:30.179-07:00git version controlgit is becoming more and more a viable tool to work with content in the cloud, on my local desktop or on a remote server. It's incredible efficient.<br /><br />Here is a nice summary. <a href="http://www.kernel.org/pub/software/scm/git/docs/everyday.html">20 commands for every-day Git</a> Git from the viewpoint of a committer and project integrator.pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-24196879311768710512010-03-21T15:16:00.000-07:002010-03-21T15:50:41.048-07:00doing a survey with ruby on rails (part 2)Now, that the tables and models are setup, we implement the View and Controller layers. The scaffold has given already some start, but we'll change these to give our application a better survey character.<br /><br />First, the index view of the questions. We want to see a simple list of questions that we have so far, and the associated choices. <br /><br />So, let's edit this view in /survey/app/views/question/index.html.erb. We remove almost everything and replace it with a unlinked list in html like this:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKJiDg4W96RG7D4k-N6dMM-QhYtAG4C9H6KtFpyDK88aNrS1__b2XNqVpHCW6yom4XUV6J5ljTKipnUkAwkL7r46k15x4WtGn5X7xp84pErNTFzWyW4qQ-RkwoBEJy8uslIywo/s1600-h/Picture+2.png"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 261px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKJiDg4W96RG7D4k-N6dMM-QhYtAG4C9H6KtFpyDK88aNrS1__b2XNqVpHCW6yom4XUV6J5ljTKipnUkAwkL7r46k15x4WtGn5X7xp84pErNTFzWyW4qQ-RkwoBEJy8uslIywo/s320/Picture+2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5451221460960055906" /></a><br /><br />Note how we have used a second unlinked list to display the choices that are associated with a question, and how the modify and destroy actions are removed to be accessible only from inside the question edit. The question can be edited by clicking on it.<br /><br />At the moment, we don't have any choices yet in our database. Let's add some with putting "http://0.0.0.0:3000/choices" in the URL of our browser.<br /><br />I add the following for now: "it's great", "much", "ok", "not much", "green", "blue", "red", "yellow"<br /><br />Now, we arrive at one of the more difficult parts. Putting checkboxes in the new and edit views of the questions.<br /><br />First, the new action in /survey/app/views/questions/new.html.erb :<br /><br />We need to iterate over the choices. We can do this like this:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpxwuz1gfj3U-yYOTgRcYAcB64LzGWJg149yRKM1kKiBnJZ_zHvSypk2fxzQ_SgZhBI7kEkMJ_peGQOUvW5jHx3_llEfwzaMRDsIoXCKe_-W_kv2WATPxbIxU4RKsApmX0L-Xj/s1600-h/Picture+4.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 94px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpxwuz1gfj3U-yYOTgRcYAcB64LzGWJg149yRKM1kKiBnJZ_zHvSypk2fxzQ_SgZhBI7kEkMJ_peGQOUvW5jHx3_llEfwzaMRDsIoXCKe_-W_kv2WATPxbIxU4RKsApmX0L-Xj/s320/Picture+4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5451221935610453474" /></a><br /><br /><br />We also insert the loop in the edit view:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi76c_SjwzDyBeu0ww0uVpKbDI-5COiWfOGUIya-QYKX3ZcOdd4aZZlB-kurjkhEEIPZAb2HiQOaFgc0FcBmbyGeGhanMn4hlzc8RXhwkH8hRpPSRUzecC5-Va_5epXZjpasdix/s1600-h/Picture+5.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 47px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi76c_SjwzDyBeu0ww0uVpKbDI-5COiWfOGUIya-QYKX3ZcOdd4aZZlB-kurjkhEEIPZAb2HiQOaFgc0FcBmbyGeGhanMn4hlzc8RXhwkH8hRpPSRUzecC5-Va_5epXZjpasdix/s320/Picture+5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5451223022616802786" /></a><br /><br /><br />To have a short list in our show view on choices, we add in app/views/questions/show.html.erb:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8CnRrebD-LuM5xS0E2UCutwMA3dJM-hswUCMYZEEi6n_mlOhsvrg01RlR942miikKWstHBOZ3R8i2nLVolcSTu4qIP6lEXGWenQTdh8t9nuQOABpAxlPVlrfd2Rgym6q6xsJG/s1600-h/Picture+6.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 86px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8CnRrebD-LuM5xS0E2UCutwMA3dJM-hswUCMYZEEi6n_mlOhsvrg01RlR942miikKWstHBOZ3R8i2nLVolcSTu4qIP6lEXGWenQTdh8t9nuQOABpAxlPVlrfd2Rgym6q6xsJG/s320/Picture+6.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5451223253623763730" /></a><br /><br />So, that was part 2. By now, you should have a survey app where an administrator can easily enter questions and associate possible choices with these questions.<br /><br />Next, we need to have users who can take part in the survey.<br /><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-Y7Ml8teYzawmIPUznMRcn9c0EPvhbzROipnnLKw8ajy93xiZM1VGZygCaye73CCbqmJ0qlufIuamAz7wC3nsXY9_cYbXUyu3c8jWOT1O2I61aD7Kck2xTxVGXjco-UvC7Tfh/s1600-h/Picture+1.png"><img style="float:center; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 298px; height: 320px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-Y7Ml8teYzawmIPUznMRcn9c0EPvhbzROipnnLKw8ajy93xiZM1VGZygCaye73CCbqmJ0qlufIuamAz7wC3nsXY9_cYbXUyu3c8jWOT1O2I61aD7Kck2xTxVGXjco-UvC7Tfh/s320/Picture+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5451220952703257410" /></a>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com3tag:blogger.com,1999:blog-11202978.post-66458745313795142032010-03-20T02:09:00.000-07:002010-03-21T15:54:54.891-07:00doing a survey with ruby on rails (part 1)This is a basic tutorial that might help you understand the basics of ruby-on-rails. The idea of the project comes from this <a href="http://stackoverflow.com/questions/2479864/ruby-on-rails-questionnaire-tutorial/2480976#2480976">stackoverflow.com question</a>. My current rails working environment is 2.3.5.<br /><br />As with every rails project, in the beginning rails gives you a basic project setup using the model-view-controller pattern.<br /><br />Let's try:<br /><br /><pre><br /> ./ > rails -d mysql survey<br /></pre><br /><br />The -d option is important to specify the usage of a database right at the start. In general, I use mysql for this, and the provided database.yml may need a bit tweeking the first time, but will soon be functional for many rails projects.<br /><br />To create and test the database, you want to check with:<br /><br /><pre><br /> ./survey/ > rake db:create<br /></pre><br /><br />if there is no error message.<br /><br />Coming back to our MVC pattern, at the moment, the directories /survey/app/models, /survey/app/views and /survey/app/controllers are still empty.<br /><br />Basic resources (what the combination of a view-model-controller often is), can easily be done with scaffolding.<br /><br />So, let's make a resource for our "question" and one resource for a "choice".<br /><br /><pre><br /> script/generate scaffold question whatabout:string<br /> script/generate scaffold choice desc:string<br /></pre><br /><br />With<br /><br /><pre><br /> rake db:migrate <br /></pre><br /><br />we create our new tables in the database.<br /><br />Now, we need to associate a choice wih a question. We want to select the choices that a user can enter in the survey. So, we use a m:n relationship between choices and questions. (The steps behind this are explained more in detail <a href="http://stackoverflow.com/questions/564306/do-i-need-to-manually-create-a-migration-for-a-habtm-join-table">here</a>, <a href="http://asciicasts.com/episodes/17-habtm-checkboxes">here</a> and <a href="http://ramblings.gibberishcode.net/archives/rails-has-and-belongs-to-many-habtm-demystified/17"> here</a>).<br /><br />So, to implement the associations, we need to modify our table and the models accordingly.<br /><br />First, we create a helper table with:<br /><pre><br />script/generate model questions_choice<br /></pre><br /><br />In the new migration, we add references to our "choices" and "questions" tables like this:<br /><pre><br />class CreateQuestionsChoices < ActiveRecord::Migration<br /> def self.up<br /> create_table :choices_questions, :id => false do |t|<br /> t.references :choice, :question<br /> t.timestamps<br /> end<br /> end<br /><br /> def self.down<br /> drop_table :choices_questions<br /> end<br />end<br /></pre><br /><br />Let's check that we have no problems so far with a:<br /><pre><br /> rake db:migrate<br /></pre><br /><br />Next, we edit our models:<br /><br />We say:<br /><br /><pre><br /># question.rb<br />class Question < ActiveRecord::Base<br /> has_and_belongs_to_many :choices<br />end<br /><br /># choice.rb<br />class Choice < ActiveRecord::Base<br /> has_and_belongs_to_many :questions<br />end<br /><br /># questions_choice.rb<br />class QuestionsChoice < ActiveRecord::Base<br /> belongs_to :question<br /> belongs_to :choice<br />end<br /></pre><br /><br />As a result, we should be able to access the table "Questions" from the table "Choices", and vice versa. "belongs_to", "has_and_belongs_to_many" are method calls of ActiveRecord. In a sense, Ruby let defines us our own domain-specific language easily, and that is basically what Rails is.<br /><br />To show that the models are working, it is helpful to check with the Ruby interpreter first. For this, we start:<br /><br /><pre><br /> ./survey/ > script/console -s<br /></pre><br /><br />The -s option says we want to use a sandbox, i.e. our modifications in the database are rollbacked after we exit from the console.<br /><br />So, first<br /><pre><br /> q = Question.new<br /> q.whatabout="Our Rails tutorial"<br /> q.save<br /></pre><br /><br />gives us a first question where we can add choices to. We do this with<br /><br /><pre><br /> c = Choice.new(:desc => "it's ok")<br /> q.choices << c<br /></pre><br /><br />Ruby knows from our models how to set the foreign key question_id and choice_id in the join table by using the operator "<<". We can repeat editing and adding new choices for our first question database.<br /><br />Within the console, we can list all our choices for a question with:<br /><br /><pre><br /> q.choices.each {|choice| puts "#{choice.id} #{choice.desc}"}<br /></pre><br /><br /><br />In the next part of the tutorial, we will have a look on how we can provide a user interface for our models on questions and choicespmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-54546018899139728422009-12-16T04:08:00.000-08:002009-12-16T04:11:30.314-08:00network computersweb browsers are in essence some form network computers. computers can be a path to information as explained very nice in this talk by eric schmidt http://www.youtube.com/watch?v=cl8bEApvblg<br /><br />he also explains that the information industry is actually much bigger than the IT industry, and that google sees itself as an information company. Personally, I think one ingredient in a company around information, is the ability to analyse data.<br /><br />there is a nice book on data analysis here: http://www.google.de/#hl=de&source=hp&q=head+first+data+analysis&btnG=Google-Suche&meta=&aq=f&oq=head+first+data+analysis&fp=c6a75e802a8b0e7pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-26720505896304468012009-10-29T05:34:00.000-07:002009-10-29T06:04:34.824-07:00how can we get smarter?how can we get smarter? maybe here is an interesting path:<br /><a href="http://www.businessweek.com/magazine/content/09_36/b4145040683083.htm">Concept of "collaboratories"</a><br /><br />also very interesting innovation marketing lecture by Clayton Christonson: <a href="http://www.youtube.com/watch?v=AMCJhJE2CKU&NR=1">Understand the job of what a customer is trying to accomplish</a><br /><br />Christensen is very inspiring. Makes me popup the question if it is better to master the basics or to study with masters directly. This could make an interesting business called "growthcurve.com" where you could record what knowledge and insight you had to master to be at the point where you are nowpmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-84462538668981645392009-08-18T13:34:00.000-07:002009-08-18T13:35:27.625-07:00git cheatsheetnice little cheatsheet about git:<br /><br /><a href="http://ionrails.com/2009/08/07/git-commands-adding-and-committing-cheatsheet/">git cheatsheet</a>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-63238328996774614702009-08-13T23:21:00.001-07:002009-08-13T23:25:22.152-07:00distributed applicationsinternet is all about pushing and pulling information from different places at different times. the basic idea behind this are the URL and the HTTP protocol. Also, the network gets encapsulated by the cloud concept.<br />An interesting variation on this seems the CouchDB project.<br />Here is an interesting video:<br /><a href="http://jsconf2009.com/couch_video.html">CouchDB overview</a><br /><br />J. Chris Anderson often uses the REST concept and that he has been learning internet programming by "view source" HTML and later rails.<br /><br />Here is a short tutorial on REST maybe interesting to look into one day:<br /><br /><a href="http://developer.yahoo.com/php/tutorials/water_bug_tutorial-making_rest_request.html">PHP rest tutorial from yahoo</a>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-56812306901369994492009-08-09T10:45:00.000-07:002009-08-09T10:55:57.213-07:00webapp with hoboHobo sounds similar to holo and it makes me remember starship Enterprise. In any case, hobo is also a framework for making CRUD application with Rails and it helped me to deploy a first experiment of an app to Heroku: <a href="http://electric-moon-35.heroku.com/">electric-moon-35.heroku.com</a><br /><br />Some ressources were helpful for learning how to do this:<br />* First the <a href="http://docs.heroku.com/quickstart">the heroku quickstart docs</a><br />* The docs about <a href="http://docs.heroku.com/logs-exceptions">debugging with Heroku</a><br />* A message in a mail server on problems with plugins and installing gems: <a href="http://www.mail-archive.com/hobousers@googlegroups.com/msg01637.html">NoMethodError undefined method</a><br />* That there exists something like <a href="http://www.herokugardens.com"> and </a><a href="http://www.mail-archive.com/heroku@googlegroups.com/msg02460.html">authentication problems with Herokugardens</a><br />* The increasingly popular GIT version control and <a href="http://wiki.github.com/tablatom/hobo/git">GIT version control</a>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-55080656408285932632009-07-26T03:00:00.000-07:002009-07-26T03:04:43.500-07:00ruby experimentswow.. had a really nice time about learning programming web-apps with rails on ruby:<br /><br />* Heroku: Very convenient Hosting service <a href="http://www.heroku.com">heroku.com</a> get in touch with cloud computing<br />* Railcasts: Very nice tricks to get ruby programs working: <a href="http://railscasts.com/episodes/38-multibutton-form">Railcasts.com</a><br />* Sample CRUD app: <a href="http://www.vimeo.com/1699112">Vimeo tutorial by eric berry</a><br />* More rails tutorials: <a href="http://www.brenelz.com/blog/2009/04/13/ruby-on-rails-to-do-list-tutorial/">rails tutorials</a><br />* probably my first ruby book <a href="http://www.apress.com/book/view/1590596862">rails book</a>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-29128694510945761422009-07-06T11:35:00.001-07:002009-07-06T11:40:21.147-07:00software and computerswow, this talk is great.<br /><br />why software is there, Moore's Law, entrepreneurship, relationship between software and engineering, software and business, online learning, access to information:<br /><br /><a href="http://www.youtube.com/watch?v=6b6DEUM5Gbw&feature=related">gates is a really a good speaker</a><br /><br />Marketing, getting appraisal is a big part of Software.pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-54493661779073617552009-06-26T13:25:00.001-07:002009-06-26T13:25:44.772-07:00interaction designnice oreilly webcast:<br /><br /><a href="http://www.youtube.com/watch?v=LW4MwvgW_ww">interaction design</a>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-80559078562697243992009-06-21T03:11:00.000-07:002009-06-21T03:12:03.142-07:00SQL podcastsinteresting list of SQL podcasts:<br /><br /><a href="http://www.sqldownunder.com/PreviousShows/tabid/98/Default.aspx">SQLDownUnder</a>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-18035669705744502312009-06-21T03:06:00.000-07:002009-07-22T23:29:23.277-07:00Unit testing<a href="http://live.eclipse.org/node/262">eclipse webcast</a><br /><br />especially towards the end this discussion gets interesting, testing JavaEE, Servlets, etc.<br /><br />"Not care how a class does something, but only WHAT it is supposed to do."pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0tag:blogger.com,1999:blog-11202978.post-59913163528220463112009-06-17T02:05:00.000-07:002009-06-17T02:08:22.587-07:00ArrayList and parameter typesInteresting forum discussions on what it means to use a "heterogeneous collection" in Java:<br /><br /><a href="http://forums.sun.com/thread.jspa?threadID=778963">forums.sun.com</a><br /><br />Also, a reference book at google books on Java:<br /><br /><a href="http://books.google.de/books?id=Bh_inpFm8NoC"> a google books/book on java </a>pmulderhttp://www.blogger.com/profile/13838208159885175972noreply@blogger.com0