Logo

Thin PC’s

over 2 years ago | Amar Phadke: Amar Phadke's weblog

I had a thought the other day. What do most people use their pc for? Checking emails, chatting, tracking stocks & financial accounts, sharing pictures, reading news, researching deals. Activities that only require Internet access. Do they really need a local computing machine for all this? Can this not be done by something that has [...]

Encrypting/Decrypting primary key appearing in the URL

over 2 years ago | Amit Kumar: RubyizednRailified

I paid a small cost for being RESTful.

As RESTful suggests, the GET request will always have the primary key in the URL like: http://somesite.com/somecontroller/123/edit

In the app we have role based access and only admins have access to edit. We made sure that the application is protected and only admins can update an existing record. The so called Security had a different perspective. They were not willing to expose the id(=123). The solution was to encrypt the id.

I came across a good blog here.

Following the same concept:

  1. I added a EncryptDecryptHelper module inside my lib directory. The module has 2 methods.
  2. encrypt -> used OpenSSl Cipher RC4 digest and Base64 encoding of the string for an already defined KEY and IV
  3. decrypt -> used the same KEY and IV to decode the string
  4. Included the module inside my model and over-ride to_param to encrypt the primary key.
  5. Added a before filter method on the application controller to decrypt the primary key.Made sure we are passing objects instead of id while creating links eg:-
  • Do:
<%= link_to 'city', :controller=>'cities',:action=>'show',:id => @city %>

Instead of:

<%= link_to 'city', :controller=>'cities',:action=>'show',:id => @city.id %>

The security team is happy now.

Kitchen Lust: FrancisFrancis! Espresso Machine

over 2 years ago | Megan Blocker: Queenie Takes Manhattan

Like any good New Yorker, I love coffee. Cannot get enough. Would drink it morning, noon and night if I could, and often do, frankly. (Not all the time, though - a girl needs to leave room for her Diet Coke and her booze.)

My coffeemaker of choice is a Bodum Chambord French press - I love it for the counter space it saves and also for the rich, hearty brew it produces. But one thing it doesn't do is make espresso.

To date, I haven't invested in an espresso maker - it seems like an awful lot of money for something that would probably be used two times a week, maximum. Plus, it would take up precious counter space in my tiny kitchen. But, if I could buy any espresso maker on earth, I think it would have to be this powder-blue FrancisFrancis! model. It's gorgeous, it's hard-working, and it's long-lasting. What more could a girl want?

But, alas, at almost $900, it's way out of reach. So I think I might go low-tech and spring for this Bialetti stovetop model. Starting at $20 for a three-cupper, it seems like the way to go. Plus, it's charmingly retro in its own way, dontcha think?I sure do.

I'm in love. (Calm down, it's with a blog.)

over 2 years ago | Megan Blocker: Queenie Takes Manhattan

Matt Wright is a British expat living in Seattle, where he's created an impressively beautiful blog that's full of recipes and bursts with a palpable fondness for the food he prepares.

Just this week he posted a recipe for braised pork belly, pickled shallots and beans (a play on the classic pork and beans combination), at which point I decided he must be one of my culinary soulmates.

Go check it out here. You won't be sorry, I promise.

Oh, and you can bet on those pickled shallots making an appearance on my table awfully soon.

Photo courtesy of wrightfood.

Share these with your friends.

over 2 years ago | Megan Blocker: Queenie Takes Manhattan

One of the great pleasures of entertaining overnight visitors, or of being a houseguest, is enjoying breakfast with your friends. Sure, we city-dwellers enjoy our fair portion of shared brunches, and more than our allotment of shared dinners, but we rarely see our friends spreading jam on toast while still wearing their footsie pajamas.

Maybe it's because I live alone, but, to me, eating breakfast with friends is a real treat, a true novelty, and something I really look forward to when traveling. And it doesn't have to be a fancy pancake breakfast, either (though those are fun, too) - sometimes the best breakfast is just coffee and a brioche smeared with butter and jam.

Louisa and I made our first loaves of brioche together last summer, and during my visit this year we decided we couldn't let the opportunity to create a true tradition pass us by. This time, though, we decided to make one full loaf and six small, traditional brioches, the better to snack and breakfast on.

