Tuesday, September 30, 2008

initialize + super

Here's a word of caution to those using inheritance and calling super in the initialize method. Consider this:

def initialize(name, price)
super
@name = name
@price = price
end

Which parent method does it call? I was surprised to find out that without () after super, it automatically calls the initialize in the parent that has the parameters (name, price), rather than the one without parameters. If your intention was to call the parent's initialize without parameters, than you must do:

super()


W

Monday, September 29, 2008

TinyMCE: enforce maxlength

TinyMce doesn't have support for maxlength, and putting maxlength in the textfield tag won't do anything either.

If you try to google for a solution, you might come across this site

Don't waste your time on it, because the solution is built with the old tinymce api, it wouldn't work. Instead, use the solution from this post.


J

RoR: attr_accessible with attachment_fu

If you try to use attr_accessible on any model with attachment_fu plugin,
you'll get an error.

This article explains why


J

Sunday, September 28, 2008

RoR: attr_accessible

In a previous post, I talked about mass assignment. Well, there's something I discovered recently. If you have a polymorphic relationship, your model will have two columns: taggable_type and taggable_id. If you want to make these available for mass assignment, you cannot do:

attr_accessible taggable_type, taggable_id

Instead, RoR treats them like one attribute like so:

attr_accessible taggable


W

Saturday, September 27, 2008

RoR Generate + SVN

We all know about RoR's ability to generate controllers, models, migrations, etc. However, if you're using a repository, you have to manually add these newly created files. This could be a pain in the ass!

Here's a tip. If you're using SVN, you'll love this. Simply add the flag --svn and the generator will automatically add the newly created files to SVN. Simple!


W

Thursday, September 25, 2008

RoR: Mass Assignment Security

In RoR, it is possible to do something called mass assignments. For instance, when submitting a form, all the parameters are put into a params hash so you can do the following:

Product.create(params[:product])
product.update_attributes(params[:product])

Very simple, but by default, there is a security flaw. That flaw is covered in this post. If you are concerned about this, the easiest way would be to make it so that all your models will require attr_accessible on any attributes that you want mass assignment for. This then protects any attributes not listed by default.

In your config files, preferably in your initializers folder, add the following to protect all attributes:

ActiveRecord::Base.send(:attr_accessible, nil)

Then go through each model and think about which attributes should be exposed to mass assignments. For those that are not accessible, you must do the following to assign values:

product.store_id = store.id

This makes the assignment explicit and cannot be manipulated by the users.

Now that you know, go secure your applications!


W

Tuesday, September 23, 2008

Stack and Queue Implementation

Array in Ruby already has built in push and pop function you can use, but if you want to make it more strict and idiot proof, here's how you can implement it.

class Stack

def initialize
@stack = []
end

def push(x)
@stack.push(x)
end

def pop
@stack.pop unless is_empty?
end

def peek
@stack.last
end

def is_empty?
@stack.empty?
end

end

class Queue

def initialize
@queue = []
end

def enqueue(x)
@queue << x
end

def dequeue(x)
@queue.shift
end

def peek
@queue.first
end

def is_empty?
@queue.empty?
end

end


J

Fun with String

This is why Ruby is amazing :D

1. converting strings to numbers

"123".to_i => 123
Duh, everyone knows that

but how bout
"123stfu".to_i => 123

or

" 123stfu ".to_i => 123

you can even indicate the base of your conversion

"111".to_i(2) => 7 # treat it as a binary number
"111".to_i(8) => 73 # treat it as an octal

split a string and convert it to an interger

"123 456 789".split.map {|m| m.to_i} => [123, 456, 789]

2. Replacing text

we can implement the lame rot13 encryption scheme in one line :)

class String; def rot13; self.tr("A-Ma-mN-Zn-z", "N-Zn-zA-Ma-m");end;end

"Please hide this line".rot13 => "Cyrnfr uvqr guvf yvar"

3. Counting Characters

s1 = "abcabcabcde"
s1.count("c") => 3
s1.count("abc") => 9
s1.count(s1) => 11

count can handle negation

s1.count("^abc") => 2
s1.count("^a") => 8

and range of chars

s1.count("a-c") => 9
s1.count("^a-z") => 0

4. Reversing a String

Microsoft loves to ask interviewee to reverse the word order of a String during an interview, it takes around 15 - 20 lines to implement the function in Java or C++, but we can do it in one :)

phrase = "This is a joke"
phrase.split.reverse.join(" ") => "joke a is This"

so next time you goto an interview, asks if they'll let you do it in Ruby ;)

5. Removing Duplicate Characters

string = "aaaaaaaaaaaaaaaaaaa".squeeze => "a"
string = "aaaaaaaaaaaaaaaaaaB".squeeze => "aB"
string = "hehe....".squeeze(".") => "hehe."


J

List of reflective methods

I find the following commands very useful from time to time, but I kept forgetting their names. So I'm creating this post to help remind myself.

a.class
# returns the class of an object a

a.superclass
# returns the superclass of an object a

a.instance_of? A
# determines if a.class == A

