Sunday, September 11, 2011

Code abstraction with partials in Rails

Abstraction was the name of the game tonight. As you many know, I have a _menu partial running across most of my pages. This partial links to a character, as well as his spells, skills, items and so on. I had a second area in the Character's view page that allowed users to add new pages, and the link would disappear once the page had been created. Why not move this create method up into the _menu partial and get it out of the Character's view page? That makes sense, right?

I thought so, but here was the problem. I had some text that said "Add:" with links for items, spells, skills and so forth. I didn't want either the text or the link showing up unless the page hadn't been created. Only showing a link_to method if that page hasn't been created is easy, but I couldn't figure out a simple way of only displaying some text if all pages that could be created hadn't been created. An easier solution would have been just to axe the "Add:" text altogether, but I like it as a bit of guidance and separation.

This may be a case of me understanding partials well, so every problem appears to be a problem that can be solved with partials, but here's how I wrote the code.

First, I created a new partial, called "_menu_create" and threw it in the Characters view folder.

Here's the code for the partial:

<%= link_to 'Items Page', character_items_path(@character) unless @character.items.exists? %>
<%= link_to 'Background Page', new_character_background_path(@character) unless @character.background %>

And here's the method for rendering the partial:

<% unless @character.items.exists? and @character.skills.exists? and @character.specials.exists? and @character.spells.exists? and @character.background %>
  <%= render 'characters/menu_create'%>

I feel like this is a bit over-engineered, especially since all it does that's different is not display the "Add:" text, but it works and I'm pleased with the result.

What's your opinion? Is there an easier way to do this? Is there also an easier way to group several conditionals together, so instead of writing the code as:

<% unless @character.items.exists? and @character.skills.exists? and @character.specials.exists? and @character.spells.exists? and @character.background %>

I could group all of these into a grouping called "conditions", and call something like:

<% unless @character.conditions? %>

Which would have the same effect? I'm guessing there IS something like this, and I just haven't run into it. I'm also getting the feeling I'm ready to move onto another project pretty soon, maybe running through more tutorials, or getting another book, or working on another personal project. Any suggestions? Should I keep working on Manticore? It's kind of hard to get a feeling for WHAT I should be working on, just that I should be working on SOMETHING. Crafting Rails Applications isn't quite what I was looking for, either. I was expecting something closer to Agile Web Development and it's more like a series of mini-tutorials, mostly for serious customization and I'm not quite ready for that jelly.


  1. Sounds like you have the right idea w/ @character.conditions?

    Go into character model and define it.

    def conditions?
    all those 'and' conditions

  2. @Brent aha, I should've guessed defining it in the model was the solution. I'll give this a shot tonight. Time to fatten up that model!