The little guys were just as easy to make as the big one - we followed the same recipe as last time and used half the dough to fill Louisa's silicon brioche pan (with a cookie sheet underneath to lend stability to the flexible material) and half for the loaf. You could also use the more traditional brioche molds - again, just stick them on a cookie sheet to make the whole thing easier. We topped the individual brioches with the same egg wash used on the loaf, and added some muscovado sugar for added crunch (and to make things all pretty-like).

The result? A loaf for French bread and sandwich-making, and six perfect breakfast treats, perfect for enjoying with friends and a big pot of coffee.

Adopting scrum is subjective

over 2 years ago | Bhargav Gandhi: AGILE SOFTWARE DEVELOPMENT

I have experienced that "scrum is subjective to the teams" in my current project. I am working on an existing legacy java application. I am part of a scrum team of 10 people. We are termed as one of the high performing scrum teams at my company. Our client is so pleased that they want to retain the same for another project :).

But when I tried to analyse our success, I realised that we never followed scrum 100%! Following are the things that make me believe so:-


  • Sprint backlogs did change during the sprints. Team was able to accomodate new stories and deliver value addition. There were many sprints where we could deliver extra credit stories.
  • Team used to skip standup calls on days when team(onsite+offshore) didn't have much updates/risks to share.
  • Since we were working on a legacy application, the team's estimates were high during the release planning due the less acquaintance with the application. But as we spent more and more time on the application, we were able to revise and reduce the estimates. Once, we changed the estimates during the sprint!!

Following are some of the things that we didn't do and saved time.

  • Never created a release burndown chart
  • Never created a sprint burndown chart
  • Never tracked individuals' hours spent on the tasks

So I feel team should be empowered to decide what works for them and what not. They should alter the scrum in a way that works best for them. I have seen teams with 100% adherence to scrum but performing poorly in terms of the development and delivery.

Any thoughts??

How to host a dinner party without turning on the stove. Well, almost.

over 2 years ago | Megan Blocker: Queenie Takes Manhattan

It's that time of year - the market is full of berries, tomatoes, corn, summer squash, and I'm desperate to cook it all before it goes away. Which of course means that I'm desperate to entertain as many friends as possible, the better to experiment with copious amounts of produce and seafood.

The only problem? It's really freakin' hot out, and that makes having people over a bit more complicated. Sure, I have a great AC stuck through one of my two windows, but it doesn't do a whole lot when the oven and stove are going full blast and there are five extra people in here.

So, what's a girl to do? Moving is not an option, nor is the complete absence of cooking. Not for me, anyway. So I spend my summers searching high and low for meals that can be made in advance, served mostly at room temperature, and showcase all the delicious things in season right now. Because, really, most of this stuff is better left as pristine as possible. I mean, there's nothing better than popping a single, tart blueberry in your mouth, or stealing a ripe, earthy tomato from the bowl and eating it plain.

Two weeks ago, this meant starting with a gorgeous corn soup courtesy of Dorie Greenspan, and following that up with a giant salad niçoise and a buttermilk cake with mascarpone and berries. As far as no-cook meals go, this was on the more-cooking-than-not end of the scale. The soup was made ahead but had to be re-heated, the salad took lots of prep work, even though it was all super-easy, the tuna had to be seared just before eating, and the cake couldn't be assembled ahead of time.

Last night, though, I served what I think might just be the perfect summertime dinner party meal. We started things off with homemade gravlax - which meant, literally, zero cooking. You just cure the raw salmon in a salt/sugar/pepper/dill mixture, then serve it with a coffee and mustard flavored sauce.

Next up, Ina Garten's superlative gazpacho. A lot of chopping, but, again, no cooking. (And, as gazpacho goes, remarkably deep in flavor and perfectly imperfect in texture.) Ina swooped in to my rescue again for the main, which was her "summer garden pasta" - a big bowl of cherry tomatoes marinated for five hours in olive oil, garlic and basil, then tossed with hot capellini and grated parmesan. Yes, you have to cook the pasta, but since it's angel hair, it takes less than five minutes.

To cleanse our palates of all that garlic (12 cloves in all, between the gazpacho and the pasta), we had a small watermelon salad with basil and pickled jalapenos. Sweet, refreshing, but with a slow, savory burn on the tongue from the peppers. Then, finally, the piece de resistance - a ridiculously delicious tart loaded with four pints of blueberries, courtesy of the Gourmet Cookbook.

There's another benefit to this whole made ahead of time thing - you actually get to spend time with your guests. That might even be a bigger plus than not sweating bullets.

Working with Excel data without working with Excel

