Nested forms with polymorphic association in Active Admin/Formtastic

I spent nearly the whole day making this work.

Given models:
Invoice, has_many :items
Item belongs_to :itemizable, polymorphic: true
Domain & Service has_many :items, as: :itemizable

The problem was multiple things:

  1. The automagic of Formtastic can’t detect the collection if it’s a polymorphic association
  2. Formtastic doesn’t really play well with non-existent attributes

Initially, I’ve thought of just doing:

ActiveAdmin.register Invoice do
  form do |f|    
    # ...
    f.has_many :items do |item|
      item.input :itemizable, collection: (Domain.all + Service.all)
      item.input :quantity
      item.input :price_per_piece
    end

    f.actions
  end
end

But this fails because 1) domains and service can share the same id and 2) I have no way to tell what the item was.
A few hours in and I was going nowhere. It’s surprisingly hard to look for anything related to polymorphic associations on Formtastic. This post gave me an idea however.

So, I’ve thought, why not just hold the id temporarily on an accessor attribute and just do the assignment from a callback before validation kicks in based on which attribute it went into? Raise an error if both were filled up.

It worked! I can now save new polymorphic records. (look at Item#assign_itemizable)

There’s a small problem however. The form to edit an existing record doesn’t pre-populate the corresponding select dropdowns. The solutions was rather simple, override the reader method to return the id of the itemizable if the itemizable is a member of the class.

Maintenance-wise, everything here would add overhead for every new itemizable model I would associate to item, but overall, I think it was a pretty elegant hack. *pats self at back*

Here’s the complete code:

# app/models/invoice.rb
class Invoice < ActiveRecord::Base 
  has_many :items

  accepts_nested_attributes_for :items
end

# app/models/item.rb
class Item < ActiveRecord::Base
  before_validation :assign_itemizable

  belongs_to :invoice
  belongs_to :itemizable, polymorphic: true
  
  validates :itemizable, presence: true

  attr_accessor :itemizable_domain, :itemizable_service

  def itemizable_domain
    self.itemizable.id if self.itemizable.is_a? Domain
  end

  def itemizable_service
    self.itemizable.id if self.itemizable.is_a? Service
  end

  protected
  def assign_itemizable
    if [email protected]_domain.blank? && [email protected]_service.blank?
      errors.add(:itemizable, "can't have both a domain and a service") 
    end

    unless @itemizable_domain.blank?
      self.itemizable = Domain.find(@itemizable_domain)
    end

    unless @itemizable_service.blank?
      self.itemizable = Service.find(@itemizable_service)
    end
  end
end

# app/admin/invoice.rb
ActiveAdmin.register Invoice do
  form do |f|
    f.inputs "Invoice" do 
      f.input :customer
      f.input :invoice_number
      f.input :issuing_person
      f.input :issued_on
      f.input :remarks
    end
    
    f.has_many :items do |item|
      item.input :itemizable_domain, collection: Domain.all
      item.input :itemizable_service, collection: Service.all
      item.input :quantity
      item.input :price_per_piece
    end

    f.actions
  end
end

Edit: Fixed a bug in Item because I overwrote the accessors, which were being called in the validation. This caused a sort of chicken-egg situation, and ultimately causes the validation to fail all the time. Changed .empty? to .blank? so it doesn't barf out on nils.

The key to happiness: a good bed, nice chair and healthy food

If you want to spend on yourself, here’s what I suggest you spend on: A good bed, nice chair and healthy food.

(Ha! I bet you didn’t see that coming!)

This image would explain everything.

Yes, that's the same image as the featured image.
Mmm. Pie.

My list of “things to spend on to invest in myself” is much longer. Those were the top 3.

Breakdown

I amortize costs over the lifetime of the product. I often say, if I spend X amount on this and it lasts me Y (months/years), then I’m just paying Z per (minute/day). Sometimes, I say, if I spend X amount on this and I use this Y number of times, then I’m just paying Z per use when applicable. This way I can compute costs on a daily/monthly/basis.

I’m a believer of YAGNI so I don’t really buy the latest and the greatest (read: most expensive) unless I need them. I fall right in the middle/upper-middle most times. Just enough for my needs, and some bells and whistles.

My longer list with approximate cost ranges is as follows: (All figures in Philippine Pesos)

  1. Good bed, read: mattress (3k to 9k over 3 years or 2.75 to 8.25 per day)
  2. Nice chair (2k to 6k over 2 years or 2.75 to 8.25 per day)
  3. Healthy food (200 to 300 per day)
  4. Flattering clothes (15k to 20k over 1 year or 41.00 to 55.00 per day)
  5. Fluffy pillows (500 to 1k over 1 year or 1.50 to 3.00 per day)
  6. Decent Keyboard & Mouse (1k to 2k over 1 year or 3.00 to 6.00 per day)
  7. Good enough desktop/laptop (20k to 50k over 3 years or 18.50 to 45.75 per day)

I’ve prioritized the list using these reasons:

  1. Bed: The effects of quality sleep affects your every waking hour.
  2. Chair: Good posture is a sort of “prevention is better than cure” thing. More short term, it helps alleviate building up of stress which would affect your quality of work. This also contributes to quality of sleep.
  3. Food: It keeps you alive. Why not spend on it?
  4. Clothes: Find the kind of person that you want to be, and dress like him/her. Imitation is the highest form of flattery or Dress for the kind of job you want, not for the job that you have. The clothes make the man. Or it doesn’t. This deserves its own post.
  5. Pillows: Goes with the bed.
  6. KB&M: My hands are my bread & butter. RSI and CTS can be literal career-ending injuries.
  7. Workstation: I spend at least 8 hours on this thing. I would want to have enough for what I need.

That comes out to 269.5 to 426.25 per day or 8,085.00 to 12,787.5 per month. [1] Factor in bills, rent and other consumables and you’re looking at close to 15,000 to 20,000 per month to live a comfortable life. [2]

I’m at this point in my life wherein I’m content, materially, with everything I have so far. The only significant purchases I have left are a laptop replacement, a vehicle and a house. The last 2 are just luxuries with my current lifestyle and wouldn’t probably buy them for myself anytime soon (i.e. in the next 3 years).

Optimizing for happiness

Happiness is having everything that you need in the world. The first step to being happy is finding out the minimum that you need. It’s entirely subjective.

The next step to happiness is optimizing the these things that contribute to your daily well being. If you feel well enough on a daily basis, then I think you’re 80% there to general happiness. [3] The rest is tougher to crack: healthy relationships, sense of purpose, et al. But it sure becomes easier once you’ve got a solid base.For the low low price of Php 20,000 a month, I can pursue the rest of my 20%.

Am I happy? Currently, yes. But it’s a process.


[1] I actually have another round of computation, wherein the costs are weighted based on how much I use the thing. I’m being lazy so I didn’t include it.

[2] This is for a single, no dependents person. For a family that is sharing a lot of the things above including rent and utilities, this would be significantly less per person. But of course, you’d have to multiply per head so it comes out larger in lump sum.

A totally pulled-out-of-my-ass formula is : x = number of people, amount = x * 20,000 * (0.9 ^ x). This yields:

1 20,000.00
2 32,400.00
3 43,740.00
4 52,488.00
5 59,049.00
6 63,772.92
7 66,961.57

[3 ]Pareto principle, the 80-20 rule. Generally speaking, 80% of output, comes from 20% of input.

Motivation and Decision-making

I like reading about psychology. Especially psychology related to motivation and decision-making.

Here are some links that I find myself visiting time and again. Some of them, I can relate with (to some degree) while others are references I come back to time and again.

Featured image care of Marco Bellucci

Obligatory Birthday Post — 24 of ???

It was more of a birthday weekend, more than anything.

I did not have any plans whatsoever. All I knew was that I was pretty tired because of the week that just ended.

I’d like to thank everyone who were there during my “surprise” birthday party.

My labs, Angel — thanks for the birthday gifts and for all the love. <3
Our head honcho, Ma’m Deng and Julianne — double thanks for arranging everything!
Joanna and family
Madumlao and Alex — thanks Mark for the cake!
Jerix, Gerry, JP and Liz
Karl, Allan, Jeffrey, Rexell and Tandz
Kenan and Matt

I spent the whole of Aug 18 with my family and my dogs. We went out and watched Percy Jackson.

It’s raining pretty hard outside though.

I’ve got a lot more in my mind, but I’m sleepy.

The Un-fun game of eRepublik

I play Erepublik and have been playing consistently for quite some time now.

Okay, playing is probably an overstatement. It’s more accurately described as I’ve-been-logging-in-and-clicking-around-10-times-before-logging-out. It’s an exercise in patience.

After doing the usual routine (which takes me probably a minute), I always stop and think what exactly this game is missing. It’s got a very engaged community, decent UI and I would presume sustainable enough sales.

It’s not fun.

Trading effort for progress

There’s only trade a lot of money for a little bit of progress.There’s no mechanism for me to put in effort to gain a little bit more of progress ahead of everyone else that does the bare minimum (login, work + train).  This kind of reminds me of Neopets at the other extreme, where there’s just so many things to do that you can easily sink a whole day in it and not be done with everything you can do daily.

Some of my ideas here are:

  • Side stories / side quests
  • Make training much more interactive
  • Make working much more interactive

Predictability

One other thing that makes it not-fun is that everything is predictable. There’s absolutely no chance involved. The larger a country is, the more population it has, the more resources it produces, the more territory it can conquer. This is a 100% sure thing.

On the other hand, small countries’ (like ePH) resistance wars is an exercise in futility.

What a huge thing a +- (1-10)% random bonus per war could give both sides. It would make war strategy much more exciting other than “I need to have more people/energy bars than the other side have.”

Some of my ideas here:

  • War module: random bonus/penalty (based on RL weather?)
  • Economy module: production bonuses/penalty (based on RL stock market?)

Simplicity

Erep’s simplicity undermines its potential.

The economy sucks because it’s too simple. There’s not enough room for players to turn a profit. The only ways to turn a profit is either build Q6-Q7 weapons factory and hire other people or buy from major markets and sell in smaller markets.

The war module kind of sucks because it’s too simple. There’s not much strategy further than “we need to find more high str players with lots of bars/weapons than the other side”.

Daily activities suck because it’s too simple. I just need to go work for the highest bidder and work everyday (read: click the work button). I just need to level up my training grounds and train everyday (read: click the train button).

The political system sucks because it’s too simple. Everything is entirely subjective and lawmakers are not given insight to country data to effectively address macro-level issues. Analytics over time would be a huge boon to proper lawmaking.

“Make it as simple as possible, but not any simpler.”


Erepublik is kind of enviable in a way that despite the game’s deficiencies, people still stick to it. It’s community finds fun within its own meta-game. For a game developer however, I think that’s a pretty pathetic state to be in.

Hopefully, there’s no other way to go but up. Unless Plato suddenly gets one of his bright ideas.

Opportunity Cost

One of my favorite micro-economic concepts is opportunity cost.

Simply put, if I have a limited resource, the total cost of spending that resource on something is the face value plus all the foregone opportunities by spending that resource on something else.

It’s highly personal because it has been one of my driving factors on why I still am not back in school.

I still had 2 more years to go before I graduate (assuming I didn’t fail a subject). When I had thoughts to go back, I kept on thinking, “What can I do in those 2 years?” and so many things come up.

I could learn mobile.
I could be better at getting customers.
I could be better at keeping customers.
I could learn more design patterns.
I could study how to keep engineering talent.
I could do this and that.

I could learn more by spending my time somewhere else. The underlying truth is, I didn’t want to be a computer scientist as badly as I wanted to be other things. If I wanted to learn specifically about computer science, sitting through lectures is probably the most efficient use of my time. But it’s not what I want to be.

10,000 hours of deliberate practice is what it takes to master anything.The best time to plant a tree was 10 years ago. The next best is now. You become good at things where you spend your time [1]

Are you spending your time on things you want to master?

[1] There’s an argument to be made here between talent and hardwork, but that’s a topic for another day.

I have a nagging feeling that I’ve written about this before already.

Featured image by G.X. He’s 12 years old now.