#55
Jul 09, 2007

Cleaning Up the View

This episode starts off with a big, messy template. Watch as this code shrinks and becomes more readable while the interface stays the same.
Download (27.2 MB, 9:26)
alternative download for iPod & Apple TV (14.8 MB, 9:26)
<!-- views/carts/show.rhtml -->
<% title "Shopping Cart" %>

<table id="line_items">
  <tr>
    <th>Product</th>
    <th>Qty</th>
    <th class="price">Unit Price</th>
    <th class="price">Full Price</th>
  </tr>
  <%= render :partial => 'line_item', :collection => @cart.line_items %>
  <tr>
    <td class="total price" colspan="4">
      Total: <%= number_to_currency @cart.total_price %>
    </td>
  </tr>
</table>

<!-- views/carts/_line_item.rhtml -->
<tr class="<%= cycle :odd, :even %>">
  <td><%=h line_item.product.name %></td>
  <td class="qty"><%= line_item.quantity %></td>
  <td class="price"><%= free_when_zero(line_item.unit_price) %></td>
  <td class="price"><%= free_when_zero(line_item.full_price) %></td>
</tr>
# models/line_item.rb
def full_price
  unit_price*quantity
end

# models/cart.rb
def total_price
  line_items.to_a.sum(&:full_price)
end

# helpers/carts_helper.rb
def free_when_zero(price)
  price.zero? ? "FREE" : number_to_currency(price)
end

33 comments

weskycn Jul 09, 2007 at 00:01

so good,thanks a lot.沙发!


chineseGuy Jul 09, 2007 at 00:31

nice and neat!~


riki Jul 09, 2007 at 01:41

Download link doesn't seem to be working for me.


Dmitry Jul 09, 2007 at 01:50

Couldn't download file :(


Daniel Jul 09, 2007 at 01:53

Can't download this episode, too.


Dmitry Jul 09, 2007 at 01:53

Both links are not works for me


Daniel Jul 09, 2007 at 02:29

Actually I can't download any episode, strange.

Hoping for a quick fix :)


ream88 Jul 09, 2007 at 02:59

media.railscasts.com seems to be down :(


Daniel Jul 09, 2007 at 03:17

Congratulations on the popularity of these. I really like them. I couldn't download them either, until just now :) Had to wait for a break in the queue I guess.


David Jul 09, 2007 at 03:40

Download is working again!


Ted Jul 09, 2007 at 06:10

Fantastic example! Love the episodes. Please keep them coming :-)


Carlos Jul 09, 2007 at 06:36

Really nice this post, but could you create a screencast about test unites in views? Thanks!


Ryan Bates Jul 09, 2007 at 08:43

Sorry about the downtime guys. I guess that's the price to pay for the cheap Dreamhost bandwidth. :/


Jonathan Andrew Wolter Jul 09, 2007 at 14:06

Ryan,

These are really great!

One suggestion: Many people primarily consume your videocasts via iTunes and may only visit the home page.

It took me many weeks before I found out you had code examples in the permalinks. I'd encourage you to have a "Read more..." or "Read Show Notes/Code..." link from each post in the main index.

Just a thought, keep it up!


crayz Jul 09, 2007 at 20:37

I would disagree with the final refactoring of the loop into a partial/collection. It doesn't really slim your code at all, and will make future alterations more of a hassle as you switch between the two files. Good stuff though

I'd be interested in a review of more advanced concepts like using concat, capture, content_for - and when you might use those in conjunction with or instead of helper methods - e.g. the <% title "blog" %> at the top, how was that implemented?


Ryan Bates Jul 09, 2007 at 21:19

@crayz, yeah, the partial refactoring is questionable. I showed it mainly for variety to cover the different refactoring techniques.

The "title" method was covered in a previous episode: http://railscasts.com/episodes/30.

I have covered concat and capture in a previous episode as well: http://railscasts.com/episodes/40


crayz Jul 10, 2007 at 21:43

Cool, I'll check them both out - thanks Ryan


David Parker Jul 11, 2007 at 09:54

These continue to be a great help! This is one of the best ones yet, thanks Ryan!


Henrik N Jul 15, 2007 at 03:22

Continually impressed by the quality of your screencasts - thank you.

Minor niggle: I believe #to_a – you use "line_items.to_a" – is deprecated; you can do "Array(line_items)" instead.


Ryan Bates Jul 15, 2007 at 08:19

@Henrik, thanks. Out of curiosity, where did you hear that to_a was deprecated?


Aaron Jul 15, 2007 at 22:20

Being unaware of the ability to sum FixNum/Float arrays I've found inject to be a great tool for that particular job.

You mentioned that you would be interested in what others are doing and most of my sums look like:
@cart.items.inject(0.0){|total,item|total+(item.price*item.quantity)}

This is also a hack, but inject is very powerful and using it in simple cases like this has helped me wrap my head around much more complicated data transitions using relatively simple injects.


Henrik N Jul 16, 2007 at 00:43

Ryan: Just from deprecation messages in the console: "warning: default `to_a' will be obsolete".

Googling it a bit, it seems that it's specifically Object#to_a that is/will be deprecated. Various other objects have their own #to_a (see "ri to_a") which are not deprecated.


Mahmoud M'HIRI Jul 16, 2007 at 01:54

I found this screencast extremely useful, thanks!

I liked too much the _with_index, but when I tried to use it with a grouped instance variable: @items.each_with_index do |category, tasks, i| but it's not working :( any idea?


Ryan Bates Jul 16, 2007 at 07:22

@Mahmoud, each_with_index only passes two arguments into the block (the item and the index). Here you're trying to pass 3 arguments which it can't do.


Mahmoud M'HIRI Jul 16, 2007 at 12:44

I don't matter, you should found me how to get rid of the <%i=0%> and the <%i+=1%> I'm having in my code! otherwise the scrrencast is useless!

No I'm joking! , your screencasts are just making of us very tough people and high class coders, You have to assume!

Good luck!


Ryan Bates Jul 16, 2007 at 13:03

@Mahmoud, I recommend asking the question on railsforum.com where you can post the full code. I'll try to reply there if I know the answer.


TaQ Jul 26, 2007 at 19:51

Ryan, nice example!

I'm wondering about the total_price method on cart.rb. As I don't have a similar code here (hey, it's already late now), I'm wondering if we write the method this way

def total_price
line_items.inject(0) {|memo,item| memo += item.full_price}
end

can speed up things a little, avoiding the to_a and sum methods. What you think?

Best regards.


Ryan Bates Jul 27, 2007 at 08:36

@TaQ, I believe the "sum" method uses inject under the hood, so I doubt it would give you a speed boost.


Umang Chouhan Aug 11, 2007 at 06:48

If I use a collection. How do I know if the counter is at the last position?


Ryan Bates Aug 12, 2007 at 21:59

@Umang, you can see if the current item matches "items.last":

if item == items.last


Umang Chouhan Aug 13, 2007 at 01:28

Thanks Ryan! So, the partial counter is just an integer. Got it!

Amazing Screencasts Ryan! Thanks for all the hard work!


PabloC Feb 20, 2008 at 09:31

Your work is amazing valuable. Thank you very much!


kino May 23, 2008 at 01:56

We see in advance that, by virtue of a synthesis in which what is meant coincides and agrees with what is itself given, we have not simply lost scientific evidence for phenomenology; we retain it by virtue of a synthesis in which what is meant coincides and agrees with an object.

Add your comment:

(SKIP THIS ONE)

(required)

(not shown)


(required)

subscribe:
sponsored by:
if you want to help:
required:
Get Quicktime Player