over 2 years ago | Alex Rothenberg: Common Sense Software

I am currently working on an application to replace manual MS Excel files that get emailed around and while the business users are looking forward to an interactive web app they are also wedded to their excel files. One of the key requirements we need to meet is allowing them to move their data back and forth.

In the past I've worked with COM and Java libraries to manipulate the files in their native formats and both were painful experiences I did not want to relive. I'm going to talk about how we solved the problem without the need to work with any Office libraries.


Loading Excel data into our Application
The approach we took was to let the users extract the data themselves with a simple copy-and-paste. The user would copy the cells of the excel file and then paste that tab delimited plain text into an HTML form.

Let's say we're trying to import a list of people with a first and last name. The Excel sheet would look like this


We start with a form with a big text area and submit button and an area to show any errors we may encounter while parsing

<% form_tag do -%>
Paste your Excel data : <%= text_area_tag :data, @data %>
Click to validate the data <%= submit_tag 'Validate' %>

<ul>
<% @errors.each do |error| %>
<li><span ><%=error%></span></li>

<% end unless @errors.blank? -%>
</ul>
Then the controller action which let's the model parse the text and only saves if every person model is valid.
class PeopleController <  ApplicationController
def import
@errors = []
people = Person.all_from_tab_delimited_text(params[:data])

