When developing an application with an audience larger than your local neighbourhood in mind, you have to start thinking where your users are. One major point that comes into play is time. The world works on different time zones, and you must realize and honour that. When your application is based on time, time zones become important.
However, time zones are one of those things you just never want to touch. Why? Because usually it's a bloody mess! There are several factors to consider, like the time on your server and database (are they in local time or UTC?), local times for users using time zones, and daylight savings times. All this bundles together to make one messy problem.
RoR's built-in Date/DateTime/Time/TimeZone classes are poorly equipped to handle... well... anything to do with local times. However, because RoR is so extendable, there are always gems and plugins! In order to get everything working nicely, the problem of time zones requires 1 gem and 3 plugins! Wow! That's a lot, but trust me, it makes things much cleaner!
Firstly, there's the TZInfo gem. This little gem provides daylight savings aware transformations of time. This is useful because not everybody observes daylight savings.
Secondly, there's the TZInfo Timezone plugin. This little baby is where most of the magic occurs. This essentially replaces RoR's built-in TimeZone class. It does wonders.
Thirdly, there's the TzTime plugin. This is another little baby that does wonders. It basically replaces RoR's built-in Time class, and works in unison with TZInfo Timezone.
In short, all you do is set TzTime.zone to the current user's time zone, and then you can use things like TzTime.now, which will return you the current local time of the user. Clean and simple!
For an illustration of this, go to:
http://www.caboo.se/articles/2007/2/23/adding-timezone-to-your-rails-app
There was one modification which I needed to make in order for the example to work. Instead of TZInfo::Timezone, I needed to write TzinfoTimezone.
Good luck with time zones, and hopefully, this will keep your application a little bit cleaner (and minus the hair pulling!)
W
Saturday, January 19, 2008
Sunday, January 13, 2008
ActiveForm
Suppose you're doing a search form. This search form can be using fields from many different ActiveRecord models and probably doesn't correspond to any table in your database.
What's nice about being an ActiveRecord model is that in the view, you can do wonderful things like a form_for helper or error_messages_for helper. Furthermore, ActiveRecord provides you a collection of wonderful validation functions.
However, without ActiveRecord, your solution would be to do it all by hand. How very sad T.T
This is where ActiveForm is a time saver! Basically, you create an ActiveForm model exactly the way you would an ActiveRecord model. It even supports validation! Furthermore, it is supported in the view, so all those helpers will still work! Just wonderful!
You can grab it as a plugin from here:
http://www.realityforge.org/svn/code/active-form/trunk
Enjoy!
W
What's nice about being an ActiveRecord model is that in the view, you can do wonderful things like a form_for helper or error_messages_for helper. Furthermore, ActiveRecord provides you a collection of wonderful validation functions.
However, without ActiveRecord, your solution would be to do it all by hand. How very sad T.T
This is where ActiveForm is a time saver! Basically, you create an ActiveForm model exactly the way you would an ActiveRecord model. It even supports validation! Furthermore, it is supported in the view, so all those helpers will still work! Just wonderful!
You can grab it as a plugin from here:
http://www.realityforge.org/svn/code/active-form/trunk
Enjoy!
W
Labels:
ActiveRecord,
Plugins,
Solutions,
Views,
W
Saturday, January 12, 2008
assert*
For testing, we have a collection of assertion functions that come with RoR. They're fundamental to any testing infrastructure. Without them, I can't imagine how testing could be done.
However, on the site that hosts the API, I cannot find the functions available. They list the functions for ActionController, but not for general testing.
Hence, I did a simple search and came up with this lovely site. Enjoy!
assert* functions
W
However, on the site that hosts the API, I cannot find the functions available. They list the functions for ActionController, but not for general testing.
Hence, I did a simple search and came up with this lovely site. Enjoy!
assert* functions
W
Auto Insertion Templates
I recently found a wonderful little tool in Aptana RadRails. The IDE provides a way for auto inserts using templates! This means you can type shortcut keywords, hit ctrl + space, and the corresponding templates will show up for you to choose from.
Window > Preferences > Ruby > Editor > Templates
is where you will find all the defined templates. This comes in handy when you want to customize the already installed set of templates, or feel like creating your own. It is very easy to create your own templates by looking at some of the examples already in the list.
This should allow you to develop your application much more quickly. Happy coding!
W
Window > Preferences > Ruby > Editor > Templates
is where you will find all the defined templates. This comes in handy when you want to customize the already installed set of templates, or feel like creating your own. It is very easy to create your own templates by looking at some of the examples already in the list.
This should allow you to develop your application much more quickly. Happy coding!
W
Friday, January 11, 2008
Locking
Usually in an application with more than 1 user, there are several resources that will be shared. And whenever there are shared resources, there are usually race conditions. Most web applications are not exceptions. Shared resources are a very old set of problems that have been solved many times in many different areas, not only for computers.
Luckily, in RoR, it provides a way to handle shared resources: locking. Locking comes in 2 flavours: optimistic and pessimistic.
Usually, optimistic locking would be used for critical sections where race conditions are not expected to happen very often (due to the abortion of the transaction if a conflict occurs), whereas pessimistic locking would be used for critical sections where race conditions are frequent.
There is, however, a huge advantage that optimistic locking has over pessimistic locking, and that is scalability. The fact that pessimistic locking for update locks the row so that no read/update/destroy can be performed on that row until it is released means that users may have to wait indefinitely. Especially when race conditions are frequent, a long queue could develop with arbitrarily long waits.
Unfortunately, with optimistic locking, there is the problem of abortion and requiring the user to redo what they just did. This is obviously not very user-friendly, as the user expects their changes to be made the first time. If the UI is thought out carefully though, the impact of this may be minimal.
RoR, being superly fantastic, supports both! And both are very simple to implement.
With optimistic locking, all you have to do is add a column to your table you want to optimistically lock. Using migrations, it would look like this:
t.column :lock_version, :integer, :null => false, :default => 0
It is important that the column name is lock_version, and the default value is 0. Now, whenever an update occurs, the lock_version is compared to the one in the database. If there are any differences, then a StaleObjectError is raised and must be handled in any fashion in which you deem appropriate. More information about RoR's optimistic locking can be found here.
With pessimistic locking, all you do is lock it down when you do a find:
Person.find(:all, :lock => true)
This will pessimistically lock any rows returned. If you already have an object, you can use the method object#lock!:
person = Person.find(1)
person.lock!
More information about RoR's pessimistic locking can be found here.
Well, hopefully that was interesting to you. One more tip about locking is to watch out for deadlocks! Good luck!
W
Luckily, in RoR, it provides a way to handle shared resources: locking. Locking comes in 2 flavours: optimistic and pessimistic.
Usually, optimistic locking would be used for critical sections where race conditions are not expected to happen very often (due to the abortion of the transaction if a conflict occurs), whereas pessimistic locking would be used for critical sections where race conditions are frequent.
There is, however, a huge advantage that optimistic locking has over pessimistic locking, and that is scalability. The fact that pessimistic locking for update locks the row so that no read/update/destroy can be performed on that row until it is released means that users may have to wait indefinitely. Especially when race conditions are frequent, a long queue could develop with arbitrarily long waits.
Unfortunately, with optimistic locking, there is the problem of abortion and requiring the user to redo what they just did. This is obviously not very user-friendly, as the user expects their changes to be made the first time. If the UI is thought out carefully though, the impact of this may be minimal.
RoR, being superly fantastic, supports both! And both are very simple to implement.
With optimistic locking, all you have to do is add a column to your table you want to optimistically lock. Using migrations, it would look like this:
t.column :lock_version, :integer, :null => false, :default => 0
It is important that the column name is lock_version, and the default value is 0. Now, whenever an update occurs, the lock_version is compared to the one in the database. If there are any differences, then a StaleObjectError is raised and must be handled in any fashion in which you deem appropriate. More information about RoR's optimistic locking can be found here.
With pessimistic locking, all you do is lock it down when you do a find:
Person.find(:all, :lock => true)
This will pessimistically lock any rows returned. If you already have an object, you can use the method object#lock!:
person = Person.find(1)
person.lock!
More information about RoR's pessimistic locking can be found here.
Well, hopefully that was interesting to you. One more tip about locking is to watch out for deadlocks! Good luck!
W
Thursday, January 10, 2008
Eager Loading
There are many instances where you need to find an object, or several objects, then require their associated objects afterwards. In the simple case, this would require (1 + n) SQL queries: one for the object(s) and n for the associated object(s) for each object. To solve this problem, RoR allows you to do eager loading of associations when performing a find. This means that the (1 + n) SQL queries can be squashed into 1 and RoR handles the placing of the data correctly. Examples of eager loading can be found here (under Eager loading of associations).
I thought I would take this one step further. Using the example of Post, I thought I would have something like:
class Post
has_many :comments, :include => :author, :order => "comments.date ASC, authors.name ASC"
end
This would eager load the authors of each comment in the post, ordered by the date created and then by alphabetical order of name.
This works great when doing:
@comments = post.comments
and later on using @comments in the view to display.
However, I started to have major problems when I attempted a find on the collection such as:
comment = post.comments.find_by_author_id(author.id)
When executing such a command, I got a database error. The error reported that the authors table was not included in the FROM clause of the SQL query (due to the order by author.name ASC). I checked the query in the output console, and sure enough, there was no join to the authors table. I tried looking around for explanations, but ended up with none.
I finally gave up and removed the :include and :order from the has_many relationship and ended up doing this instead when I required eager loading and ordering:
@comments = post.comments.find(:all, :include => :author, :order => "comments.date ASC, authors.name ASC")
Hopefully, if anyone knows the explanation as to why the previous did not work, I would love to hear it. Otherwise, I hope this solution works for you.
W
I thought I would take this one step further. Using the example of Post, I thought I would have something like:
class Post
has_many :comments, :include => :author, :order => "comments.date ASC, authors.name ASC"
end
This would eager load the authors of each comment in the post, ordered by the date created and then by alphabetical order of name.
This works great when doing:
@comments = post.comments
and later on using @comments in the view to display.
However, I started to have major problems when I attempted a find on the collection such as:
comment = post.comments.find_by_author_id(author.id)
When executing such a command, I got a database error. The error reported that the authors table was not included in the FROM clause of the SQL query (due to the order by author.name ASC). I checked the query in the output console, and sure enough, there was no join to the authors table. I tried looking around for explanations, but ended up with none.
I finally gave up and removed the :include and :order from the has_many relationship and ended up doing this instead when I required eager loading and ordering:
@comments = post.comments.find(:all, :include => :author, :order => "comments.date ASC, authors.name ASC")
Hopefully, if anyone knows the explanation as to why the previous did not work, I would love to hear it. Otherwise, I hope this solution works for you.
W
Wednesday, January 2, 2008
Radio Buttons
RoR is lovely when it comes to supplying frontend helpers. For example, if you want to create a form for a particular object, it's very simple:
<% form_for :user, :url => new_user_path do |f| %>
...
<% end %>
Inside "...", you can add all your fields, such as:
However, our topic for today is actually radio buttons. Many times, we want to use radio buttons to select some sort of true/false field. It is possible to do this with checkboxes, andRoR is wonderful with this. However, sometimes, 2 radio buttons are better. This is where I ran into some problems. Reading the API, I came up with 2 radio buttons as follows:
<%= f.radio_button :is_good, true %>
<%= f.radio_button :is_good, false %>
I thought that this would generate two radio buttons with values true/false respectively. However, it didn't! The first generated one that had a value of "true" and was checked. But the second generated a radio button with no value! I then changed the given values from booleans to strings:
<%= f.radio_button :is_good, 'true' %>
<%= f.radio_button :is_good, 'false' %>
Everything worked fine now, but given a model that held data, neither radio buttons were checked! This is due to the fact that the model holds boolean values, whereas the radio buttons use string literals. Saving was fine because we were using prepared statements, which automatically convert the string literals to boolean. I was completely stumped on the displaying of data though. I came up with a quick hack using virtual attributes, but it's ugly:
def is_good_temp=(is_good_temp)
@is_good_temp = is_good_temp
if @is_good_temp == 'true'
self.is_good = true
else
self.is_good = false
end
end
def is_good_temp
@is_good_temp.nil? ? 'true' : @is_good_temp
end
def is_good
@is_good.nil? ? true : @is_good
end
def is_good=(is_good)
@is_good = is_good
end
and changed the radio buttons to:
<%= f.radio_button :is_good_temp, 'true' %>
<%= f.radio_button :is_good_temp, 'false' %>
So basically what I did was create a virtual attribute to deal with the radio buttons using string literals, and have that convert the string literals to booleans and assign it to the actual variable. To be noted is that there is no nice function object#to_b to convert a string literal to boolean. There are nice functions like object#to_s and object#to_i, but not to boolean.
This is one disappointment from RoR. I have searched around and could find no solution to this. Perhaps I am doing this wrong, but for now, it works.
Any ideas would be appreciated, and I'll update if I find a better solution.
W
<% form_for :user, :url => new_user_path do |f| %>
...
<% end %>
Inside "...", you can add all your fields, such as:
First name: <%= f.text_field :first_name %>
Last name: <%= f.text_field :last_name %>
...
<%= submit_tag 'Update' %>
However, our topic for today is actually radio buttons. Many times, we want to use radio buttons to select some sort of true/false field. It is possible to do this with checkboxes, andRoR is wonderful with this. However, sometimes, 2 radio buttons are better. This is where I ran into some problems. Reading the API, I came up with 2 radio buttons as follows:
<%= f.radio_button :is_good, true %>
<%= f.radio_button :is_good, false %>
I thought that this would generate two radio buttons with values true/false respectively. However, it didn't! The first generated one that had a value of "true" and was checked. But the second generated a radio button with no value! I then changed the given values from booleans to strings:
<%= f.radio_button :is_good, 'true' %>
<%= f.radio_button :is_good, 'false' %>
Everything worked fine now, but given a model that held data, neither radio buttons were checked! This is due to the fact that the model holds boolean values, whereas the radio buttons use string literals. Saving was fine because we were using prepared statements, which automatically convert the string literals to boolean. I was completely stumped on the displaying of data though. I came up with a quick hack using virtual attributes, but it's ugly:
def is_good_temp=(is_good_temp)
@is_good_temp = is_good_temp
if @is_good_temp == 'true'
self.is_good = true
else
self.is_good = false
end
end
def is_good_temp
@is_good_temp.nil? ? 'true' : @is_good_temp
end
def is_good
@is_good.nil? ? true : @is_good
end
def is_good=(is_good)
@is_good = is_good
end
and changed the radio buttons to:
<%= f.radio_button :is_good_temp, 'true' %>
<%= f.radio_button :is_good_temp, 'false' %>
So basically what I did was create a virtual attribute to deal with the radio buttons using string literals, and have that convert the string literals to booleans and assign it to the actual variable. To be noted is that there is no nice function object#to_b to convert a string literal to boolean. There are nice functions like object#to_s and object#to_i, but not to boolean.
This is one disappointment from RoR. I have searched around and could find no solution to this. Perhaps I am doing this wrong, but for now, it works.
Any ideas would be appreciated, and I'll update if I find a better solution.
W
Subscribe to:
Posts (Atom)