A Problem with Partials
Partials are incredibly powerful and flexible tools for a Rails developer; they help to DRY up view code, contextualize distinct presentational ideas and modularize markup for use in HTML or Javascript. It's been my experience, however, that each developer seems to use partials in a different way and, while I appreciate the value of personal coding style, these variations can cause confusion between developers.
The following techniques have proven to be 'best partial practices' for my fellow developers and myself. Adhering to these ideas helps us to keep our code consistent, legible and portable.
Keeping Organized
Organization and naming conventions are two initial hurdles in developing effective partials. It is an easy mistake to start arbitrarily organizing and naming partial files without thinking through their roles within the application.
I think that one pitfall is using (or at least over-using) a /views/shared directory for storing partials that will be used by many controllers. I used to use the /shared folder after seeing it used in the prominent Rails books and tutorials, and initially the logic of such a directory makes sense (especially before REST became the norm). That logic breaks down, however, when virtually ALL of your partials exist in that folder! If partials are meant to be reusable and flexible, shouldn't they all be in the shared folder? This is what would happen to me, and suddenly my file names lost a lot of meaning. What does the partial shared/thumbnail show? What about shared/favorite?
Certainly you can simply use more concise naming (user_thumbnail, favorite_video) but I have found that it's best to place these partials in the view folder of the related resource. There's nothing magical about the /shared directory, it's just as easy to use :partial => 'users/thumbnail' as it is to use :partial => 'shared/user_thumbnail'. I find storing the partial in /views/users, /views/videos, etc. helps to clarify the partial's function and keeps my files in order.
Another good practice is utilizing singular and plural naming conventions. In a recent project I was using two partials with poor names: shared/user_block and shared/user_thumb. The user_block partial accepted an array of Users as the :object and passed it on as :collection to the user_thumb partial, placing it all in a wrapper. I found that a name like user_block doesn't help me remember what the partial does - does it display a block of users, or one user in a block? By renaming my partials as users/thumbs and user/thumb, respectively, I was able to clarify their purposes and make it obvious which would display a single thumb versus a collection of them.
One other pitfall is mixing up where wrapper HTML is stored. A sidebar, for example, may have a series of modules that all use a common wrapper and header markup. Some of these modules are stored in their own partials, so should the wrapper markup go inside the partial? Or should that markup stay in the view file and wrap the render method call? Either might be appropriate given any set of circumstances, but the most important thing to remember is to keep it consistent! Placing the wrapper in one partial but leaving it out of another can only lead to confusion down the road.
No Partial is an Island... or is it?
In software development modular design is king. The ability to create portable, flexible and self-sufficient chunks of code significantly helps speed up development and code reuse. So why not apply the same principles to partials? Partials, like any other code, can become much more robust and useful when given good defaults, error handling and documentation.
If a partial were a method then :object, :collection and :locals would be the arguments. Unlike arguments, however, there is no built-in way to ensure that these passed variables are valid or even present. It is simple, however, to mimic this functionality within the RHTML template. For example, the following partial displays a series of thumbnails for recently added videos (the partial name is videos/recent_thumbs):
<% limit ||= 10 %> <% videos = recent_thumbs || Video.find_recent_videos(limit) %> <div id="recent_video_thumbs"> <%= render :partial => 'videos/thumb', :collection => videos %> </div>
Default values are supplied for each variable that can be passed in to the render method. The number of videos displayed (limit) can be passed in through the :locals hash, otherwise it defaults to 10. The :object parameter, which reads as recent_thumbs within the partial, will be used if given; otherwise, the partial uses the Video class to find the most recent videos. This partial can be passed some, all or none of those parameters and will still work correctly.
But wait! Isn't this placing application logic in the view?! Isn't this strictly taboo?! Though it may approach that line, I believe this is still clean code. The actual logic is still stored within the Video#find_recent_videos method and this behavior is only the fallback behavior, not the primary functionality. In this situation it works, but that may not always be the case. If a fallback collection would not be available, proper error handling should be used instead:
<% raise ArgumentError, "The videos/recent_thumbs partial requires an array of Video objects passed as :object." unless recent_thumbs %>
Using these techniques achieves two goals. First, the developers are given more flexibility and less trouble with partials that can 'take care of themselves.' These partials can be easily dropped into a view and rely on defaults that can later be easily overridden. The developers are also given some 'documentation' about how the partial works. It may not be rDoc, but these variable 'declarations' at the top of a partial make it very clear what :locals it takes and whether it takes an :object and/or a :collection.
With a Little Help From My Friends
When passing a collection to a partial, I have often found the "collection_name_counter" variable to be very helpful (ie the thumb_counter in :partial => 'thumb'). This dynamic variable, built-in by Rails, gives the current index within the passed collection. As helpful as that can be, I usually find it to be incomplete without having access to the collection itself. Without the collection array I have no idea if the current index is the last item, the first item or any in between!
For a while I simply passed in the collection both as :collection as well as :locals => {:collection => @collection}. It worked, but it wasn't very DRY. To fix this I created a simple monkey patch module called PartialEnhancer. This hacks the partial code so that you have access to two more dynamic variables. If the partial were named "thumb" the variables would be thumbs and thumbs_count. The thumb_count variable simply stores the length of the collection for comparison with thumb_counter while the thumbs plural variable accesses the collection array directly. It's now very simple to find where a given object is within the overall collection within a partial.
Another partial-related problem struck me when I began working on a project that used a great number of nested partials within nested layouts. Whenever I had to change some view markup it was often very difficult to figure out where that markup was! Which stacked partial, layout or view did it belong to? To help me find my way I created another monkey patch module called PartialExposure. This module hacks the render method so that every layout and partial is wrapped in an HTML comment. Each comment displays the filename and path of each partial file and reveals exactly where it starts and stops. Thanks to that module I can now instantly figure out where display code exists, even on projects that I am not familiar with. Just make sure you only use it in Development!
