Tuesday, May 31, 2011

More work on Chorenivore

I'm still working on Chorenivore, my to-do list application. Nothing major to report, but I'm still wrestling with a way to update the Finished? status from the view.

What I've read suggests I should have two methods in the Tasks controller, called Finish and Unfinish. This makes sense, because then a user could toggle this status from the Tasks view with either a button_for or a link_to.

So here's the code I've got so far:

def finish
  { redirect_to(tasks_path, :notice => 'Task completed!') }
end

def unfinish
  { redirect_to(tasks_path, :notice => 'Did you forget something?') }
end


I haven't quite thought out HOW this method will be called, but I want a user to be redirected to the Tasks list once a Task has been marked as finished or unfinished. Am I thinking about this in the right way? What I want is to be able to mark something as finished, then have that change reflected in the view, and also to be able to change it back, in case you change your mind. Whoops! Is creating two methods the best way to do this?

I've also got this little number in the Tasks view:

<%= task.created_at.strftime("%b %d, %Y") %>


After some srs googling, I was able to find a way to display when a Task was created and format that information in a way I found acceptable. My only question is this: is this too much logic to load into a view? Couldn't I create another method in the Controller, then call it from the View?

Monday, May 30, 2011

Gettin my git on

Oh so you want to know about Memorial Day weekend coding? First off, at my friend Eli's insistence, I've been getting more familiar with keyboard shortcuts in TextMate. Who no longer digs through files to find what he's looking for? This guy. Who keeps everything in a project, then performs a little search magic with CMD+T? THIS GUY!

I also started using Git Hub, after almost three years of having an account. I understand how commits and pushing changes work, but I had some trouble last night. I was able to create a repository and upload the readme file, but then I couldn't get the entire project uploaded.

So here's what I think happened. I'm working with Chorenivore (my to-do list application) and I created a new directory at users/tylermoore/chorenivore, ran git init, tossed a README file in there and pushed it to git. Then when I went to upload the whole project, I was trying to push from users/tylermoore/code/chorenivore. Obviously having duplicate directories is a stupid idea!

So if I want to make a folder into a Git directory, ready for upload, all I have to do is navigate to that directory in terminal and use git init? Or do I need to make a brand new directory every time, then copy all my code into it? It seems like I should just be able to set up the necessary files with an existing directory. Also, what does git touch do? Can you just enter git touch . to touch everything in the directory?

