Sadly, I was not able to spend nearly as much time on the rewrite project this week as I wanted to. I have a code release early next week for another project, and I still had a number of things to wrap up there. So, the rewrite project had to be put on hold for the second half of the week.
I did make some progress early in the week though. I now have 8 models working with all the relationships set up and behaving as expected. I decided to use a single-table inheritance pattern for a few of the models as well. This works really well. I debated the value of it early on. I really don’t like to see applications that seem to use complicated design patterns just for the sake of it. I’ve seen some extreme cases where it almost seemed like the developers were flipping through the Gang of Four Design Patterns Book making sure they used as many as they could. Early on it just seemed more practical to put some if blocks in various places to account for the different view behaviors I wanted to have, but in the end I realized that the single-table inheritance made the most sense.
So, why would I want to use single-table inheritance? In this application, I have a model called Attachment. An attachment can be of various file types (PDF, MOV, MP3, etc.). For the most part the differences are in how the attachments are displayed to the user. This is going to require an if block on the view regardless, so I was not sure how the inheritance model would benefit the design. To help me decide, I listed out all the things that I knew needed to be different for each of the types. The deciding factor was when I remembered the need to provide a way for users to convert the video files to flash videos for display on the site. This extra work of video conversion really belongs in it’s own class and not in the Attachment class. So, that was it; I had to do it.
Of course it’s really not a headache at all. I created a Video model which inherits from Attachment, and I added a field called ‘type’ to the Attachments table. There is not a table in the database for Videos. Rather when a Video object is created, ActiveRecord persists it to the Attachments table with a type of “Video”. And when I lookup a Video for retrieval, ActiveRecord knows to get it from the Attachments table but retuns a Video object.
There are a few things to remember when using this pattern. As with learning many things in rails, one of the best things to do is go to the command line.
>> my_video = Attachment.new(:name => "my video", :type => "Video", :file_name => "video231.mov") => #<Attachment id: nil, name: "my video", type: nil, file_name: "video231.mov", activity_id: nil, created_at: nil, updated_at: nil> >> my_video.type= "Video" >> my_video => #<Attachment id: nil, name: "my video", type: "Video", file_name: "video231.mov", activity_id: nil, created_at: nil, updated_at: nil> >> my_video.class.to_s => "Attachment"
As you can see here, I created an Attachment and tried to set the type to “Video”, but the result is a type with a value of nil. Next I set the type to “Video” and this appears to work, but calling the .class method reveals that the object is an Attachment which is not really what I wanted. The correct way to create the object is this:
>> my_video = Video.new(:name => "my video", :file_name => "video231.mov") => #<Video id: nil, name: "my video", type: "Video", file_name: "video231.mov", activity_id: nil, created_at: nil, updated_at: nil> >> my_video.class.to_s => "Video"
As you can see, I now have the correct object type giving me access to all the methods and attributes of both a Video and an Attachment object. Those of you from Java land should think of the Attachment class as abstract. In most cases you should work with the sub class instead of the parent.
I hope this is helpful to those of you learning Rails and ActiveRecord. Please feel free to ask me questions or just let me know you stopped by.
As a final commentary on my progress with the rewrite project, here is the output from calling rake stats:
+----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 538 | 371 | 7 | 43 | 6 | 6 | | Helpers | 19 | 17 | 0 | 1 | 0 | 15 | | Models | 51 | 33 | 8 | 0 | 0 | 0 | | Libraries | 0 | 0 | 0 | 0 | 0 | 0 | | Model specs | 125 | 101 | 1 | 0 | 0 | 0 | | View specs | 625 | 485 | 0 | 0 | 0 | 0 | | Controller specs | 1392 | 1032 | 0 | 6 | 0 | 170 | | Helper specs | 66 | 42 | 0 | 0 | 0 | 0 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 2816 | 2081 | 16 | 50 | 3 | 39 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 421 Test LOC: 1660 Code to Test Ratio: 1:3.9
Not too impressive just yet. Especially when you consider that most of the lines shown are from the generators.
{ 0 comments… add one now }