<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>upstream agile - software</title>
	<atom:link href="http://upstream-berlin.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://upstream-berlin.com</link>
	<description></description>
	<pubDate>Tue, 19 Aug 2008 20:35:17 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.1</generator>
	<language>en</language>
			<item>
		<title>Functional Testing awesomeness with Webrat</title>
		<link>http://upstream-berlin.com/2008/08/09/functional-testing-awesomeness-with-webrat/</link>
		<comments>http://upstream-berlin.com/2008/08/09/functional-testing-awesomeness-with-webrat/#comments</comments>
		<pubDate>Sat, 09 Aug 2008 21:54:23 +0000</pubDate>
		<dc:creator>Alexander Lang</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[functional testing]]></category>

		<category><![CDATA[html]]></category>

		<category><![CDATA[rails]]></category>

		<category><![CDATA[tdd]]></category>

		<category><![CDATA[testing]]></category>

		<category><![CDATA[webrat]]></category>

		<guid isPermaLink="false">http://upstream-berlin.com/2008/08/09/functional-testing-awesomeness-with-webrat/</guid>
		<description><![CDATA[I recently started using Webrat in one of our project&#8217;s test suites and fell in love with it immediately. Webrat is a functional testing library for Ruby on Rails which you can use in your rails integration tests (or better: the RSpec Story Runner) to let your tests walk through your application. The big difference [...]]]></description>
			<content:encoded><![CDATA[<p>I recently started using <a href="http://www.brynary.com/uploads/webrat/rdoc/index.html">Webrat</a> in one of our project&#8217;s test suites and fell in love with it immediately. Webrat is a functional testing library for Ruby on Rails which you can use in your rails integration tests (or better: the RSpec Story Runner) to let your tests walk through your application. The big difference between Webrat and a &#8220;standard&#8221; Rails Integration Test is that with Webrat you click on actual links and submit actual forms, instead of just sending requests to you application.</p>
<p>This closes an important gap to testing in a real browser (like with Selenium) and now gives us much more confidence in our tests - we now not only know that our models and controllers integrate, but we also know that they work with our views. That had been an unpleasant problem for a while. All our tests were passing but we still had way too many problems with invalid links and forms submiting to the wrong action. No more. </p>
<p>Webrat provides a sort of DSL (everything is a DSL nowaday isn&#8217;t it? <img src='http://upstream-berlin.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ) for interacting with all the HTML elements you would find in a HTML document like links, checkboxes, radio buttons, text fields, selects and submit buttons. A test case might look like this:</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
visits '/'
clicks_link 'Sign up'
fills_in 'username', :with => 'joedoe'
selects 'Male'
checks 'Terms of Service'
clicks_button
</textarea>
<p>Webrat now fetches the start page of the application, parses it and follows the first link labelled with &#8220;Sign Up&#8221;, gets the corresponding page, parses the form, fills in the values and submits it. Whenever a response comes back with anything else than a 200 (or 302, in which case that redirection is followed automatically) or an element on the page can&#8217;t be found, Webrat complains with an error and you know there&#8217;s probably something wrong in your view.</p>
<p>In Order to get this working with Story Runner I have wrapped most calls into When calls, for example:</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
When 'I click on $link' do |link|
  clicks_link link
end
When 'I submit the form' do
  clicks_button
end
When 'I select $option' do |option|
  selects option
end
</textarea>
<p>And now my Story looks like this:</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
Scenario: successful signup
  When I go to the start page
  And I click on Sign up
  And I select Male
  And I check the Terms of Service
  And I submit the form
  Then the page should show Thank you for signing up
</textarea>
<p>I&#8217;m not sure yet if it makes sense to release those wrappers as a plugin, we&#8217;ll see. After all it&#8217;s just a few lines of trivial code.</p>
<p>By the way, <a href="http://github.com/brynary/webrat">Webrat is hosted on awesome github</a>, so after using it for 30 minutes (seriously) <a href="http://github.com/langalex/webrat">I forked my own version</a> and added support for the Rails date helpers (<code>selects_date Date.today, :from => 'signup_date'</code> instead of <code>selects 'December', :from => 'signup_date_2i'; selects '2008', :from => 'signup_date_1i'; selects '01', :from => 'signup_date_3i'</code>) and Emails (e.g. clicking the activation link in a signup email). (Bryan Helmkamp, if you read this: Why haven&#8217;t you pulled this (and in fact any other fork) into the main line yet?)</p>
<p>All in all the experience has been fantastic. Webrat is on all my Rails projects now. The only - conceptual - problem so far is that I can&#8217;t use it to test AJAX. But that&#8217;s the topic of another post. And there&#8217;s <a href="http://github.com/johnnyt/webrat">a fork</a> on github that experiments with <a href="http://celerity.rubyforge.org/">celerity</a>, which can do AJAX and everything.</p>
]]></content:encoded>
			<wfw:commentRss>http://upstream-berlin.com/2008/08/09/functional-testing-awesomeness-with-webrat/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Warum ich selbständig geworden bin?</title>
		<link>http://upstream-berlin.com/2008/07/23/warum-ich-selbstandig-geworden-bin/</link>
		<comments>http://upstream-berlin.com/2008/07/23/warum-ich-selbstandig-geworden-bin/#comments</comments>
		<pubDate>Wed, 23 Jul 2008 16:15:10 +0000</pubDate>
		<dc:creator>Alexander Lang</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[arbeit]]></category>

		<category><![CDATA[freelancer]]></category>

		<category><![CDATA[manifest]]></category>

		<category><![CDATA[selbstaendig]]></category>

		<guid isPermaLink="false">http://upstream-berlin.com/2008/07/23/warum-ich-selbstandig-geworden-bin/</guid>
		<description><![CDATA[Ich kann arbeiten wann ich will.
Ich kann arbeiten wo wo ich will.
Ich kann arbeiten mit wem ich will.
Ich kann arbeiten woran ich will.
Ich kann mir meine Kunden aussuchen.
Ich kann arbeiten womit ich will.
Ich kann arbeiten wie ich will.
Ich kann mir mein Büro aussuchen und einrichten wie ich will.
Ich kann mir aussuchen, wieviel Geld ich verdienen [...]]]></description>
			<content:encoded><![CDATA[<p>Ich kann <a href="http://upstream-berlin.com/2008/03/10/4-tage-woche-und-kreditkarten-fur-alle/">arbeiten wann ich will</a>.</p>
<p>Ich kann arbeiten <a href="http://upstream-berlin.com/2008/07/18/oslo-were-comming/">wo wo ich will</a>.</p>
<p>Ich kann arbeiten <a href="http://upstream-berlin.com/network/">mit wem ich will</a>.</p>
<p>Ich kann arbeiten <a href="http://kommt-mit.de">woran</a> ich <a href="http://hallenprojekt.de">will</a>.</p>
<p>Ich kann mir <a href="http://upstream-berlin.com/projects/">meine Kunden</a> aussuchen.</p>
<p>Ich kann <a href="http://rubyonrails.org/">arbeiten</a> <a href="http://www.apple.com/macbookpro/">womit</a> <a href="http://developer.apple.com/iphone/">ich</a> <a href="http://macromates.com/">will</a>.</p>
<p>Ich kann <a href="http://en.wikipedia.org/wiki/Behavior_driven_development">arbeiten wie ich will</a>.</p>
<p>Ich kann mir <a href="http://boxhagener119.de/">mein Büro</a> aussuchen und einrichten wie ich will.</p>
<p>Ich kann mir aussuchen, wieviel Geld ich verdienen will.</p>
<p>Ich lerne jeden Tag mehr dazu, weil ich nicht nur Programmierer, sondern gleichzeitig noch Projektmanager, Geschäftsführer, Administrator, Sales-Fuzzi und sonstwas bin.</p>
<p>Um das mal zusammenzufassen: ich habe die freiheit zu tun was ich will. Und wenn ich irgendwann mal keine Lust mehr habe kann ich mich immer noch anstellen lassen. Oder nach Hawaii gehen. <em>Darum</em>.</p>
<p>(Hab ich noch was vergessen? Kommentare&#8230;)</p>
]]></content:encoded>
			<wfw:commentRss>http://upstream-berlin.com/2008/07/23/warum-ich-selbstandig-geworden-bin/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Oslo we&#8217;re coming</title>
		<link>http://upstream-berlin.com/2008/07/18/oslo-were-comming/</link>
		<comments>http://upstream-berlin.com/2008/07/18/oslo-were-comming/#comments</comments>
		<pubDate>Fri, 18 Jul 2008 16:53:19 +0000</pubDate>
		<dc:creator>thilo</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[culture]]></category>

		<category><![CDATA[exchange]]></category>

		<category><![CDATA[holiday]]></category>

		<category><![CDATA[oslo]]></category>

		<category><![CDATA[remote office]]></category>

		<category><![CDATA[ruby]]></category>

		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://upstream-berlin.com/2008/07/18/oslo-were-comming/</guid>
		<description><![CDATA[So, finally everything is prep&#8217;ed: flights booked, accommodation confirmed, host office organized and cat fed. Tomorrow, very early in the morning, off we go to Oslo to live and work there for one week  
It&#8217;s just a short period of time but we&#8217;ll try to get the most out off it. We got in [...]]]></description>
			<content:encoded><![CDATA[<p>So, finally everything is prep&#8217;ed: flights booked, accommodation confirmed, host office organized and cat fed. Tomorrow, very early in the morning, off we go to Oslo to live and work there for one week <img src='http://upstream-berlin.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>It&#8217;s just a short period of time but we&#8217;ll try to get the most out off it. <a href="http://irb.no/-/bulletin/show/91505_rubyists-visiting-oslo">We got in contact </a> with the local ruby user group, starting off with a couple of beers on sunday and hopefully exchanging some great wisdom. Maybe we can also initiate a <a href="http://listas.apesol.org/pipermail/chat-lrug.org/2007-November/001784.html">speaker exchange</a> with the <a href="http://www.rug-b.de">berlin ruby user group</a>. </p>
<p>Thanks to <a href="http://shortcut.no">shortcut</a> who have been kind enough to let us stay at their office for the week, we are mighty excited to get a glimpse on their work culture. And in the evenings and weekends we will surely check out the vicinity of Oslo. </p>
<p>I&#8217;m sure this will be cool work holidays <img src='http://upstream-berlin.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> If anyone in Oslo wants to meet us just send an email. We&#8217;ll also be posting some photos once we&#8217;re there.</p>
]]></content:encoded>
			<wfw:commentRss>http://upstream-berlin.com/2008/07/18/oslo-were-comming/feed/</wfw:commentRss>
		</item>
		<item>
		<title>RSpec Story Runner auf deutsch</title>
		<link>http://upstream-berlin.com/2008/07/14/rspec-story-runner-auf-deutsch/</link>
		<comments>http://upstream-berlin.com/2008/07/14/rspec-story-runner-auf-deutsch/#comments</comments>
		<pubDate>Sun, 13 Jul 2008 23:22:18 +0000</pubDate>
		<dc:creator>Alexander Lang</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[bdd]]></category>

		<category><![CDATA[deutsch]]></category>

		<category><![CDATA[rails]]></category>

		<category><![CDATA[rspec]]></category>

		<category><![CDATA[ruby]]></category>

		<category><![CDATA[setup]]></category>

		<category><![CDATA[story-runner]]></category>

		<guid isPermaLink="false">http://upstream-berlin.com/2008/07/14/rspec-story-runner-auf-deutsch/</guid>
		<description><![CDATA[Wir sind gerade mit einem neuen Projekt gestartet - alles richtig  &#8220;nach Lehrbuch&#8221;: kurze Iterationen, Iteration Planning zusammen mit dem Kunden, Behavior Driven Design, User Stories, automatisierte acceptance Tests - all die schönen Dinge die man in so einem modernen agilen Softwareprojekt haben will. 
Während der Planung der ersten Iteration haben wir zusammen mit [...]]]></description>
			<content:encoded><![CDATA[<p>Wir sind gerade mit einem neuen Projekt gestartet - alles richtig  &#8220;nach Lehrbuch&#8221;: kurze Iterationen, Iteration Planning zusammen mit dem Kunden, Behavior Driven Design, User Stories, automatisierte acceptance Tests - all die schönen Dinge die man in so einem modernen agilen Softwareprojekt haben will. </p>
<p>Während der Planung der ersten Iteration haben wir zusammen mit dem Kunden User Stories geschrieben, um sie anschließend direkt in den RSpec Story Runner zu werfen, also <code><em>As a</em> User <em>I want</em> to upload my photo <em>So that</em> everyone can see my smiley face</code>. Da unsere Kunden deutsch sprechen war das Meeting und dementsprechend auch die Stories auf deutsch, also <code><em>Als</em> Benutzer <em>will ich</em> mein Foto hochladen können <em>damit</em> alle mein tolles Grinsegesicht sehen können</code>. Damit der Story Runner damit umgehen konnte mussten wir ihm eine neue Sprache beibringen. So geht&#8217;s:</p>
<p><span id="more-210"></span></p>
<p>In <a href="http://rspec.lighthouseapp.com/projects/5645/tickets/269-stories-in-other-languages">diesem Ticket</a> gibt&#8217;s einen <a href="http://rspec.lighthouseapp.com/attachments/10667/story_for_ticket_269.tar.gz">Patch</a> für den Story Runner, womit die Schlüsselwörter in den plain text stories konfiguriert werden können. (Wer wie ich mit Kommandozeilenpatchen nicht klar kommt, TextMate hat ein schönes Diff Bundle mit dem man den Patch auf einen RSpec (z.B. 1.1.4) checkout anwenden kann).</p>
<p>Die Konfiguration kann dann einfach in der <em>stories/helper.rb</em> landen:</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
Spec::Runner.configure do |config|
  config.with_story_template_words({
    :story          => "Story",
    :scenario       => 'Szenario',
    :given          => 'Gegeben',
    :given_scenario => 'Gegebenes Szenario',
    :when           => 'Wenn',
    :then           => 'Dann',
    :and            => 'Und'
  })
end

</textarea>
<p>Was diesem Patch allerdings noch fehlt ist die Übersetzung der zu jeder plain text gehörenden steps. Man füge einfach noch folgendes Snippet mit ein:</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
module Spec
  module Story
    class StepGroup
      alias_method :Wenn, :When
      alias_method :Gegeben, :Given
      alias_method :Dann, :Then
    end
  end
end
</textarea>
<p>Und schon kann man seine Stories auf deutsch schreiben (sorry das Beispiel ist irgendwie grauenhaft sinnlos, es ist schon spät):</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
Story: Als ich will ich ich sein damit ich mal so richtig ich sein kann
  Szenario: ich bin ich bin ich
    Gegben ich
    Wenn ich ich bin
    Dann soll ich auch ich sein
</textarea>
<p>Und dann in den zugehörigen steps:</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
require File.join(File.dirname(__FILE__), '../helper')


with_steps_for :common do
  Gegeben 'ich' do
    @me = create_me
  end
  Wenn 'ich ich bin' do
    @me.be_me
  end
  Dann 'soll $expected auch $result sein' do |expected, result|
    expected.should == result
  end
	
  run File.dirname(__FILE__) + '/ich_story.txt', :type => RailsStory
end

</textarea>
<p>Ach ja, one more thing: Um im Story Runner so eine Art setup/teardown zu haben, einfach noch ein wenig Code in den helper:</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
class MyStoryListener
  def scenario_started(story, scenario)
    # hier setup code
  end
  
  def method_missing(method, *args)
     # no-op
  end
end

Spec::Story::Runner.register_listener(MyStoryListener.new)
</textarea>
]]></content:encoded>
			<wfw:commentRss>http://upstream-berlin.com/2008/07/14/rspec-story-runner-auf-deutsch/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Moving from Rails 2.0.x to Rails 2.1 [Updated]</title>
		<link>http://upstream-berlin.com/2008/06/04/moving-from-rails-20x-to-rails-21/</link>
		<comments>http://upstream-berlin.com/2008/06/04/moving-from-rails-20x-to-rails-21/#comments</comments>
		<pubDate>Wed, 04 Jun 2008 09:59:26 +0000</pubDate>
		<dc:creator>thilo</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[active_record]]></category>

		<category><![CDATA[caching]]></category>

		<category><![CDATA[define_callbacks]]></category>

		<category><![CDATA[rails]]></category>

		<category><![CDATA[rails2.1]]></category>

		<category><![CDATA[rails20]]></category>

		<category><![CDATA[test_cache]]></category>

		<category><![CDATA[update]]></category>

		<category><![CDATA[will_paginate]]></category>

		<guid isPermaLink="false">http://upstream-berlin.com/blog/2008/06/04/moving-from-rails-20x-to-rails-21/</guid>
		<description><![CDATA[We are in the process of moving our production code from autoki to the shiny new rails 2.1 and thanks to our unit tests/(r)specs we encountered some gotchas and wows we&#8217;d like to share. 
Here are some things that change in rails you shold be aware of.
If you are using custom callbacks for you rails [...]]]></description>
			<content:encoded><![CDATA[<p>We are in the process of moving our production code from <a href="http://autoki.com">autoki</a> to the shiny new <a href="http://weblog.rubyonrails.org/2008/6/1/rails-2-1-time-zones-dirty-caching-gem-dependencies-caching-etc">rails 2.1</a> and thanks to our unit tests/(r)specs we encountered some gotchas and wows we&#8217;d like to share. </p>
<p>Here are some things that change in rails you shold be aware of.<br />
If you are using custom callbacks for you rails observer you now have to tell rails about these callbacks first. Simply add a <code>define_callbacks :your_callback, :your_other_callback</code> in models with custom callbacks.</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
class GroupMembership &lt; ActiveRecord::Base
  
  belongs_to :member, :foreign_key => :user_id, :class_name => 'User'
  ...
  define_callback :after_confirm # required since 2.1 
  ...
  def confirm!
    update_attribute :status, 'active'
    callback :after_confirm # custom callback
  end
end

class GroupMembershipObserver &lt; ActiveRecord::Observer
  def after_confirm(group_membership) # will be called from confirm! in the GroupMembership
    some code here
  end
end
</textarea>
<p><span id="more-194"></span><br />
The call to register custom template handlers in the enviroment has changed from <code>ActionView::Base.register_template_handler</code> to <code>ActionView::Template.register_template_handler</code>. With a custom handler you can output pdfs for example.</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
#register a tempalte handler in enviroment.rb or as an initializer
# pdf renderer
require 'pdf_render'
ActionView::Template.register_template_handler 'rpdf', ActionView::PDFRender
</textarea>
<p>Consequently the <code>ActionController::MissingTempalte</code> Error was moved to <code>ActionView::MissingTemplate</code>.</p>
<p>With the <a href="http://ryandaigle.com/articles/2007/12/19/what-s-new-in-edge-rails-pluggable-controller-caching">new Caching</a> in place the config call changed from <code>fragment_cache_store</code> to <code>cache_store</code> to reflect the new unified caching infrastructure.</p>
<p>If you have included the Observable mixin in one of your ActiveRecord models, like we did before we learned to <a href="http://upstream-berlin.com/blog/2007/10/27/using-and-testing-activerecordrails-observers/">harness the power of <code>ActiveRecord::Observer</code></a>, it&#8217;s time to abandon these because the <code>changed</code> method overwrites the new <code>changed</code> of ActivRecords dirty tracking. So if your stack trace look similar to this&#8230;</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
NoMethodError: undefined method `each' for true:TrueClass
method attributes_with_quotes in base.rb at line 2574
method update_without_lock in base.rb at line 2479
method update_without_dirty in optimistic.rb at line 70
...
</textarea>
<p>.. it&#8217;s <code>Observable</code> overwriting the ActiveRecord <code>changed</code> method.</p>
<p>What also comes with <a href="http://ryandaigle.com/articles/2008/3/31/what-s-new-in-edge-rails-dirty-objects">dirty tracking</a> is, that a save call does nothing unless someting really changed. Although this is the desired behavior, it might break logic where you rely on the old behavior, e.g. when you just want to update the time stamps of an object in the database. You can tell the object with <code>attr_name_will_change!</code> that an attribute should be written to the database. </p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
class User &lt; ActiveRecord::Base
  def visit #should set updated at to current time if visited
     updated_at_will_change! #tell the user that updated_at field will change 
     self.save 
   end
end
</textarea>
<p>Another ActiveRecord change we found is that <code>:dependent => true</code> isn&#8217;t supported anymore although I don&#8217;t remember a deprecation warning. Just use <code>:dependent => :nullfiy|:delete|:destroy</code>.</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
class User &lt; ActiveRecord::Base
 has_one :profile, :dependent => true #this will break, use :nullfiy|:delete|:destroy instead
end
</textarea>
<p>But now let&#8217;s come to some nice stuff we discovered.</p>
<p>ActiveRecord now complains with a <code>stack level to deep</code> if you have circular dependency behaviors defined, eg. User has_one :profile, :dependent => :destroy and Profile belogs_to :user, :dependent => :destroy. Such logic can just be the result of isolated late night coding, so an error is the desired behavior in my opinion.</p>
<p>Let&#8217;s get back to the aforementioned <code>changed</code> method. Because it returns an array of changed field names, it is a good way to fire after save actions only if a specific field changed. For our autoki application it is a good way to fire some image processing task only if the auto picture changed. </p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
class Auto &lt; ActiveRecord::Base
  after_save :build_new_image
  private
  def build_new_image 
    regenerate_widget if changed.include?(:image) # only do this when the image was changed
  end
end
end
</textarea>
<p>At the end comes the real nasty stuff. Rails 2.1 really wrecks havoc under the plugins we are using. As you might guess the most have to do with caching.</p>
<p>While the fragement_cache_test plugins error <code>uninitialized constant ActionController::Caching::Fragments::MemoryStore</code> can be fixed relatively easy by changing the base class for the <code>TestStore</code>class in <code>frament_cache_test.rb</code> to <code>ActiveSupport::Cache::MemoryStore</code> and the calls to <code>reset</code> have do be changed to <code>clear</code> the <a href="extended_fragment_cache">timed_fragment_cache</a> plugin and the <a href="http://rubyforge.org/projects/zventstools/">extended_fragment_cache</a> are rendered useless until updated, which we don&#8217;t expect to happen, so we put together the <a href="http://github.com/langalex/local_cache/tree/master/README">local_cache_plugin</a> as a resplacement for both.</p>
<p><a href="http://github.com/mislav/will_paginate/wikis">Will_paginate</a> requires an update from git, and it will play nice again. It resides on <a href="http://github.com">github</a> now and can be installed with <code>script/install git://github.com/mislav/will_paginate.git</code> thanks to the install script git support.</p>
<p>The paginated search plugin for ferret will require an update too, because of the changes in will_paginate. But it&#8217;s still maintained so just grap the <a href="http://opensoul.org/2007/8/17/acts_as_ferret-will_paginate">new code from the opensoul blog</a>.</p>
<p>So that&#8217;s all for now. (Wow this post got big) </p>
<p>We aren&#8217;t finish yet so we will post more while we find other noteworthy changes. </p>
]]></content:encoded>
			<wfw:commentRss>http://upstream-berlin.com/2008/06/04/moving-from-rails-20x-to-rails-21/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Dealing with legacy databases - multiple models per table</title>
		<link>http://upstream-berlin.com/2008/06/04/dealing-with-legacy-databases-multiple-models-per-table/</link>
		<comments>http://upstream-berlin.com/2008/06/04/dealing-with-legacy-databases-multiple-models-per-table/#comments</comments>
		<pubDate>Wed, 04 Jun 2008 09:33:30 +0000</pubDate>
		<dc:creator>Alexander Lang</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[activerecord]]></category>

		<category><![CDATA[legacy database]]></category>

		<category><![CDATA[multiple models]]></category>

		<category><![CDATA[rails]]></category>

		<category><![CDATA[scopes]]></category>

		<category><![CDATA[scope_out]]></category>

		<category><![CDATA[set_table_name]]></category>

		<category><![CDATA[table]]></category>

		<guid isPermaLink="false">http://upstream-berlin.com/blog/2008/06/04/dealing-with-legacy-databases-multiple-models-per-table/</guid>
		<description><![CDATA[On a recent Rails project I had to use an old database schema that had been designed years ago for some php app. The two main entities in the application were companies and their projects. For whatever reason the designer had created one huge table called organizations with all the companies and projects inside. A [...]]]></description>
			<content:encoded><![CDATA[<p>On a recent Rails project I had to use an old database schema that had been designed years ago for some php app. The two main entities in the application were companies and their projects. For whatever reason the designer had created one huge table called organizations with all the companies and projects inside. A row in the database marked a company when the <em>is_company</em> column was 1 and a project when the <em>is_project</em> column was 1.</p>
<pre style="font-family:courier;font-size: 12px">
|----------------------------------------------------|
| id | name                | is_company | is_project |
|----------------------------------------------------|
| 1  | google              | 1          | 0          |
| 2  | world domination    | 0          | 1          |
|----------------------------------------------------|</pre>
<p>In my rails app I created two ActiveRecord models: Company and Project and set the table name for both to organizations:</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
class Company
  set_table_name 'organizations'
end

class Project
  set_table_name 'organizations'
end

</textarea>
<p>Now the real problem was his: when I did a <code>Company.find :all</code> I got all the companies and all the projects, so I had to do this instead: <code>Company.find :all, :conditions => {:is_company => true}</code> - throughout the project, and whenever I forgot the condition somewhere all the projects showed up in the wrong place. So what I needed was a generic solution.</p>
<p>To make a longer story short I played with <a href="http://code.google.com/p/scope-out-rails/">scope_out</a> defining a <code>projects</code> scope on the Company model, so I could at least do <code>Company.find_all_companies</code> and didn&#8217;t have to specify the conditions over and over again - but that still wasn&#8217;t DRY at all. One morning short after waking up (the time I usually have the best ideas) it dawned on me how simple the solution actually is:</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
class Company
  def self.find(*params)
    with_scope(:find => {:conditions => {:is_company => true}}) do
      super
    end
  end
  
  def self.count(*params)
    with_scope(:find => {:conditions => {:is_company => true}}) do
      super
    end
  end
end
</textarea>
<p>I added a scope around all find and count calls of my model and now I can just do whatever find operations I want and don&#8217;t have to think about scopes and tables ever again. Sweet object encapsulation.</p>
]]></content:encoded>
			<wfw:commentRss>http://upstream-berlin.com/2008/06/04/dealing-with-legacy-databases-multiple-models-per-table/feed/</wfw:commentRss>
		</item>
		<item>
		<title>New plugin: totally restful authorization</title>
		<link>http://upstream-berlin.com/2008/06/03/new-plugin-totally-restful-authorization/</link>
		<comments>http://upstream-berlin.com/2008/06/03/new-plugin-totally-restful-authorization/#comments</comments>
		<pubDate>Tue, 03 Jun 2008 08:48:38 +0000</pubDate>
		<dc:creator>Alexander Lang</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[authorization]]></category>

		<category><![CDATA[declarative]]></category>

		<category><![CDATA[dsl]]></category>

		<category><![CDATA[permission]]></category>

		<category><![CDATA[plugin]]></category>

		<category><![CDATA[rails]]></category>

		<category><![CDATA[rest]]></category>

		<category><![CDATA[transparent]]></category>

		<guid isPermaLink="false">http://upstream-berlin.com/blog/2008/06/03/new-plugin-totally-restful-authorization/</guid>
		<description><![CDATA[We have again released a new plugin. Continuing the series of completely original names it&#8217;s called totally restful authorization. 
The exec summary: you can declaratively add permissions to your (ActiveRecord) models for creating, viewing, updating and destroying them. A set of before filters automagically checks all incoming requests on your restful controllers for the permission [...]]]></description>
			<content:encoded><![CDATA[<p>We have again released a new plugin. Continuing the series of completely original names it&#8217;s called <a href="http://github.com/langalex/totally-restful-authorization">totally restful authorization</a>. </p>
<p><strong>The exec summary:</strong> you can declaratively add permissions to your (ActiveRecord) models for creating, viewing, updating and destroying them. A set of before filters automagically checks all incoming requests on your restful controllers for the permission and grants or denies access based on the permissions declared on the respective model.</p>
<h3>How to install</h3>
<p>Now with Rails 2.1 out all you have to do is <code>script/plugin install git://github.com/langalex/totally-restful-authorization.git</code>. </p>
<h3>How to use</h3>
<p>Include he PermissionCheck Module into the controllers you want to be checked or simply into the ApplicationController to secure your entire application.</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
class ApplicationController &lt; ActionController::Base
  include PermissionCheck

  ...
end
</textarea>
<p>Second, declare permissions on your model using the built in <a href="http://en.wikipedia.org/wiki/Domain_specific_language">domain specific language</a>.</p>
<textarea name="code" class="ruby:showcolumns" cols="60" rows="10">
class User
  updatable_by :admin # updatable if updater.admin? return true
  updatable_by :self, :except => [:admin] # special role self, allow all attributes except some to be updated
  updatable_by :newbie, :only => [:description] # only allow some attribute to be updated
  
  viewable_by :anyone # special role, includes nil
  
  destroyable_by [:admin, :root] # declare multiple roles at once
end

</textarea>
<p>That&#8217;s it. From now on all requests will be checked against your model permissions and be blocked if the authorization fails. For more details see the <a href="http://github.com/langalex/totally-restful-authorization/tree/master%2FREADME?raw=true">README</a> and the <a href="http://github.com/langalex/totally-restful-authorization/tree/master/test/unit">unit tests</a>. (Btw. if anyone has a good idea on how to replace the controller tests with <a href="http://rspec.info">RSpec</a> specs, i.e. get controller specs working in a plugin please tell me)</p>
]]></content:encoded>
			<wfw:commentRss>http://upstream-berlin.com/2008/06/03/new-plugin-totally-restful-authorization/feed/</wfw:commentRss>
		</item>
		<item>
		<title>MySql - Teil 1: Den richtigen Index finden</title>
		<link>http://upstream-berlin.com/2008/06/03/mysql-teil-1-den-richtigen-index-finden/</link>
		<comments>http://upstream-berlin.com/2008/06/03/mysql-teil-1-den-richtigen-index-finden/#comments</comments>
		<pubDate>Tue, 03 Jun 2008 07:54:57 +0000</pubDate>
		<dc:creator>thilo</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[index]]></category>

		<category><![CDATA[indices]]></category>

		<category><![CDATA[indizes]]></category>

		<category><![CDATA[logging]]></category>

		<category><![CDATA[mysql]]></category>

		<category><![CDATA[slow query log]]></category>

		<category><![CDATA[table scan]]></category>

		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://upstream-berlin.com/blog/2008/06/03/mysql-teil-1-den-richtigen-index-finden/</guid>
		<description><![CDATA[Die Datenbak MySql ist bei Webanwendungen sehr verbreitet, unter anderem weil sie kostenlos, relativ schnell und etabliert ist. Auch bei uns verrichtet MySQL  zuverlässig seinen Dienst. Grund genug mal unsere Erfahrungen in ein paar Blogeinträge zu gießen und damit das rumlavieren in der sehr umfangreichen offiziellen Dokumentation auf echte Härtefälle zu beschränken. 
Zuerst schauen [...]]]></description>
			<content:encoded><![CDATA[<p>Die Datenbak MySql ist bei Webanwendungen sehr verbreitet, unter anderem weil sie kostenlos, relativ schnell und etabliert ist. Auch bei uns verrichtet MySQL  zuverlässig seinen Dienst. Grund genug mal unsere Erfahrungen in ein paar Blogeinträge zu gießen und damit das rumlavieren in der sehr umfangreichen <a href="http://dev.mysql.com/doc/refman/5.1/de/index.html">offiziellen Dokumentation</a> auf echte Härtefälle zu beschränken. </p>
<p>Zuerst schauen wir uns mal an welche Werkzeuge MySQL von Hause aus mitbringt, um beim Erstellen von sinnvollen Indizes zu helfen.<br />
<span id="more-191"></span><br />
Mit <code>EXPLAIN</code> vor einem <code>SELECT</code> in der MySQL Shell lässt sich erst einmal herausfinden, wie einzelne Abfragen ausgeführt werden. So lassen sich gut Informationen über verwendete und fehlende Indizes sammeln. Das Ergebnis von EXPLAIN wird standardmäßig als Tabelle ausgegeben. Hier kurz was die Angaben bedeuten. Die Spalte <code>table</code> gibt den Namen der abgefragten Tabelle an. Unter <code>type</code> steht die Art des Lesezugriffs. Steht dort <code>ALL</code> wird ein Table Scan durchgeführt. Unter <code>possible_keys</code> stehen die Namen der verfügbaren Indizes. Die Spalte key enthält die bei der Abfrage verwendeten Index. Es kann nur ein Index verwendet werden. Unter <code>extra</code> stehen die Einschränkungen nach denen die Zeilen ausgewählt werden. Steht unter type ALL, aber in den Bedingungen &#8216;using where&#8217; fehlt mit Sicherheit ein geeigneter Index.  Ein Grund, warum selbst ein vorhandener Index nicht verwendet wird, ist, dass die WHERE-Bedingung zu weit gefasst ist.  Unter diesen Umständen ist die Verwendung eines Indizes aufwendiger als ein Table Scan.  Ein gutes Beispiel für eine zu weit gefasst Abfrage ist, alle Frauen aus einer Nutzertabelle zu laden, da etwa die Hälfte aller Nutzer Frauen sind, ist der Aufwand für den Einsatz von Indizes viel zu groß und wird daher von MySQL ausgeschlossen. Als Richtwert gilt, wenn 20% oder weniger Zeilen durch eine Bedingung erfasst werden ist der Einsatz eines Indexes sinnvoll. Oder anders herum gesagt, ein Index sollte eine gute Selektivität besitzen. Mit <code>EXPLAIN tablename</code> lässt sich herausfinden, welche Spalten einer Tabelle bereits mit einem Index versehen sind. </p>
<p>Aber nicht nur die Selektivität eines Index ist entscheidend, denn jeder Index kommt zu dem Preis, dass er bei einer Änderung der Tabelle mit geändert werden muss und so <code>INSERTS</code>, <code>UPDATES</code> und <code>DELETES</code> länger dauern. Also ist auch darauf zu achten wie viele Spalten der Index umfasst und wie lang die Schlüssel sind. Darum ist es gut ersteinmal zu ermitteln, welche Abfragen am meisten von einem Index profitieren würden. Um diese im Live-Betrieb zu ermitteln ist der Loggingmechanismus von MySQL ein praktisches Werkzeug. Das Logging lässt sich in der Konfigurationsdatei my.cnf (bei *nix Systemen in <code>/etc/mysql/</code> zu finden) des Servers einrichten. Um Abfragen, die besonders lange dauern, mitzuloggen, muss dies mit <code>log_slow_queries  = /var/log/mysql/mysql-slow.log</code> aktiviert werden. Mit dem Parameter <code>long_query_time = 2</code> kann in Sekunden angegeben werden, ab welcher Ausführungsdauer eine Abfrage mitgelogged wird. Um Abfragen ins Log zu schreiben die keinen Index verwenden kann <code>log-queries-not-using-indexes</code> in die Konfigurationsdatein eingetragen werden. Vorsicht, diese Einstellung kann ordentlich viel Output erzeugen. </p>
<p>Dass waren jetzt die einfachen Bordmittel, die dabei helfen können, sinnvolle Indizes zu vergeben. Das Letzte Wort zu Indices ist damit aber noch nicht gesprochen, denn beim Locking, womit sich der nächste Post befasst, spielen sie auch eine wichtige Rolle.</p>
]]></content:encoded>
			<wfw:commentRss>http://upstream-berlin.com/2008/06/03/mysql-teil-1-den-richtigen-index-finden/feed/</wfw:commentRss>
		</item>
		<item>
		<title>New Rails Plugin for making ActionMailer asynchronous</title>
		<link>http://upstream-berlin.com/2008/05/19/new-rails-plugin-for-making-actionmailer-asynchronous/</link>
		<comments>http://upstream-berlin.com/2008/05/19/new-rails-plugin-for-making-actionmailer-asynchronous/#comments</comments>
		<pubDate>Mon, 19 May 2008 12:09:06 +0000</pubDate>
		<dc:creator>Alexander Lang</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[actionmailer]]></category>

		<category><![CDATA[asynchronous]]></category>

		<category><![CDATA[database]]></category>

		<category><![CDATA[email]]></category>

		<category><![CDATA[rails]]></category>

		<category><![CDATA[ruby]]></category>

		<category><![CDATA[timeouts]]></category>

		<category><![CDATA[workling]]></category>

		<guid isPermaLink="false">http://upstream-berlin.com/blog/2008/05/19/new-rails-plugin-for-making-actionmailer-asynchronous/</guid>
		<description><![CDATA[We have just released a new rails plugin called workling_mailer. This plugin provides a module which - when included into an ActionMailer subclass - pushes all emails that would normally be delivered synchronously into a queue for asynchronous processing. For queuing it relies on the workling plugin which can use for example twitter&#8217;s starling as [...]]]></description>
			<content:encoded><![CDATA[<p>We have just released a new rails plugin called <em>workling_mailer</em>. This plugin provides a module which - when included into an ActionMailer subclass - pushes all emails that would normally be delivered synchronously into a queue for asynchronous processing. For queuing it relies on the <a href="http://playtype.net/past/2008/2/6/starling_and_asynchrous_tasks_in_ruby_on_rails/">workling plugin</a> which can use for example twitter&#8217;s starling as a queue server.</p>
<p>We use this on <a href="http://autoki.com">autoki</a> which sends a lot of email (thanks to our <a href="http://upstream-berlin.com/blog/2008/04/25/new-rails-plugin-social-feed/">social feed plugin</a> <img src='http://upstream-berlin.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ).</p>
<p>Recently we got errors from the mailserver complaining about too many concurrent connections. This did not only cause emails not being delivered and our users getting an error page, it also caused long running transactions in the database: if you send an email within an <code>after_create</code> hook in a model this happens inside of the database transaction. That means that if you have a 60s timeout on your mail server you end up with database transactions taking 60s to finish (or being rolled back in this case) which essentially locks up your tables after a short period of time.</p>
<p>Now that we are sending our emails from a queue one at a time, the mailserver is happy and our database transactions are again as short as they should be.</p>
<p>You can get the sources at <a href="http://github.com/langalex/workling_mailer/">github</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://upstream-berlin.com/2008/05/19/new-rails-plugin-for-making-actionmailer-asynchronous/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Git commits in the blog sidebar</title>
		<link>http://upstream-berlin.com/2008/04/25/git-commits-in-the-blog-sidebar/</link>
		<comments>http://upstream-berlin.com/2008/04/25/git-commits-in-the-blog-sidebar/#comments</comments>
		<pubDate>Fri, 25 Apr 2008 14:47:53 +0000</pubDate>
		<dc:creator>Alexander Lang</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[blog]]></category>

		<category><![CDATA[commits]]></category>

		<category><![CDATA[github]]></category>

		<category><![CDATA[mashup]]></category>

		<category><![CDATA[open-source]]></category>

		<category><![CDATA[pipes]]></category>

		<category><![CDATA[rss]]></category>

		<category><![CDATA[upstream]]></category>

		<category><![CDATA[yahoo]]></category>

		<guid isPermaLink="false">http://upstream-berlin.com/blog/2008/04/25/git-commits-in-the-blog-sidebar/</guid>
		<description><![CDATA[As the careful reader might have noticed, we have added another RSS feed to the blog sidebar. Under the keiala product blog you can now see our commits to all our open source repositories on github. To make this possible I have used yahoo pipes for the first time. The pipe consumes the RSS feeds [...]]]></description>
			<content:encoded><![CDATA[<p>As the careful reader might have noticed, we have added another RSS feed to the blog sidebar. Under the <a href="http://blog.keiala.com">keiala product blog</a> you can now see our commits to all our open source repositories on <a href="http://github.com/langalex">github</a>. To make this possible I have used <a href="http://http://pipes.yahoo.com/">yahoo pipes</a> for the first time. The pipe consumes the RSS feeds of all our open source projects on github, merges these into one, prefixes the titles with the project names and also truncates them, before wordpress consumes that pipe&#8217;s output and displays it in a sidebar widget. That&#8217;s what I call a real mashup. <img src='http://upstream-berlin.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> If anyone is interested, here&#8217;s <a href="http://pipes.yahoo.com/pipes/pipe.info?_id=9I7dtOoR3RGi1GANj0nRlg">the pipe</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://upstream-berlin.com/2008/04/25/git-commits-in-the-blog-sidebar/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