people.each do |person|
person.errors.each { |error| @errors << "#{error} on #{person.inspect}"} unless person.valid?
end
end
end
Now we move onto the Person model where the parsing actually takes place
class
class Person < ActiveRecord::Base
def Person.all_from_tab_delimited_text(data)
people = []
CSV::Reader.parse(@data, "\t") do |row|
person = Person.new(:first_name"> row[0], :last_name => row[1])
people << person
end
people
end
end
We now have a working allbeit simple implementation that even does some simple error checking to give the user feedback if their data cannot be imported. Of course the example here is simple and the real system has additional features and complexity that I didn't show here. Some of these are
  • The import into a 2-step operation where we first ask the user to click 'Validate' then return a table showing the data as we parsed it. This allows the user to review and verify it was parsed correctly (i.e. the columns were in the correct order). Only on this second page do we provide an 'import' button that actually persists the new data.
  • The data can not only create new people but also update existing ones. The example above with just first and last name is contrived so this wouldn't make sense but imagine an example where there are many other columns like address, phone number, etc. Our model code is a bit more complex in that it first tries to find a person with the same first and last names. If it succeeds it will then update that person and only creates a new one if there is no match.
  • Some of the additional columns in the real system refer to other models in our system. To deal with these our model code must find other kinds of model objects and pass those into the Person.new. Ensuring the proper errors are sent back to the user in this case is fairly tricky as they may not always show up as part of the ActiveRecord validations.
Downloading data from our app into Excel
Moving data in this direction was even easier as we just relied on the fact that Excel will open csv files as long as our Rails app returns an Excel MIME type. We add a line to register the mime type with the csv extension
# config/initializers/mime_types.rb
Mime::Type.register 'application/vnd.ms-excel', :csv
Then we had to do for this was add a respond_to.xsl in the appropriate places of our controller
class PeopleController < ApplicationController
def index
people = Person.all
respond_to do |format|
format.html # index.html.erb
format.csv do
render :text => @people.collect { |person| person.to_csv}.join("\n")
end
end
end
and then add a to_csv to the model
class Person < ActiveRecord::Base
def to_csv
"#{first_name}\t#{last_name}"
end
end

This only works for very simple Excel data on a single worksheet but when that's true it makes your job of working with that data so much simpler!

Working with Excel data without working with Excel

over 2 years ago | Alex Rothenberg: Common Sense Software

I am currently working on an application to replace manual MS Excel files that get emailed around and while the business users are looking forward to an interactive web app they are also wedded to their excel files. One of the key requirements we need to meet is allowing them to move their data back and forth.

In the past I've worked with COM and Java libraries to manipulate the files in their native formats and both were painful experiences I did not want to relive. I'm going to talk about how we solved the problem without the need to work with any Office libraries.


Loading Excel data into our Application
The approach we took was to let the users extract the data themselves with a simple copy-and-paste. The user would copy the cells of the excel file and then paste that tab delimited plain text into an HTML form.

Let's say we're trying to import a list of people with a first and last name. The Excel sheet would look like this


We start with a form with a big text area and submit button and an area to show any errors we may encounter while parsing

<% form_tag do -%>
Paste your Excel data : <%= text_area_tag :data, @data %>
Click to validate the data <%= submit_tag 'Validate' %>

<ul>
<% @errors.each do |error| %>
<li><span ><%=error%></span></li>

<% end unless @errors.blank? -%>
</ul>
Then the controller action which let's the model parse the text and only saves if every person model is valid.
class PeopleController <  ApplicationController
def import
@errors = []
people = Person.all_from_tab_delimited_text(params[:data])

people.each do |person|
person.errors.each { |error| @errors << "#{error} on #{person.inspect}"} unless person.valid?
end
end
end
Now we move onto the Person model where the parsing actually takes place
class
class Person < ActiveRecord::Base
def Person.all_from_tab_delimited_text(data)
people = []
CSV::Reader.parse(@data, "\t") do |row|
person = Person.new(:first_name"> row[0], :last_name => row[1])
people << person
end
people
end
end
We now have a working allbeit simple implementation that even does some simple error checking to give the user feedback if their data cannot be imported. Of course the example here is simple and the real system has additional features and complexity that I didn't show here. Some of these are
  • The import into a 2-step operation where we first ask the user to click 'Validate' then return a table showing the data as we parsed it. This allows the user to review and verify it was parsed correctly (i.e. the columns were in the correct order). Only on this second page do we provide an 'import' button that actually persists the new data.
  • The data can not only create new people but also update existing ones. The example above with just first and last name is contrived so this wouldn't make sense but imagine an example where there are many other columns like address, phone number, etc. Our model code is a bit more complex in that it first tries to find a person with the same first and last names. If it succeeds it will then update that person and only creates a new one if there is no match.
  • Some of the additional columns in the real system refer to other models in our system. To deal with these our model code must find other kinds of model objects and pass those into the Person.new. Ensuring the proper errors are sent back to the user in this case is fairly tricky as they may not always show up as part of the ActiveRecord validations.
Downloading data from our app into Excel
Moving data in this direction was even easier as we just relied on the fact that Excel will open csv files as long as our Rails app returns an Excel MIME type. We add a line to register the mime type with the csv extension
# config/initializers/mime_types.rb
Mime::Type.register 'application/vnd.ms-excel', :csv
Then we had to do for this was add a respond_to.xsl in the appropriate places of our controller
class PeopleController < ApplicationController
def index
people = Person.all
respond_to do |format|
format.html # index.html.erb
format.csv do
render :text => @people.collect { |person| person.to_csv}.join("\n")
end
end
end
and then add a to_csv to the model
class Person < ActiveRecord::Base
def to_csv
"#{first_name}\t#{last_name}"
end
end

This only works for very simple Excel data on a single worksheet but when that's true it makes your job of working with that data so much simpler!

Sometimes, it just has to be done.

over 2 years ago | Megan Blocker: Queenie Takes Manhattan

Generally speaking, I'm pretty good at turning down sweets. My cravings tend to run in the salty/greasy direction (bad Chinese, fried chicken, Pirate's Booty), but, every so often, a need for cake worms its way in.

Last Sunday, just such a craving hit me like a sack of bricks, and I decided to assuage said sack with a marble cupcake from Two Little Red Hens. Conveniently located about half a block from my Yorkville apartment, it's an adorable bakery specializing in traditional American treats. They have ridiculously good maple scones, beautiful cakes, and witty frosted cookies (featured on Sunday: hot dogs and watermelon slices). They also make a mean iced coffee.

The marble cupcake was good - especially the cake part, which was white sponge swirled with chocolate. The buttercream was tasty, but a bit too cold from the fridge. It just didn't give enough, and as a result broke off in little pieces. It was a bit like eating (really, really) buttery fudge. That said, it did hit the spot.

So, is it bad that this was my dinner on Sunday night?

How to unit test a Java class with static initializers

over 2 years ago | Alex Rothenberg: Common Sense Software

We have a large Java codebase that we're trying to put under test. Since this class was not designed for testability we often run into code that cannot be tested as is. Most often this involves code that assumes it will always be run inside our J2EE Application Server because it depends on classes provided by the server.

I was recently working with someone on this Java class

class Person {
static {
Logger logger = new ContainerLogger();
}

public String doSomething() {
...
logger.info("I did something");
...
}
}
We couldn't create a unit test for the doSomething method because the ContainerLogger class was provided by our application server and couldn't be used outside the container. We refactored to come up with this solution.
class MyClass {
public static Logger _logger;
public Logger logger() {
if (_logger == null) {
logger = new ContainerLogger();
}
return _logger;
}

public String doSomething() {
...
logger().info("I did something");
...
}
}
We refactored our code to access the logger using the accessor method logger() then we also made the logger variable itself public at the same time. Why did we do those two seemingly contradictory things? The accessor method implements the singleton pattern preserving the semantics of the static initializer and the public access to the instance variable _logger allows us to replace the implementation with a mock in our test.
public class TestMyClass extends TestCase {
public void testSomething() {
MyClass._logger = new MockLogger();
assert(MyClass.doSomething(), "expected return");
}
}
I've seen too much legacy Java code that assumes it will always run inside a container but with testing we need to change our mindsets because when running a test we will be outside the container. All dependencies on the container (and in most applications I've seen we don't need that many!) should be encapsulated and able to be mocked through dependency injection. If you do this you'll end up with simpler code that better follows the Single Responsibility Principle

How to unit test a Java class with static initializers

over 2 years ago | Alex Rothenberg: Common Sense Software

We have a large Java codebase that we're trying to put under test. Since this class was not designed for testability we often run into code that cannot be tested as is. Most often this involves code that assumes it will always be run inside our J2EE Application Server because it depends on classes provided by the server.

I was recently working with someone on this Java class

class Person {
static {
Logger logger = new ContainerLogger();
}

public String doSomething() {
...
logger.info("I did something");
...
}
}
We couldn't create a unit test for the doSomething method because the ContainerLogger class was provided by our application server and couldn't be used outside the container. We refactored to come up with this solution.
class MyClass {
public static Logger _logger;
public Logger logger() {
if (_logger == null) {
logger = new ContainerLogger();
}
return _logger;
}

public String doSomething() {
...
logger().info("I did something");
...
}
}
We refactored our code to access the logger using the accessor method logger() then we also made the logger variable itself public at the same time. Why did we do those two seemingly contradictory things? The accessor method implements the singleton pattern preserving the semantics of the static initializer and the public access to the instance variable _logger allows us to replace the implementation with a mock in our test.
public class TestMyClass extends TestCase {
public void testSomething() {
MyClass._logger = new MockLogger();
assert(MyClass.doSomething(), "expected return");
}
}
I've seen too much legacy Java code that assumes it will always run inside a container but with testing we need to change our mindsets because when running a test we will be outside the container. All dependencies on the container (and in most applications I've seen we don't need that many!) should be encapsulated and able to be mocked through dependency injection. If you do this you'll end up with simpler code that better follows the Single Responsibility Principle

Erlang adopters on the rise

over 2 years ago | Karthik Ramachandra : Concrete Abstractions

Stories about new adopters of Erlang are going up day by day. Here are a few:

  • Amazon SimpleDB (here)
  • FaceBook's instant messaging feature(here)
  • Engineyard's new cloud computing platform - vertebra (here)
  • IMDB (here and here)
  • Google gears uses erlang style concurrency(here)
  • Scalaris - A Transactional Scalable Distributed Data Store (pdf: here)
  • Apache couchDB (here)
  • ...

Feel free to add to this list...

Remove rake tasks

over 2 years ago | Amit Kumar: RubyizednRailified

Ever tried over-riding rake task ?

I tried to over-ride and I found that the default always gets called after your implementaion.

Here is what I tried doing:

namespace :db do
  namespace :test do
    task :prepare do |t|
        puts "Skipping Preparing database for Oracle"
    end
  end
end

But the default db:test:prepare was always getting called.

To solve the probelm:

Inside your Rakefile just below you require the rake modules put the following code.

Rake::TaskManager.class_eval do
  def remove_task(task_name)
    @tasks.delete(task_name.to_s)
  end
end

def remove_task(task_name)
  Rake.application.remove_task(task_name)
end
remove_task 'db:test:prepare'

namespace :db do
  namespace :test do
    task :prepare do |t|
      puts "Skipping Preparing database for Oracle"
    end
  end
end

Voila, the italicized code to override the default rake tasks worked.

Hope this helps !!

Some things are inherently complicated and slow ... put them in the right place

over 2 years ago | Alex Rothenberg: Common Sense Software

One of the first lessons I learned when I started working as a software developer professionally was that you don't always have to make an action fast, sometimes its just enough to make it seem fast to a user. This lesson was learned in the 1990s in the context of a Windows application. What we did was quickly draw part of the screen (or a splash image) immediately then do the time consuming work in the background so that by the time the user was ready to interact with the application we'd be ready for them.

Recently I was reminded of this lesson on a website I'm working on. We have a complicated report to show on the user's homepage. My first implementation involved generating the report in real-time when the page is loaded but this was very slooooow. Some profiling and analysis let us make it somewhat faster but not fast enough.

I was stumped until I remembered my old lesson. If it wasn't possible to generate the report quickly, perhaps we could do it sometime when the user wouldn't mind.

Luckily this is a Rails application and ActiveRecord Callbacks make it easy to do this. I could pregenerate the report and update a portion of it each time something is saved. Users expect a save to take some time and don't do it that often. Then generating the homepage becomes just a simple matter of displaying the existing rows.

First I setup my models to call into the report generator every time they change


class Person < ActiveRecord::Base
after_destroy {|person| ReportGenerator::Person.destroyed(person)}
after_create {|person| ReportGenerator::Person.created(person) }
after_update {|person| ReportGenerator::Person.updated(person) }
end


Then I implement the complicated (and slow) logic to pre-compute the rows in the report in a library class


module ReportGenerator
class Executive
def destroyed(executive)
#figure out which rows to delete from the report and persist with the Report model
end
def created(executive)
#figure out which rows to add to the report and persist with the Report model
end
def updated(executive)
#figure out which rows to update in the report and persist with the Report model
end
end
#Similar classes corresponding to the other models that trigger recalculations would go here
end


Finally I can show the report on the homepage with some boring (and fast) Rails code

Model:

class Report < ActiveRecord::Base
end


Controller:

class ReportsController < ApplicationController
@report =" ReportRows.find_by_user(current_user)">


and the View:


<% for row in @report %>
Display the row
<% end %>


The interesting insight for me is that when optimizing there are sometimes hard problems that can't be solved. Its important not to lose sight of the goal you're aiming at (a satisfying user experience) and that sometimes involves spending the computational time somewhere where the user won't mind.

Some things are inherently complicated and slow ... put them in the right place

over 2 years ago | Alex Rothenberg: Common Sense Software

One of the first lessons I learned when I started working as a software developer professionally was that you don't always have to make an action fast, sometimes its just enough to make it seem fast to a user. This lesson was learned in the 1990s in the context of a Windows application. What we did was quickly draw part of the screen (or a splash image) immediately then do the time consuming work in the background so that by the time the user was ready to interact with the application we'd be ready for them.

Recently I was reminded of this lesson on a website I'm working on. We have a complicated report to show on the user's homepage. My first implementation involved generating the report in real-time when the page is loaded but this was very slooooow. Some profiling and analysis let us make it somewhat faster but not fast enough.

I was stumped until I remembered my old lesson. If it wasn't possible to generate the report quickly, perhaps we could do it sometime when the user wouldn't mind.

Luckily this is a Rails application and ActiveRecord Callbacks make it easy to do this. I could pregenerate the report and update a portion of it each time something is saved. Users expect a save to take some time and don't do it that often. Then generating the homepage becomes just a simple matter of displaying the existing rows.

First I setup my models to call into the report generator every time they change


class Person < ActiveRecord::Base
after_destroy {|person| ReportGenerator::Person.destroyed(person)}
after_create {|person| ReportGenerator::Person.created(person) }
after_update {|person| ReportGenerator::Person.updated(person) }
end


Then I implement the complicated (and slow) logic to pre-compute the rows in the report in a library class


module ReportGenerator
class Executive
def destroyed(executive)
#figure out which rows to delete from the report and persist with the Report model
end
def created(executive)
#figure out which rows to add to the report and persist with the Report model
end
def updated(executive)
#figure out which rows to update in the report and persist with the Report model
end
end
#Similar classes corresponding to the other models that trigger recalculations would go here
end


Finally I can show the report on the homepage with some boring (and fast) Rails code

Model:

class Report < ActiveRecord::Base
end


Controller:

class ReportsController < ApplicationController
@report =" ReportRows.find_by_user(current_user)">


and the View:


<% for row in @report %>
Display the row
<% end %>


The interesting insight for me is that when optimizing there are sometimes hard problems that can't be solved. Its important not to lose sight of the goal you're aiming at (a satisfying user experience) and that sometimes involves spending the computational time somewhere where the user won't mind.