Sword tag:blog.markjuh.net,2005:Sword-markjuh Markjuh Experiences with weblog design in Rails Mark van Eijk mark@fngtps.com 2005-09-26T14:51:28+02:00 tag:blog.markjuh.net,2005:Sword-markjuh-56 Hanging FCGI-processes with Edge Rails and lighttp 2005-09-26T14:51:28+02:00 2005-09-26T14:51:29+02:00 <p>For quite some time now, if you use <a href="http://www.lighttpd.net/">lighttpd</a> combined with <a href="http://wiki.rubyonrails.com/rails/pages/EdgeRails">Edge Rails</a>, the Rails <span class="caps">FCGI</span>-processes don&#8217;t terminate when lighttpd terminates. This is strange, since lighttpd sends the <code>TERM</code> signal to the <span class="caps">FCGI</span>-processes. I had to use a <code>kill -9</code> to actually end the <span class="caps">FCGI</span>-processes.</p> <p><a href="http://techno-weenie.net/" title="technoweenie">Rick Olson</a> confirmed this behaviour and we tried to track it down. We couldn&#8217;t find it back then, but since then I got SO annoyed that I looked into it a bit more.</p> <p>It seems that the problem is in <code>vendor/rails/railties/lib/fcgi_handler.rb</code>. It shows that the <code>TERM</code> signal is handled by the <code>graceful_exit_handler</code>. This handler sets <code>whenready</code> to <code>:exit</code>, which should make sure that the <span class="caps">FCGI</span>-process ends <em>after</em> processing the <em>current or next</em> FCGI-request.</p> <p>And now this last part <em>exactly</em> forms the problem. When lighttpd terminates, the <span class="caps">FCGI</span>-process is waiting for the next request to come so it can finish gracefully. But the next request never comes, since lighttpd is already down, so there is no process to send requests to the <span class="caps">FCGI</span>-process.</p> <p>So, I&#8217;ve written a <a href="http://fngtps.com/projects/sword/file/trunk/doc/fix_fcgi_exit_when_autospawning.diff?rev=278">dirty hack to fix this problem</a>. <a href="http://www.loudthinking.com/">David Heinemeier Hansson</a> already promised to fix it the right way, but I just couldn&#8217;t wait for that to happen. (Using <code>kill -9</code> every time you restart the webserver is just too annoying.)</p> tag:blog.markjuh.net,2005:Sword-markjuh-55 Unexpected characters when using Prototype (AJAX) 2005-09-26T13:27:17+02:00 2005-10-02T03:41:04+02:00 <p>A little while back someone pointed me at the weird behaviour of my preview box when adding a comment. Somehow <code>&#38;_=</code> was added to the end of the preview content.</p> <p>It took me quite some time to figure out where it was coming from. I searched and searched, but couldn&#8217;t find the problem. I thought it wouldn&#8217;t be a Prototype bug, since Rails had been updated, but Prototype hadn&#8217;t changed.</p> <p>So I asked around in <code>#rubyonrails</code> and <a href="http://script.aculo.us/" title="madrobby">Thomas Fuchs</a> pointed me in the right direction.</p> <p>It seemed <a href="http://dev.rubyonrails.com/changeset/2106">changeset 2106</a> in Rails changed the way a Safari bug was tackled. It had been the case that Prototype added the <code>&#38;_=</code> to the end of the <span class="caps">POST</span> data and <code>ActionPack</code> would strip this away again. But since another fix was found for this problem, there was no need for the <code>&#38;_=</code> anymore.</p> <p>So the following (line 213, or in the latest Edge Rails version line 476) should be removed from <code>prototype.js</code>:</p> <p><code>if (parameters.length &gt; 0) parameters += '&#38;_=';</code></p> <p>I had already discovered that removing the line fixed the problem, but it was good to find the reason why. And I&#8217;ve filed it as <a href="http://dev.rubyonrails.com/ticket/2258">ticket 2258</a>.</p> tag:blog.markjuh.net,2005:Sword-markjuh-51 How to make sure an attribute doesn't get updated 2005-08-08T10:55:17+02:00 2005-08-08T20:53:18+02:00 <p>I have a Rails model in which I don&#8217;t want the <code>title</code> attribute to change. I implemented this with a <code>before_update</code>:</p> <code><pre> before_update :check_title_unchanged protected def check_title_unchanged Post.find(id).title == title end </pre></code> <p>This didn&#8217;t quite work because of <a href="http://blog.markjuh.net/markjuh/2005/7/29/rails_activerecord_bug">an ActiveRecord bug</a> I wrote about before.</p> <p>When talking to <a href="http://www.koziarski.net/">Michael Koziarski</a> at <code>#rubyonrails</code> about this bug, he made clear that I have at least one problem with my code <em>and</em> that I could have made a different implementation.</p> <p>First to tackle the real problem in <em><strong>my</strong></em> code. The problem with my implementation is that it isn&#8217;t thread-safe, because the title could have been changed by another thread after we&#8217;ve fetched the object from the database. And hence our title wouldn&#8217;t have changed, but we still wouldn&#8217;t be able to save our model.</p> <p>So the better way of doing it is by adding an <code>after_find</code> which is documented at the <a href="http://wiki.rubyonrails.com/rails/show/HowToUseUndocumentedCallbacks">Rails Wiki</a>. And also updating the <code>before_update</code> method accordingly.</p> <code><pre> before_update :check_title_unchanged attr_accessor :original_title protected def after_find @original_title = title end def check_title_unchanged @original_title == title end </pre></code> <p>Now to take a look at another approach to tackle this. We could also override the <code>validate</code> method. The <code>validate</code> method has the following documentation:</p> <p><em>Overwrite this method for validation checks on all saves and use Errors.add(field, msg) for invalid attributes.</em></p> <p>So we could now change our code to:</p> <code><pre> attr_accessor :original_title protected def after_find @original_title = title end def validate @original_title==title end </pre></code> <p>And if we would want to make it really nice, we would use <code>Errors.add</code> to add a descriptive error message, which is then added to the list of errors that will be displayed by <code>error_messages_for</code>. <em>This would be the only reason I would use this approach instead of using a <code>before_update</code>.</em></p> <p>So we could do:</p> <code><pre> def validate result = (@original_title==title) if !result Errors.add(:title, "Title cannot be changed.") end end </pre></code> <p><em><strong>Conclusion:</strong></em> in my project I have no use for the error message, so I don&#8217;t really see the point in overriding the <code>validate</code> method. But now I at least know the available options and can choose one wisely. So if I just need to make sure the title cannot be updated by a programming mistake in a controller, I use the <code>before_update</code>. If the user needs to be presented with a nice error message why they cannot change the title, then I would choose for overriding the <code>validate</code> method.</p> <p><em><strong>Update:</strong></em> I tried to put this nice piece of code to work, but it breaks my <span class="caps">CRUD</span> tests. My <span class="caps">CRUD</span> tests might behave a little different from the actual application, but still, they shouldn&#8217;t break. I actually create an object, save it, update it and then save it again. This failed, because I did not do a find for the same object and hence <code>original_title</code> is not yet set. So I&#8217;ll leave my implementation as it is currently. The issue with thread-safety is not that shocking in my case, since the title <em>really</em> shouldn&#8217;t be changed anyway.</p> tag:blog.markjuh.net,2005:Sword-markjuh-46 Significance of Unit Testing in Rails 2005-08-07T03:14:54+02:00 2005-08-08T09:50:47+02:00 <p>Today I&#8217;ve been explaining some basics of <a href="http://www.rubyonrails.com/">Ruby on Rails</a> to a friend of mine. With a couple of friends we&#8217;re building a <a href="https://trac.luon.net/ledr-frontend">front-end for <span class="caps">LEDR</span></a>, which is basically an educational document repository, which we intend to use at <a href="http://w3.tue.nl/en/">Eindhoven University of Technology</a>.</p> <p>We only went into the model part of the <a href="http://www.slash7.com/articles/2005/02/22/mvc-the-most-vexing-conundrum">MVC design pattern</a>. And since Rails applications are especially suited for <a href="http://en.wikipedia.org/wiki/Test_driven_development">Test Driven Development</a>, I decided to start showing Rails by writing unit tests. So we first started with the generation of a model and then wrote some basic <span class="caps">CRUD</span> tests for them. We had been writing down requirements for some of our models earlier today and could now write these requirements in the tests directly. We heavily borrowed test code from other projects I&#8217;m doing. So we had some default tests for each possible model requirement we had come up with.</p> <p>Time to run rake! <em>And boy, did we get failures and errors!</em></p> <p>We were using SQLite, had created the databases and even made sure <code>config/database.yml</code> contained the right settings. All nice, but we had forgotten to install <a href="http://rubyforge.org/projects/sqlite-ruby">sqlite-ruby</a> on our development system. <em>(Ironically enough, our production server already has it installed.)</em> We should have definitely read <a href="http://wiki.rubyonrails.com/rails/show/HowtoUseSQLite">Howto Use SQLite in Rails</a> a bit better.</p> <p>If you are not even interested in writing tests, running the automatically generated test for the model would have already shown this.</p> <p>After getting this out of the way, our tests were still failing&#8230; <em>Well, duh!</em> We forgot to even create a table in the database for the model. Again, just running the automatically generated test would have shown this.</p> <p>So, writing the table and importing it in SQLite (<em>which by the way is a painful process when you are used to <a href="http://www.phpmyadmin.net/">PHPMyAdmin</a> or <a href="http://yoursql.ludit.it/">YourSQL</a> for all your database editing</em>) solved at least a bunch of the errors/failures. Basic <span class="caps">CRUD</span> tests were now at least passing.</p> <p>So on with the more interesting aspects. Our tests clearly showed we were missing <code>validates_presence_of</code>, <code>validates_uniqueness_of</code> and <code>validates_format_of</code>. Since we had some well-defined <a href="https://trac.luon.net/ledr-frontend/file/branches/TRY-Mark-Bas/test/unit/course_test.rb?rev=87">tests</a>, it was really clear what to add in the corresponding <a href="https://trac.luon.net/ledr-frontend/file/branches/TRY-Mark-Bas/app/models/course.rb?rev=87">model</a>.</p> <p>Still, one test was failing&#8230; The test that made sure that we couldn&#8217;t change the <code>code</code> field of the model. Maybe not as clear, but after some thinking we added the following straightforward <code>before_update</code> to the model:</p> <pre><code> def check_code_changed Course.find(id).code == code end </code></pre> <p>Now our test <strong>should</strong> have all passed.</p> <p>Unfortunately there is a <a href="http://blog.markjuh.net/markjuh/2005/7/29/rails_activerecord_bug">bug in Rails I wrote about some time ago</a>. So we first had to apply the patch I had made for the bug. Then everything worked just fine.</p> <p>After this we wrote another two models and created relationships between them, all driven by tests defined before actually writing <em><strong>any</strong></em> model code. And every since test-case that failed showed us exactly where we had to find the problem and showed us at least a hint of where to find our mistakes or where to add model code; even more specific, it often showed us <em><strong>which</strong></em> code to add.</p> <p>We also had a problem in the <span class="caps">SQL</span> code that updated our SQLite database. It wasn&#8217;t actually a query performed by Rails, but we needed it to update our table to the lastest version. We had totally forgotten to add a commit at the end of the transaction. Our tests showed our missing field in the table quite nicely.</p> <p>I can conclude that it convinced us both that Test Driven Development is <strong>the</strong> way to go when developing Rails applications. It helps you detect so many things, sometimes not even directly related to the specific model (<em>as we can see above</em>). Lots of times before I had seen tests as a necessary evil, but today we both got really excited by writing tests and seeing all the positive results we got from it. <em>Our tests even made it possible to write Rails code after having a couple of glasses of wine. ;)</em></p> tag:blog.markjuh.net,2005:Sword-markjuh-44 Rails ActiveRecord bug 2005-07-29T16:43:42+02:00 2005-07-29T16:48:50+02:00 <p>Today I had to make sure a model couldn&#8217;t be saved if someone tried to update a certain field.</p> <p>Reading in the <span class="caps">API</span> documentation I found the following:</p> <blockquote> <p>If a <code>before_*</code> callback returns <code>false</code>, all the later callbacks and the associated action are cancelled.</p> </blockquote> <p>So a <code>before_update</code> callback in my model would be the solution. I just had to make sure it would return <code>false</code> in the right cases.</p> <p>Because of the last three months of test-driven development, I decided to write a test first. And to my surprise I could <em>always</em> save the model, even if my <code>before_update</code> callback would always return <code>false</code>. First I double-checked my test, but it was okay. Time to use yet another great tool in Rails: <code>script/console</code>.</p> <p>It showed that even though the <code>save</code> method always returned <code>true</code>, it in fact did <em>not</em> save the model. So fortunately no problem with the <code>before_update</code> callback. This meant that there was no way avoiding it anymore&#8230; I would take my first dive into the <code>ActiveRecord</code> code.</p> <p>After quite some time of searching back and forth through a couple of Ruby files, I found the problem:</p> <pre><code> def create_or_update if new_record? then create else update end true end </code></pre> <p>And see here, it always returns <code>true</code> instead of the actual result from <code>create</code> or <code>update</code>. Why? Well, probably because there would be a problem in the <code>create</code> method:</p> <pre><code> def create self.id = connection.insert( "INSERT INTO #{self.class.table_name} " + "(#{quoted_column_names.join(', ')}) " + "VALUES(#{attributes_with_quotes.values.join(', ')})", "#{self.class.name} Create", self.class.primary_key, self.id, self.class.sequence_name ) @new_record = false end </code></pre> <p>This <code>create</code> method returns the value of <code>new_record</code> (which is <code>false</code>), instead of the result of the query (<code>self.id</code>).</p> <p>I&#8217;ve written a simple patch (see <a href="http://dev.rubyonrails.com/ticket/1861">ticket #1861</a>), which solves my problems and doesn&#8217;t introduce any new problems in my application. But again, it would be good to have a test for <code>ActiveRecord</code>. The problem is that I&#8217;m just not well-acquainted with <code>ActiveRecord</code>, so I have no idea where or how to incorporate the test. <em>Any help with this would be greatly appreciated.</em></p> tag:blog.markjuh.net,2005:Sword-markjuh-43 Sword 2005-07-27T22:30:24+02:00 2005-07-27T22:30:24+02:00 <p>This blog has now moved to my own machine and it&#8217;s running <a href="http://fngtps.com/projects/sword/">Sword</a>.</p> <p>Since most people will not be interested in every note I make about this project, I&#8217;ve moved the frequent and detailed posts about Sword to it&#8217;s <a href="http://blog.markjuh.net/sword/">own blog</a>. It will mostly contain posts about new versions and features.</p> <p>This blog will contain things I&#8217;ve uncovered during Rails development. Interesting behaviour or pieces of Rails code that might be of interest.</p> tag:blog.markjuh.net,2005:Sword-markjuh-22 Back up again 2005-07-05T14:14:23+02:00 2005-07-25T15:27:12+02:00 <p><em>Finally</em> I&#8217;ve been able to get this blog up and running again after somehow going down and not being able to start up again.</p> <p>I checked the <code>lighttpd.conf</code> file, but I couldn&#8217;t find anything that was wrong. But after throwing away the configuration file and setting it up again from scratch, it now works again!</p> tag:blog.markjuh.net,2005:Sword-markjuh-21 Prototype adjustment 2005-05-30T12:56:14+02:00 2005-07-25T16:15:21+02:00 <p>The little error I just fixed made me look at some minor issues with running this prototype.</p> <p>I used <a href="http://jlaine.net/blog/57/keeping-your-lighttpd-up-on-textdrive-part-ii">Keeping your lighttpd up on TextDrive, part II</a> to make sure lighttpd would be restarted if the Rails FastCGI process had died.</p> <p>And I also added <a href="http://rails.rubyonrails.com/classes/ActionController/Pagination.html">Pagination</a> to the main weblog part so the page that needs to be loaded is smaller than before (only 5 posts instead of all of them).</p> tag:blog.markjuh.net,2005:Sword-markjuh-20 Annoying bug 2005-05-30T11:38:00+02:00 2005-05-30T11:38:00+02:00 <p>Since <a href="http://www.textdrive.com/">Textdrive</a> moved bidwell to new hardware, this application doesn&#8217;t seem to function as well as before.</p> <p>As a first step I&#8217;ve removed the contents of the vendor directory and restarted lighttpd, so the gem versions of the Rails components will be used.</p> <p>Now to figure out why posting fails.</p> <p><strong>Update</strong>: I guess that was it, it&#8217;s fully functional again.</p> tag:blog.markjuh.net,2005:Sword-markjuh-19 Routing 2005-05-13T08:34:26+02:00 2005-05-13T08:34:26+02:00 <p>I&#8217;ve been diving into <a href="http://manuals.rubyonrails.com/read/book/9">routing</a> the last two weeks. It&#8217;s a great concept, but the code is hard to get through.</p> <p>One thing that had me puzzled for several hours was that I wasn&#8217;t able to break the routing tests, no matter what I did. It turned out there was an <a href="http://dev.rubyonrails.com/ticket/1287">error in the filename of the file that contains the routing tests</a>.</p> <p>After fixing this simple problem, I added support for domains and subdomains to <code>vendor/rails/actionpack/lib/action_controller/routing.rb</code>. The <code>Route::items=</code> method now sets an optional part in array that contains the routing information.</p> <p><code>[[domain_info], path_info]</code>, where if <code>domain_info</code> is empty, it reduces to <code>[path_info]</code>, which is just the regular case it used to be without any domain/subdomain additions.</p> <p>This makes sure that I did not break existing behaviour, yet provides a way to identify the new items.</p> <p>Unfortunately, also changes to the test-functions are needed, since currently <code>verify_recognize</code> and <code>verify_generate</code> do not accept <code>/</code> as a prefix for the path. And the possibility to use this prefix is essential in our extension of routing, since we would like to use the following scheme in our application:</p> <p><code>//:weblog.ourdomain.org/:year/:month/:day/:post</code></p> <p>(the nice <code>Route::items=</code> method would give us <code>[[:weblog, "ourdomain", "org"], :year, :month, :day, :post]</code> here)</p> <p>Furthermore, the flow of information through the <code>UrlRewrite::rewrite</code> method would need to change. The following implementation would not work anymore:</p> <p><code>rewrite_url(rewrite_path(options), options)</code></p> <p>But instead <code>rewrite_path</code> should also update the options in a smart way.</p> <p>Since this is too much of a hassle at the moment, we decided to drop this for a bit and go ahead with the implementation of the pilot version and use URIs of the form <code>/:weblog/:year/:month/:day/:post/</code>.</p> tag:blog.markjuh.net,2005:Sword-markjuh-18 Daedalus 2005-05-02T12:50:00+02:00 2005-05-02T12:50:00+02:00 <p>I waited for the transfer of bidwell (one of the shared hosting servers of <a href="http://www.textdrive.com/">TextDrive</a>) to the new hardware and took some time today to figure out how to get Daedalus to work, so it would monitor lighttpd and restart it if it would crash.</p> <pre> $ mkdir ~/src $ cd ~/src $ wget http://svn.textdrive.com/repos/scripts/daedalus-1.2.tar.bz2 $ tar xjvf daedalus-1.2.tar.bz2 $ mkdir ~/daedalus $ cd ~/daedalus $ cp ~/src/daedalus/daedalus.rb . $ mkdir log run $ wget http://blog.fngtps.textdriven.com/daedalus.conf $ ./daedalus.rb </pre> <p>And it was up and running.<br />Just to be sure, I added a cron job to make sure Daedalus gets started each time the server is rebooted.</p> <p>Of course I cheated and prepared the config file (daedalus.conf) in advance:</p> <pre> name: lighttpd checkcommand: /bin/ps ax checkregex: /lighttpd/ onfailcommand: /usr/local/sbin/lighttpd -f /home/thijs/lighttpd/lighttpd.conf checkinterval: 30 aftercommandwait: 15 </pre> tag:blog.markjuh.net,2005:Sword-markjuh-17 Caching (2) 2005-04-18T15:18:40+02:00 2005-04-18T15:18:40+02:00 <p>Now that I had caching at least working, it was time to get it the way I wanted it to work. Page caching turned out to be quite nice if you are just looking at the page as a visitor, but then after you login, you cannot edit anything, because the links just don&#8217;t show up. This is not that weird, since I was caching the whole page and invalidating the page just because someone logs in is a bit silly.</p> <p>So, then I did some research and it turned out that action caching wasn&#8217;t the thing for me either, so I turned to fragment caching. After some initial confusion it turned out to be quite simple and <em>fast</em>.</p> <p>I also tried to use <a href="http://www.danga.com/memcached/">memcached</a> on my development machine at home. After installing <a href="http://www.deveiate.org/code/Ruby-MemCache.html">Ruby-MemCache</a> and it&#8217;s required libraries and adding the following line to <code>config/environments/development.rb</code>, it worked quite nicely:</p> <p><code>ActionController::Base.fragment_cache_store = ActionController::Caching::Fragments::MemCacheStore.new("localhost")</code></p> <p>So why use memcached instead of the default MemoryStore? Well, the default MemoryStore creates its own fragment store for each <span class="caps">FCGI</span>-process. So it would create more of a burden on your system then just using one central fragment store.</p> tag:blog.markjuh.net,2005:Sword-markjuh-16 Caching 2005-04-15T16:24:00+02:00 2005-04-15T16:24:00+02:00 <p>I&#8217;ve been trying to get page caching to work. All to no avail, until I asked around in the Ruby on Rails <span class="caps">IRC</span> channel. It turned out that in version 0.11.1 caching of pages is broken and that updating to Edge Rails solved the problem.</p> <p>This was the perfect time to change my repository around and move the vendor part into a <span class="caps">SVN</span> external.</p> tag:blog.markjuh.net,2005:Sword-markjuh-15 lighttpd 2005-04-15T08:37:00+02:00 2005-04-15T08:37:00+02:00 <p>Just switched this <a href="http://www.rubyonrails.com/">Rails</a> application to FastCGI on <a href="http://www.lighttpd.net/">lighttpd</a>. And it&#8217;s no surprise at all that lighttpd is much faster, since I&#8217;ve been using it on my development-machine ever since I started on Rails-applications.</p> <p>So finally, this blog is a bit more usable. :)</p> <p>For those of you wondering how I&#8217;ve set this up, have a look at (which is what I found when I was looking how to do this):<br /><a href="http://weblog.textdrive.com/article/31/having-ones-own-lighttpd-and-running-it-too">Having one&#8217;s own lighttpd and running it too</a></p> tag:blog.markjuh.net,2005:Sword-markjuh-14 So now what? 2005-04-14T20:43:00+02:00 2005-04-14T20:43:00+02:00 <p>Well, I still have to figure out caching and build support for multiple users. And if possible, try out <a href="http://pear.math.pitt.edu/mathzilla/itex2mmlItex.html">itex2mml</a>, which basically converts a subset of L<sup>a</sup>T<sub>e</sub>X to MathML.</p> <p>Before anyone comments on it, yes, this <em>does</em> look like <a href="http://wordpress.org/">WordPress</a> and <a href="http://typo.leetsoft.com/">Typo</a>, but that&#8217;s not strange. Typo took it from WordPress and I took some of both. Since it is supposed to be a prototype, I&#8217;m not taking the time to make a different design. This one is just clean, nice and readily available.</p> tag:blog.markjuh.net,2005:Sword-markjuh-13 Prototype online at Textdrive 2005-04-14T20:26:00+02:00 2005-04-14T20:26:00+02:00 <p>Yesterday and today I&#8217;ve been trying to get this prototype online at <a href="http://www.textdrive.com/">TextDrive</a>.</p> <p>Once you know how to install it, it&#8217;s quite simple. But there are some pitfalls. First thing I ran into was that I couldn&#8217;t get Apache properly configured. But it turned out I had to disable <code>*.fngtps.textdriven.com</code> or otherwise <code>blog.fngtps.textdriven.com wouldn't</code> work. Then it worked just fine, but just with <span class="caps">CGI</span>, which is <em>slow</em>. But I couldn&#8217;t get FastCGI to work properly. Someone was kind enough to tell me that there were some problems with the combination of Apache2 and FastCGI on TextDrive. Still have to switch to lighttpd and use Apache2 as a proxy. At least so far it works.</p> <p>Next obstacle was MySQL&#8230; It doesn&#8217;t complain when you make tables with the InnoDB engine, but as soon as you try to insert values into the table, it returns an error (<code>#1030 - Got error -1 from storage engine</code>). It took me hours of searching on Google and trying things to figure out that just switching to MyISAM fixed the problem.</p> <p>Then once it was online, I disabled the signup-functionality of the login generator I used, imported the blog entries I had been typing in a text-file.</p> <p>Then I found out my Atom feeds were containing quite a few errors, so I found a feed validator and the <a href="http://www.atomenabled.org/developers/syndication/atom-format-spec.php#rfc.section.4.13.3">The Atom Syndication Format 0.3</a>, which helped me correct the mistakes I had ignorantly made.</p> <p>Only annoying thing left was that I had no real titles for each post, so I took some time to read what I had written before and come up with a title. :)</p> tag:blog.markjuh.net,2005:Sword-markjuh-12 Ajax makes life more fun :) 2005-04-13T11:09:00+02:00 2005-04-13T11:09:00+02:00 <p>So, what have I been doing since last Friday?</p> <p>Well, I&#8217;ve been busy with the prototype I&#8217;m building. Not quite sure what I did exactly on which day, but so far I&#8217;ve got comments to work. Mostly adding comments Ajax-style. Ajax, shorthand for Asynchronous JavaScript + XML, makes web interfaces more interactive. It relies heavily on XMLHttpRequest, which enables the use of asynchronous server communication. For more information see <a href="http://www.adaptivepath.com/publications/essays/archives/000385.php">Ajax: A New Approach to Web Applications</a>.<br />After that I added deleting of comments. Having done this in a more traditional way, I had to wait for a new page every time I deleted a comment. Since this too was annoying, I used Ajax here too. And it sure made the page more responsive.</p> <p>I&#8217;ve also added <em>very</em> basic authentication support, which basically boils down to having to login to be able to edit, delete or post a new entry. During this process, I made sure that users who are not logged in are shielded from all this management functionaly.</p> <p>Next in line is support for multiple blogs and after that caching is waiting around the corner.</p> tag:blog.markjuh.net,2005:Sword-markjuh-11 Shifting design perspective 2005-04-07T23:23:00+02:00 2005-04-07T23:23:00+02:00 <p>Today I got home around 13:00 after having a hard time with the trains yesterday and today.</p> <p>So, after lunch, I started working on the prototype of the blogging application, which is what I&#8217;ve mostly been busy with since Tuesday.</p> <p>Tuesday I mostly learned how to deal with database design in combination with Rails and how to use the console script to test your models. My first idea was to define my foreign keys as <span class="caps">NOT NULL</span>, but this gives the key a default value of 0. In it&#8217;s own not much of a problem. I thought that validates_presence_of and validates_associated would take care of this and not accept non-existant foreign key values. But that wasn&#8217;t quite right.<br />So then my idea was to enforce the foreign key constraint directly in the database. But this made sure I could never get my unit tests to work again, since you cannot independently test one of the tables of the one-to-many relationship. Back to the old idea then. But now defined my foreign keys as <span class="caps">NULL</span> and giving them a default value of <span class="caps">NULL</span>. This at least makes validates_presence_of work and you have to actually change the value of the foreign key to be able to save a record.</p> <p>But setting a default value of <span class="caps">NULL</span> is ugly, right? Sure, if you are looking at it from the old <span class="caps">RDBMS</span>-view, that&#8217;s absolutely right. But we are now looking at it from the Rails side, which is quite innovative. I had a hard time grasping this too at first, but after a day of discussing it, I remembered an article by Date I had read a couple of years ago in which he argued (quite well I must say) that a <span class="caps">RDBMS</span> combined with business logic is in itself again a <span class="caps">RDBMS</span>. So when you look at Rails, you have to see for example MySQL + ActiveRecord + models as the <span class="caps">RDBMS</span>. And when you take that perspective, it all makes sense. It&#8217;s not MySQL anymore that does the constraints, it&#8217;s actually defined in the models, so you can use the <span class="caps">DRY</span> (Don&#8217;t Repeat Yourself) way of working.</p> <p>Then Wednesday, I&#8217;ve mostly been busy with giving functional tests a try and working on the controller and view part of adding a new post to the blog.</p> <p>Which brings me to the work of today. Mostly been working at some functional tests, getting some green lights and finally some refactoring (mostly of views). I really like working <span class="caps">TDD</span>-style, but it annoys me that it&#8217;s so hard to write functional tests.</p> <p>Tomorrow I want to work out comments, logins and creation of new blogs (which requires some database remodeling). So that will mostly be &#8220;yay for refactoring&#8221;-day.</p> tag:blog.markjuh.net,2005:Sword-markjuh-10 Mondays 2005-04-05T11:02:00+02:00 2005-04-05T11:02:00+02:00 <p>Yesterday was a typical Monday. Lots of things just didn&#8217;t work out the way you expected them to go.</p> <p>But in the process of writing the use case/evaluation for Blogger, I found out that I had overseen some details and that it was actually a better blogging site than expected.</p> <p>Other than that, I&#8217;ve been watching Thijs being busy with a nice script that creates a graph of the Rails models in your project. See <a href="http://journal.schubert.cx/read/9">Graphing graphers graphically</a> for more information. Although it contained some bugs, it surely helped us to spot errors in the model code. And while we were playing around with this script, Thijs was also trying out single table inheritance. It took him some time to get it working, but we both learned a lot from it.</p> <p>Thijs left early, I finished up some documentation and read how components are supposed to work in Rails.<br />For the most part, it was a typical 8:30 to 16:30 day, which I normally don&#8217;t have. :)</p> tag:blog.markjuh.net,2005:Sword-markjuh-9 FlySketch to the rescue! 2005-04-04T09:52:00+02:00 2005-04-04T09:52:00+02:00 <p>So, what did I do last Friday?</p> <p>Mostly, I&#8217;ve been busy all day with making screenshots of all those beautiful (read: annoying) weblog tools/sites. Fortunately Thijs came up with a nice application which helped me to get all the screenshots and yellow markings on those shots done in just one day, called <a href="http://www.flyingmeat.com/flysketch/">FlySketch</a>&#8221;. So basically, today I will be busy with working out the use cases and getting the images in.</p> <p>Furthermore, this morning (in the train from Eindhoven to Utrecht), I&#8217;ve been playing around with the console script of Rails to see how I can interact with database models that way. It was interesting to find out how it all works.</p> tag:blog.markjuh.net,2005:Sword-markjuh-8 TDD (2) 2005-03-30T23:40:00+02:00 2005-03-30T23:40:00+02:00 <p>This afternoon and evening I&#8217;ve been reading a bit more in the fabulous book by Kent Beck. Not quite sure when I finished doing work today, since I&#8217;ve done a few things in between. But the reading really made me want to do some serious test-driven development. :)</p> tag:blog.markjuh.net,2005:Sword-markjuh-7 Test-Driven Development 2005-03-30T19:26:00+02:00 2005-03-30T19:26:00+02:00 <p>This morning, I started working around 9:15. After catching up with the Rails weblog, I started reading &#8220;Test-Driven Development (By Example)&#8221; by Kent Beck. I&#8217;ve finished Part I and so far it has been quite inspiring. It has some nice parallels to the way Multiprogramming is taught by Wim Feijen at our university; in this course you learn to first focus on the simplest possible correct implementation and then worry about progress requirements. To make the parallels more explicit, I like to point out constructing correct implementations from a specification is not so different from making tests and trying to implement the simplest possible thing that fulfills these tests. The test can be seen as a sort of specification in this <span class="caps">TDD</span>-methodology. Often it occurs that the progress requirements in multiprogramming problems require you to do refactoring of the implementation. So far <span class="caps">TDD</span> sounds logical and actually gives testing a better place in the way I think about programming.</p> <p>The Fibonacci-example in Appendix II made it clear that it fits really well with the formal programming style I learned in university. I think I&#8217;ll write a comparison of the two methods of working later when I have some spare time.</p> tag:blog.markjuh.net,2005:Sword-markjuh-6 Using Instiki 2005-03-30T17:19:00+02:00 2005-03-30T17:19:00+02:00 <p>Yesterday, I left work around 17:15. It took me some part of the day to document some user interface related things in <a href="http://instiki.org/show/HomePage">Instiki</a>&#8221;, a wiki-system built upon Rails. I thought Instiki would be helpful, but weird enough the stable version had a few annoying bugs which bothered me. After some research, I found out that the problem was fixed in the <span class="caps">SVN</span>-version of Instiki. On the one hand this has cost some precious time, but on the other hand it had me looking at several Rails and RedCloth (library for Textile support) topics.</p> tag:blog.markjuh.net,2005:Sword-markjuh-5 What will I be doing? 2005-03-29T10:36:00+02:00 2005-03-29T10:36:00+02:00 <p>Today, I arrived half an hour late at work, because the NS decided to cancel a train. So, I arrived around 9:00. Then around 9:45, Thijs and I had a brief meeting to discuss what I have been doing and what we both expect to do the coming weeks and more specifically, what I will be doing this week. He suggested that I should also make a quick, functional prototype and write unit tests for the models and also some functional tests. It will be nice to at least briefly touch every aspect of the Rails framework and see what kind of troubles you can run into.</p> tag:blog.markjuh.net,2005:Sword-markjuh-4 Blogging systems 2005-03-24T16:55:00+01:00 2005-03-24T16:55:00+01:00 <p>So, what did I do today besides fucking up two important files? Well, mostly been busy with blogging engines today.</p> <p>I first registered with <a href="http://www.sixapart.com/">Six Apart</a> to be able to test their <a href="http://www.typepad.com/">TypePad</a> online blogging service and download <a href="http://www.sixapart.com/movabletype/">Movable Type</a>, which you can install on your own webserver. Getting a TypeKey is quite an annoying process <del>- if I didn&#8217;t have to research this, I would have stopped after 1 minute of annoyance &#8211; </del> but finally I got everything to work. I got an error message somewhere and filled out an error report and to my amazement they looked at it, pointed me in the right direction and didn&#8217;t forget to mention that by the looks of it in their logs, I had figured out what to do myself. So, buggy process, but good feedback. Installing Movable Type was alright, but more annoying than other products.</p> <p>Then registering with <a href="http://www.blogger.com/">Blogger</a>... This went really painless, just enter some information and you&#8217;re good to go. The only negative thing I found so far is that they don&#8217;t send an email to confirm your account.</p> <p>So, which leaves us with <a href="http://wordpress.org/">WordPress</a>. No registration to be able to download anything, easy installation <del>- once you figure out that you have to set <tt>cgi.fix_pathinfo = 1</tt> in your <tt>php.ini</tt> &#8211; </del> and good usability.</p> <p>Which leaves me with the installation of Typo, which I will do tomorrow morning. And then I&#8217;m ready to make use cases and screenshots of the different blogging systems. But for now, I call it a day, after working from 8:30 to about 17:15.</p> tag:blog.markjuh.net,2005:Sword-markjuh-3 Debian vs MacOS X 2005-03-24T14:57:00+01:00 2005-03-24T14:57:00+01:00 <p>I just accidentally copied some files to the wrong location and in turn destroyed the already existing files&#8230; As a result of this, I lost my entry of what I did yesterday (which was on my notebook) and I lost all of my bookmarks on my desktop. The entry of yesterday&#8217;s work is unfortunate, but not unrepairable. But my bookmarks&#8230; Damn! Lost hundreds of handy bookmarks. Especially losing locations of <span class="caps">HTML</span>/CSS-related stuff and homepages of people bugs me.</p> <p>Anyway, let me first recover <del>- briefly &#8211; </del> what I did yesterday. I installed a virtual desktop program to make my working experience even more fun. Then I was confronted with all kinds of package-stuff I was taking for granted on my Debian systems.</p> <p>For example, installing a new version of MySQL on my machine. Installing the new version is not much of a problem, but purging the old package&#8230; There is just no predefined way of doing that, so the simplest solution is just to keep it hanging around and let it clog up your system.</p> <p>Furthermore I had an issue with Ruby-FCGI. It seems the default Ruby-installation doesn&#8217;t come with that on MacOS X. No wonder I couldn&#8217;t get Rails to work. So I had to go and fetch the source, apply patches, build and install it myself. Quite annoying when you are used to automatically having dependencies coming along with your installation. Even installing the gems-version of Rails didn&#8217;t automatically download the gem of this library.</p> <p>Of course there was no <span class="caps">FCGI</span>-version of <span class="caps">PHP</span> <del>- which is needed for most webservers that don&#8217;t include their own <span class="caps">PHP</span>-module &#8211; </del> installed on MacOS X, so I had to build that myself too. No package for phpmyadmin either, so I found out that the Debian package actually fills in quite a sane default for the config file (which I now had to do by hand).</p> <p>There are some things that just work though. <span class="caps">X11</span>-support for MacOS X is just marvellous and installing and using The <span class="caps">GIMP</span> is quite easy that way. And once you get the hang of it, the default terminal that comes with MacOS X is quite usable too <del>- after configuring default window size and keybindings &#8211; </del>.</p> <p>It didn&#8217;t feel like much work, but I had been working from 8:30 to around 17:15.Anyway, back to work.</p> tag:blog.markjuh.net,2005:Sword-markjuh-2 Working at home 2005-03-22T21:22:00+01:00 2005-03-22T21:22:00+01:00 <p>I had set my alarm around 7:00, but I still felt pretty tired, so I slept until around 7:55. I got up, put some bread into the oven and sat down behind my computer. During breakfast I played around with Squirrelmail, but wasn&#8217;t quite as charmed by it as I thought I would be, so I switched to Thunderbird. I used it to send an email to Marc Voorhoeve, who will be my guide from university to help my out during my internship, to ask him what I needed to do for my report on this whole project. I got a reply later that day and with the help of some documents online and some of the reports class-mates had made, I started to set up the main document layout. After identifying risks and countermeasures, I filled in the guidelines for the rest of the document.</p> <p>Furthermore, I noticed Rails was updated to version 0.11, which includes all kinds of new nifty features. I won&#8217;t repeat what is new, <a href="http://weblog.rubyonrails.com/archives/2005/03/22/rails-0110-ajax-pagination-non-vhost-incoming-mail/">Rails 0.11.0: Ajax, Pagination, Non-vhost, Incoming mail</a> lays it all out for you. It will also contain a link to a movie about the new Ajax-feature, which basically makes it possible to make web-applications more interactive (more like &#8220;normal&#8221; applications).</p> <p>Somehow it felt like I&#8217;ve been doing quite a bit, but somehow I don&#8217;t feel as accomplished as yesterday. But I guess I also have to get used to the dynamics of working at home. At least it was nice to listen to some uplifting music by <span class="caps">VNV</span> Nation and some soothing music by Vangelis.</p> tag:blog.markjuh.net,2005:Sword-markjuh-1 First day! 2005-03-21T17:49:00+01:00 2005-03-21T17:49:00+01:00 <p>This morning around 8:30, I started the first day of my internship at Fingertips in Amsterdam.</p> <p>Basically, I&#8217;ve been busy setting up my working environment all day. I&#8217;m finally in the fortunate position to work with MacOS X (panther) and although I still have to get used to some things, I must say that I really like working with this system. After completing the system installation and required updated, I continued with QuickSilver. Now <ins>that</ins> is an application I&#8217;m going to miss when I&#8217;m working my days at home. Once you get the hang of it <del>- say in about 10 minutes &#8211; </del> you really speed up your work <del>- and I&#8217;m not even scratching the surface of all the functionality &#8211; </del>.</p> <p>To keep it short, I&#8217;ve got everything ready for the work I need to do. Just have to find a decent <span class="caps">RSS</span>/Atom-feedreader and fix a permissions problem with the Rails/lighttpd combination.</p> <p>Left work around 17:30 with an accomplished feeling and some regrets that I have to work with Linux at home.</p>