a.is_a? A
#determines whether a is an instance of c, or of any of its subclass, or of any modules.

a.respond_to? :something
#determines if a has a public or protected method with the specified name.


J

Shuffling an Array

I just found a very interesting article about shuffling an array correctly!

http://adrianquark.blogspot.com/2008/09/how-to-shuffle-array-correctly.html

Enjoy!


W

Monday, September 22, 2008

Duck Typing and Type Checking

Consider the following example:

class A
attr_accessor :x

def initialize
@x = 0
end

def +(other)
a = A.new
a.x = @x + other.x
return a
end
end

class B
attr_accessor :x

def initialize
@x = 0
end
end

a = A.new
a.x = 10
b = B.new
b.x = 5
puts (a+b).x # this will return 15

Ruby is a very dynamic language, the addition function doesn't care if the argument passed in is of type A, as long as it looks and behaves like A. This is called duck typing, name after the phase "if it walks like a duck and quacks like a duck, it must be a duck!"

if you want to ensure the object passed into the + function has to have an x accessor, you can add this to def +(other)

raise "error" unless other.respond_to? :x

or if you want to ensure object passed into the + function has to be of class A, you can add this instead:

raise "error" unless other.is_a? A


J

Instance Variable

Java and C++ programmers are used to declaring their variables in a class, and they think they should do the same in Ruby. WRONG!

For example:

class Animal
@age = 0
@name = ""

def initialize(age, name)
@age = age
@name = name
end
end

In this example, two sets of @age, @name are created. When the initialize method is called, self holds an instance of the Animal class. But the code outside of that function are executed as part of the definition of the Animal class. When @age and @name are executed, it refers to the Animal class, not the object instance. Hence @age, @name inside the initialize function are different from the @age, @name on the outside.


J

Sunday, September 21, 2008

Variable Parameters

Sometimes we want a method that can take any number of parameters.
One way to do it is to pass in a hash, but this can be annoying. Another method is to put an * before the method's parameter. Within the body of the method, list will be treated as an array with 0 or more elements.

For example:

def average(*list)
x = 0
list.each {|l| x+= l}
l/list.size
end

irb>average 1,2,3,4,5,6,7,8,9
=> 5

J

Copying Objects

When you use =, clone, or dup to copy an object, only the object reference is copied,
not the referenced object itself (Shallow Copy).

In order to do a deep object copy, we can use the marshaling trick by dumping and
loading the object.

For example:

def deepcopy(something)
Marshal.load(Marshal.dump(something))
end

irb>b = "abcd"
=> "abcd"
irb>a = b
=> "abcd"
irb>a.upcase!
=>"ABCD"
irb>b
=>"ABCD" # see how b changes too
irb>b = deepcopy(a)
=>"ABCD"
irb>b.downcase!
=>"abcd"
irb>a
=>"ABCD" # a stayed the same this time

J

Saturday, September 20, 2008

More on enumerable

In ruby, I use .each alot to visit every elements in the array.
Did you know there's a .step(x) function that allows you to visit
every x th element in the array?

For example:

r = 0..3
r.each {|l| prints l.to_s + ' ' } # Prints 0 1 2 3

r.step(2) {|l| prints l.to_s + ' '} # Prints 0 2


J

Thousands Seperator

In ruby, underscore can be inserted into integer literals as thousands separator.

For example:

1_000 will be interpreted as 1000
1_000 + 1_000 will equal 2000
1_000_000_000 will be interpreted as 1 billion

the same technique works for float number as well

For example:

1_000.1 will be interpreted as 1000.1


J

Friday, September 19, 2008

Prototype: $A is not defined

Ever get this annoying error? Well... I do. Odd thing is, everything still works like a charm. So what's happening.

Unfortunately, no one seems to really know! I did some digging and found this bug. If you go through the comments, Prototype has some problems when loading/unloading a page on Firefox 2. Or maybe it's Firebug. People can't seem to entirely agree, and the bug has been reopened several times.

However, if you want a patch and forget about finding out what the problem really is, check out this fix.

I've used it and forgot about it now. Would be nice to know why though...


W

Thursday, September 18, 2008

Dropbox

Recently, there has been a lot of buzz around Dropbox. It is now open to beta testing, and many people say it's awesome.

In short, Dropbox can be thought of as storage that you can access from anywhere you have an internet connection. It'll automatically sync your local and remote files, and also work on PCs, Macs, and *nix machines.

For those of you that move around a lot and need your files reliably without the hassle, check out Dropbox.


W

Wednesday, September 17, 2008

Database Visualization

Keeping documentation up-to-date is always a pain in the ass. I was recently working on updating our database diagrams and thought that there may be a way to automate the process.

I found 2 solutions:

1. XMI
2. RailRoad

For solution (1), it worked, but I had to tweak it slightly. Because we are using PostgreSQL, I had a problem when UmlDumper tried to execute current_database for the adapter. This works fine for the MySQL adapter, but no such function exists for the PostgreSQL adapter. I quickly hacked it and just replaced it with a general name for our database, as we didn't have to be dead-on here.

