Tuesday, September 13, 2011

Validating integer ranges in Rails

Taking my friend Matt's advice, I redid the validation and logic for my models in Manticore tonight. Didn't take too long and the new way makes more sense than before.

Here's what I had before:

class Initiative < ActiveRecord::Base   belongs_to :character   validates_presence_of :dex, :misc, :speed   validates_numericality_of :dex, :misc, :speed   def total     dex + misc   end end


And I've changed it to:

class Initiative < ActiveRecord::Base   belongs_to :character   validates_numericality_of :dex, :misc, :speed   validates_inclusion_of :dex, :misc, :in => -10..20, :message => "must be between -10 and 20."
  validates_inclusion_of :speed, :in => 20..200, :message => "must be at least 20."

  def total
    dex.to_i + misc.to_i
  end
end


A pretty minor change, but here's what this is doing. First off, there's no need to validate both for presence_of and numericality_of an object. Validating numericality_of an object will in effect also validate_presence_of that object, since it must be an integer to pass validation.

Secondly, I've added a validates_inclusion_of to ensure that all integers make sense within Dungeons and Dragons rules. For example, :speed refers to how many feet a character can move per round. The vast majority of characters are going to be either 20 or 30, so I set 20 as the base. However, there are ways to get higher speeds, through class benefits, spells, magical items and so on, so I set the upper limit at 200. I don't use this object to make any calculations, but it's nice to have information that makes sense for a Dungeons and Dragons character, since Manticore is a Dungeons and Dragons character database program.

Lastly (and I think this might be a bit of overkill) I added .to_i to my logic, which will ensure all objects are integers before attempting to perform calculations. Am I right about this one? It also sets nil to 0, right? Pretty handy, considering I was wanting a way to set nil to 0 a while back.

I started to bang out a question, but as I was writing I got an idea of how to do what I want to do, so I'll give it a shot before asking for help

Monday, September 12, 2011

Code abstraction and models in Rails

I felt like I had a minor break through tonight, thanks in part to my friend Brent. Abstracting code using partials is something that's made sense to me for a long time. Basically, you're just cleaning up the code of a view by creating another bit of code that's called using a render method.

However, last night as I was writing some partials, I noticed I was loading quite a bit of logic into my view and it felt wrong, somehow. I felt...dirty. I was on the right track when I assumed there was a way to collect this logic into a method, then just call that method in the view, rather than having all the logic piling up, making an untidy mess of my code.

But I didn't quite get how to define a method in a model. Sure, I've defined methods such as:

def foo
  bar
end


But usually I got this code by following a tutorial, or reading through a book and so forth. It was never my code, and I think that was the reason I didn't really understand it. Now that a situation has arisen that I needed to learn how to write logic into a model and then call it in the view, I understand it. Funny how that works, huh?

Also, I don't think I'm quite as done with Manticore as I thought last night. I'm obviously still learning from working on it, and that's what I'm after. I've got some big ideas that are frankly a bit intimidating (user account creation and log-in, differing account types and permissions for dungeon masters and players, to name just two) but what's the best way to get over being intimidated by coding? By getting excited about coding. It's brought me this far, anyway!

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:

Add:
<%= 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.