In more concrete code-related news, Chorenivore is coming along pretty well. After creating the initial files with a scaffold (something my friend Matt says is a bad idea, even at early stages, and while I DO agree with him, I'm still finding it useful) I was able to edit the default code to do a few things I wanted to do. For example:

After creating a new Task, the user is taken back to the Task index page. A user is also taken back to the Task index page after deleting a Task and a flash :notice is displayed.

Creating a new Task does not allow a user to mark a Task as complete, but Editing a Task DOES allow this. Since scaffold generates New and Edit actions that use the same form, I simply copied the code and modified it so the boolean column for Finished? wasn't included.

Not bad! I've definitely got an application that works and functionality that makes sense. I think I've been good about thinking about how things should work, but actually making that happen is getting easier.

Oh, here's my git profile.

Tuesday, May 24, 2011

Boolean behavior

So I finally found a (pretty good) tutorial to build the To-Do list application. This one is still a couple years out of date, but I was able to figure out how to do most of what it describes.

This tutorial also mentions the nifty-generators gem, which just applies some basic CSS so you don't just end up with the standard black and white view. It's neat, but I'll still end up doing most of my own styling on more finished applications. (CSS is, after all, my first love)

However, I ran into a problem when trying to get rails to generate a nifty-layout. The solution was to manually add nifty-generators to the gemfile list. Easy enough!

So I ended up with three columns: name:string, description:text and finished:boolean. I've never used a boolean field before, and I did not find the standard issue true/false states satisfactory. Another google search gave me the code to edit this to a more user-friendly yes/no.

This was simply a matter of updating the view. I went from this:

<p>
  <b>Finished:</b>
  <%= @task.finished? %>
</p>


To this:

<p>
  <b>Finished:</b>
  <%= @task.finished? ? 'Yes' : 'No' %>
</p>


Aww shit, who is the dude so rad he uses a ternary operator? (Side note: I should probably brush up some more on my Ruby. But Rails is SO HOT right now!) I also updated this in the edit file, mostly for consistency.

However, I still want to be able to check or uncheck a task as "Finished," and have that change reflected in the database and displayed on the view, as well. I'm sure this is easy enough to do, but I haven't found quite what I'm looking for yet. I haven't been able to convert the old code the tutorial provides into code that makes more sense to me yet.

I also added some validation to the Tasks model. First, a task must at least have a name, right? Description should be optional, so I won't require that. How much description does "Take out the trash" really need? I also think a task is unique, so I am validating for that, as well. I also figured it makes sense for the name and description to have character limits, mostly to keep the view tidier. And here's my Task model:

class Task < ActiveRecord::Base   validates_presence_of :name   validates_uniqueness_of :name   validates_length_of :name, :maximum=>30
  validates_length_of :description, :maximum=>100
end

And that's about it. I spent about an hour working on this, of which about 15 minutes was generating working code, 15 minutes was googling for more information and 30 minutes was spent trying to figure out how to get that boolean field to behave.

Sunday, May 22, 2011

Everybody's coding on the weekend

So here's what I've been up to today:

RAILS TUTORIALS

I like doing tutorials and I always learn something new from each one, but there are some annoying factors. For one thing, since Rails has been around for a while now, a lot of the tutorials I find that I want to create are for older versions of Rails. I'm still interested in doing these, but figuring out what the new syntax is for older examples is tricky. I found an updated version for the recipe application and finished that up last night. Now I'm trying to find a new version for a to-do list.

I tried a couple of video tutorials, but the problem with those is I like to code along with the tutorial, and it's a pain in the ass to constantly pause and restart a video. Still, railscasts is a great resource and it would be worthwhile just to watch, even if I'm not coding along with the video.

One final gripe: a lot of Rails tutorials are geared towards beginners, so every one walks me through what Rails is, a brief history of Rails, how to install Rails and so on. I get it, and it's useful, but it gets tedious. I'd like to see more tutorials geared for slightly more experienced users. Do such things exist? I don't know!

Still, doing just a fucking ton of tutorials is a good idea. I'm learning new things and reinforcing what I already know to the point that I can do some things automatically.

One useful thing I learned today: setting up a Project with TextMate, because I saw a video where a guy was using it and thought "Oh man, why am I still browsing back and forth through a series of folders? That seems MUCH better!" So sometimes it's not a matter of learning new things, it's a matter of learning new ways to use familiar tools.

Saturday, May 21, 2011

A little late-night coding

I wish I didn't have to get up at 7 am during the week. I've always felt most productive and focused when working on projects late at night.

I've been reading the archives at railstips.org lately. I'm using some liberty when I say "reading the archives," because I really only got to this article on good Rails tutorials.

On a side note: I've linked to a 5 year old article which is a link to another article which is a collection of Rails tutorials. Is that ridiculous?

ANYWAY! My friend Eli encouraged me to try out some of these tutorials, despite their age. Most of them use bizarre, antiquated syntax. Luckily, I found an updated version of the first tutorial, which walks you through creating a recipe database. It's a simple application, allowing a user to create recipes and categories, then assign recipes to categories. I can think of several ways to expand functionality for this application: allowing users to search by ingredients, sorting recipes by categories, allowing users to create meals consisting of multiple recipes and so on.

I try to think of these things when I'm doing a tutorial or working on a personal project. I always ask "What else could be done? Where else could this go?" Luckily, Rails not only makes it easy to build something functional very quickly, it also makes adding functionality easy. I'm not sure if this is true for most other languages, but I highly doubt I'd have gotten interested in Rails if it wasn't so simple to pick up the basics.

Not that I think I'm an expert, or even knowledgable! I still get discouraged, especially when I can't figure out how to do something that SHOULD be easy, but I'm getting better every day. I'm planning to work through some of the tutorials on that list, hoping to learn some techniques that I can apply to Manticore and other projects.

A couple of interesting things I learned tonight:

Linking back to the main page of an application:

I got on irc and asked about this. It turns out the trick is this:

<%= link_to 'Home', :root %>

I'd tried linking to various forms of home, index, homes_path and index_path with no luck. This nice little trick saves a bit of time when navigating, though in a real application I'd want to use breadcrumbs instead. I'm assuming that would be built in much the same way?

Pulling information from one model and displaying it in the form of a second model:

In this application, I have two models: Recipe and Category. Each Recipe will belong to a Category, and to build this information in the form for a new Recipe, here's the code:

<div class="field">
  <%= f.label :category %><br />
  <%= select "recipe", "category_id", Category.find(:all).collect {|p| [ p.name, p.id ] }, {:include_blank => true} %>
</div>

It feels good to make progress, and I think I should be talking more specifically about what I've learned. I feel like my learning has been all over the board, but maybe that's how everyone learns to code.

Thursday, May 19, 2011

WTF is an attribute

So I've run into another wall in my work on Manticore. Basically, here's where I'm at right now:

I have the Character model, with several models with a has_one association: Statistic, Fortitude, Reflex, Will, Armor, Hp and Initiative. These are all displayed on the Character show page.

What I want to do is create a horizontal menu bar that link to other pages with further information. The first one I want to do is an Items page, with various items such as Weapons, Armor, Magic Items, Gear and Treasure. I'm seeing these as separate models that belong_to the Character model, but I'm unsure how to go about building this.

Look, I made some visual cues (mostly because I am awful at explaining what I'm trying to do)


Here's a rough idea of how the final, styled application might look. At the top, you'll see "Items." This will be a link that takes a user to a new page, like so:


So now for more questions!

When I asked about this on Stack Overflow, several people said the models I've created for Character (Hp, Armor, Statistic, etc) should really be attributes. I'm not clear on how an attribute differs from a model. Can a user edit an attribute from the view the way a user can edit the model, the way I've built it? Am I creating too much complexity here? My thinking was that things that change (relatively) often, such as Items, Spells, Statistics, should be Models for ease of editing, styling and displaying, whereas things that don't change, such as a character's name, class, race, etc, would be created as columns in the Character model.

Should these be attributes instead of columns? Are columns attributes? I'm not entirely sure what attributes are, and it's hard to find concrete information.

In other news, I've been reading through the archives of railstips.org. I found an article about 12 great rails tutorials, but the problem is the article it linked to is 6 years old. What! So if you've got any great tutorials that are more recent, lay them on me.

Onward!

Sunday, May 15, 2011

Triumph of the heart

So Blogger was down for a day or two this week, which sucks because I really wanted to talk about the progress I've made with Manticore. Thanks to a ton of friendly advice from more experienced coders (UnixMonkey, jqr and a ton of guys on Stack Overflow) I finally fixed the problems I was having with the has_one relationship.

For people who are just tuning in, Manticore is the Dungeons and Dragons character database application I'm working on. I had created a Character and a Statistic model, where Character has_one Statistic and Statistic belongs_to Character. However, I had some issues with displaying the Statistic model on the Character page, and also ensuring there was only one instance of Statistic in use at any given time. But no more!

I was able to take the code David (UnixMonkey) showed me on github and extrapolate that to create new models that belong_to the Character model with a has_one relationship.

So far, I've got a working Character model, with models for character statistics, saving throws, armor class, hit points and speed. I'm beginning to see how I want all this information displayed. Eventually I want it to be a page with 5 tabs: Character, Equipment, Skills and Feats, Spells and Background. I see the Character tab as being a quick sheet with all the relevant information for playing a game, and the other tabs having more detailed information.

I'm also thinking about other things I can do with this app. For example, Armor Class is composed of several different numbers: values for armor worn, a shield, a character's dexterity modifier and more. So it would be pretty easy to ensure the total AC value is equal to all of the separate values and display an error message if this is not true.

I mentioned that I see the Character tab as being a quick page with combat information at the ready. Eventually, I'd like this page to contain some tools to make playing a game easy from that view: stand alone dice rollers and specialized dice rollers that a player can create and save. For example, your character has a short sword and you want to save an attack roll with the short sword. So this would create a button that generates a random number from 1 to 20 (the attack roll) then adds in any relevant modifiers (attack bonuses, weapon enhancements, etc) and spits out a total number.

I've also been thinking about tools specifically for Dungeon Masters. Things like a database of plot hooks to generate ideas for campaigns or short adventures, an NPC personality and description generator and so on.

A lot of Rubyists go on and on about how Ruby on Rails makes programming fun. While I'm beginning to see why that's true (since you spend most of your time building things and not trying to get the tools you need to build things to work) I really think it really opens you up to what's possible. Now that I've got some ideas of HOW to build things, I'm getting lots of inspiration for things TO build.