I was quite disappointed when Dia did not know how to open up the XMI file. So, searching around, I found a program called Umbrello. It works great. Unfortunately, I had all my UML classes, but no diagram! I had to drag and drop each one individually (I couldn't figure out how to drag them all at the same time T.T). I then manually added in all the lines and made it pretty. Not too bad, but it was partly automated and partly manual.

For solution (2), it worked great. I used a rake task to generate the svg files. I had several issues with this, which was the fact that RailRoad is used to diagram models in RoR, not the database. Hence, I ended up with a lot of relations that didn't exist in the database. This meant TONS of lines. The lines are also quite hard to follow as they constantly overlap and cross each other.

2 major issues I had was that there is a 1-to-1 relationship (for efficiency purposes). However, the diagram did not reflect this. For example, we have class A and B that are in a 1-to-1 relationship. A will have has_many relationships and so will B. However, the diagram showed that all of B's has_many relationships were related to A, not B. I couldn't figure out why.

The other issue was a logged bug. If the model ends in an 's', the diagram gets messed up. The diagram will automatically drop the trailing 's'. This created incorrect relationships.

For these 2 major issues, I was unable to use solution (2) in the end. However, if more improvements are made, I may give it another chance as the whole process was completely automated. If your interested, it also does Controller diagrams.

If anyone else has a better way of producing automated diagrams of their database or models, give me a shout. I'd love to hear other solutions.


W

Monday, September 15, 2008

Google: AdWords Algorithm

Sorry, this isn't a post about Google's algorithm :P

But, there is news that they're planning to modify it! That's big news to people using AdWords. Go and check it out.

Quick summary:

- dynamic calculations of Quality Score at search time
- keywords are no longer labeled as "inactive for search"
- no more "minimum bids"... in comes "first page bid estimates"

In other words, Google wants more money ;)


W

Sunday, September 14, 2008

Saturday, September 13, 2008

Y Combinator

Y Combinator is a venture firm that specializes in funding startups in their early stages. I recently discovered their news section, which, as a technical person, I find very interesting. It is a Digg type site that gives links to interesting articles. Every so often, I will also see RoR articles on there. Check it out:

http://news.ycombinator.com/


W

Friday, September 12, 2008

Ubuntu: Volume Problems

Recently, my audio has been much softer than it has been when I first installed Ubuntu. Even if I turn my volume up completely, the audio was only at a normal volume. I found this odd because before, when I turned it up, it would blast my ears off.

I managed to find out why! If you go to your Volume Control, Edit > Preferences, and select PCM. Then turn the PCM volume up to the desired level. Mine, for some reason, was set at a very low volume.

I'm not quite sure what happened, as I never played with my settings. My only guess is that some particular update fooled with the settings.


W

Tuesday, September 9, 2008

BackgrounDrb.destroy

So we've been noticing some pretty odd things with BackgrounDrb lately. In spite of our previous fixes to BackgrounDrb, we've decided to give up on it. Why? Simply put: It's not working properly.

We've been checking the logs recently, and we've noticed way too many calls to our scheduled tasks. On the odd days, we'll get 3 or 4 extra calls when only 1 was scheduled. I don't know how to explain this, nor do I wish to find out, because frankly, I'm fed up with this.

I admit, it really was my fault for trying to use an overly complicated program to run something very simple. KISS - I know. I'm kicking myself in the ass for this now! Anyways, simple solution: cron. It's the most basic of basic schedulers. You can't go wrong here.

Luckily, all our functions were encapsulated in the models, so the logic didn't need to be changed. We ripped out the stuff in the BackgrounDrb worker and placed them in a rake file. We then called the rake tasks from the cron.

Very simple. Very clean.

Bye Bye BackgrounDrb!


W

Tuesday, September 2, 2008

Sitemap

It's nice to have a sitemap that adheres to the Sitemap 0.90 protocol. In rails, this can be automatically generated. Unfortunately, you have to do some work.

I found 2 different ways:

1. using controllers
2. using rake

If your site is small, (1) works really well. It's as dynamic as it can be as the sitemap is generated on the fly. However, every time anyone visits that URL, you end up hitting the database for a fairly large call, memory-wise. If it's just legitimate people accessing it, they will access the URL when they need it, or on a periodic time frame. However, if you encounter malicious users (which there are many out there), they could easily overload your server.

(2) is not as up-to-date, but from my point of view, that's ok, especially if you update the files daily. The solution posted works well, but since out site takes advantage of BackgrounDrb, I thought I would modify it to work with BackgrounDrb instead of rake.

I created some self functions to do the database queries and handle the tasks in the rake. Also, in sitemap.rb, I added the lines:

include ActionController::UrlWriter
default_url_options[:host] = 'www.twoblindfish.com'

This allows you to use named routes and url_for. Now we don't need to hardcode our URLs! Another plus! The rest is pretty straight forward. A few of the tasks were redundant, so I refactored them into multiple functions for reuse.

The only thing really different would be to place your sitemaps in public/system/. so that the sitemaps don't get removed when you do a cap:deploy. This works because the public/system folder is symlinked to shared/system.

Hope this helps those in need of generating sitemaps!


W