Ruby on Rails : Cascade Insert

Among the many applications and ideas I have been working with is my Anime Manager, written in Ruby using the Rails framework for Web Application development. And one of the problems I have struggled with involves sequences. Since their are two elements that require a certain ordering: episodes and seasons. The requirements for ordering the seasons is less stringent as the position numbers are used exclusively for display purposes, but are never actually shown to (or modifiable by) the user.

For example, a series of seasons with position values 1, 2, 4, 5, 7, 8, 9 is not a sequence we need to worry about heavily as the implementation does not stipulate the display of these numbers, they are used as a means of ordering. However, a series of episodes with this same sequence requires much more stringent ordering and series maintenance, as episode numbers are displayed to the user. This was the root of a problem that I have been battling for some time. Essentially, given the sequence of episodes 1, 2, 3, 4, 6, 7 if I insert an episode in position 1 I would like the resulting series to be 1, 2, 3, 4, 5, 6, 7. I know of the acts_as_list construct for models and attempted to use it. However, it is too general, the resulting sequence is 1, 2, 3, 4, 5, 7, 8. Note the gap here.

I did some searching on Google, to no avail, this is something that is too rarely encoutnered or not something skilled Ruby developers have thought of, so I decided to come up with my solution. The idea I came up with was a simple gap check where given a desired position, we should check and see if an episode exists at that point. If it does, we select this episode and attempt to change its position to the next integer value. We recursively repeat this process until either we encounter a gap or reach the end of the series, at which point the stack begins to unwind.

Here is the code that I came up with to perform this cascading insert:
def number=( pPosition )
# first – use SQL to see if an episode exists at the specified position
ep = Episode.find( :first,
:conditions => [ “season_id = ? and number = ? and episode_type_id = ?”,
self.season_id, pPosition, self.episode_type_id ]
)
if ( ep != nil )
# recurse case
ep.number = (pPosition.to_i + 1) # recurse call
#write_attribute :number, pPosition.to_i + 1
ep.save #SAVE WITH NEW NUMBER
end

# assign to the position
write_attribute :number, pPosition
end

I was surprised this was not built into Rails somewhere, but I was glad to assist as after seeing this code a couple of developers expressed interest in adding it to the Framework, some even hinted that they remember seeing a module that was written to handle this problem.

I hope this help anyone who wishes to perform this type of insertion for a series

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s