Showing posts with label partials. Show all posts
Showing posts with label partials. Show all posts

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.

Sunday, June 5, 2011

Rendering a different view using partials

Remember yesterday when I was talking about having a good day followed by a bad day with Rails? Looks like today is going to be a good day!

Something I've been wanting to do with Chorenivore is change the view so it only displays the information for a task (Done, Task, Description, Created) if there actually IS a task. Otherwise, this information shouldn't be displayed, right?

This morning I woke up with the idea of creating a couple of partials and then rendering them with an if else statement. So right away I got started. I broke out the code displayed in the view into 'yestask', then creating a partial called 'notask' that didn't display anything but a method for creating a new task.

Here's what I tried at first:

<% if @task.blank? %>
<%= render 'notask' %>
<% else %>
<%= render 'yestask' %>
<% end %>


This code doesn't throw an error, but it doesn't do what I want. In this case, it bypasses 'yestask' altogether and only renders 'notask'. I dug around in Tasks controller and realized I should be writing the code like so:

<% if @tasks.blank? %>
<%= render 'notask' %>
<% else %>
<%= render 'yestask' %>
<% end %>


I get why this version works, because it's checking if there are any instances of @task. I'm still not sure why just calling @task.blank? didn't work. Is it because @task is a method, while @tasks is defined in the controller as Task.all?

Definitely feels good to make some progress, even if I'm not 100% sure about why the method I tried first didn't work.

Another general question: Is using partials in this way a good practice? I kind of feel like I understand partials pretty well, so every problem appears to be something that can be solved with partials. There's a metaphor buried in there somewhere.

Saturday, June 4, 2011

A little Saturday morning code jam

Here's my latest trouble with Manticore.

Eli showed me this code for a menu partial, which I put at the top of the Character view page. It allows you to switch to the view of a different model that belongs_to Character.

<%= link_to_unless_current 'Character', character_path(@character) %>
<%= link_to_unless_current 'Armor', character_armor_path(@character, @character.armor) %>


So this links to Armor's view page. Pretty awesome, except it doesn't work if Armor hasn't been built yet, which will be the case whenever creating a new character. Ops! I thought putting a method for creating a new instance of Armor if one didn't exist would fix this problem, but I couldn't get that to work, either. Also, I'm not convinced that's the best way to handle this problem. For another thing, I want to link to an Item page, not an Armor page, since I see Armor as being an Item.

I updated that code and here's what we've got now:

<%= link_to_unless_current 'Character', character_path(@character) %>
<%= link_to_unless_current 'Items', character_item_path(@character, @character.item) %>


However, this gives me a new error.

No route matches {:controller=>"items", :action=>"show", :id=>nil, :character_id=>#<Character id: 7, name: "Test" ... updated_at: "2011-06-04 15:43:59">


I'm not sure why I'm getting a routing error. Here's my route code:

resources :characters do
  resources :statistics
  ...
  resources :items
end


Here's what I'm trying to do with this menu partial. I'll want to have 5 links: Character, Items, Skills and Feats, Spells and Background. Much like the code David showed me for creating Statistics, I know I can use this method for all of them once I have it down.

And here's what I want the links to do. Clicking on Items will allow a user to create various types of items associated with that character: weapons, armor, pimp canes and so on. At this point I'm assuming Item will need to be a separate model, because it will have a belongs_to relationship with Character, right? Even though it's just going to be used as a view that displays forms for creating other models?

And Character should have a has_one relationship with Item, right? It's just going to be a single page, and while a Character can have many weapons, armors and pimp canes, I'll only be working with one Item view.

I'll have a day where everything I try to do works and I'm making great progress and I'll feel like the champion of code, then the next day I'll switch gears slightly and feel like I'm adrift on a hostile sea of errors. Anyone else have this same experience when you were learning Rails?