#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

RSS Feed for Episode Comments 33 comments

1. weskycn Jul 09, 2007 at 00:01

so good,thanks a lot.沙发!


2. chineseGuy Jul 09, 2007 at 00:31

nice and neat!~


3. riki Jul 09, 2007 at 01:41

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


4. Dmitry Jul 09, 2007 at 01:50

Couldn't download file :(


5. Daniel Jul 09, 2007 at 01:53

Can't download this episode, too.


6. Dmitry Jul 09, 2007 at 01:53

Both links are not works for me


7. Daniel Jul 09, 2007 at 02:29

Actually I can't download any episode, strange.

Hoping for a quick fix :)


8. ream88 Jul 09, 2007 at 02:59

media.railscasts.com seems to be down :(


9. 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.


10. David Jul 09, 2007 at 03:40

Download is working again!


11. Ted Jul 09, 2007 at 06:10

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


12. Carlos Jul 09, 2007 at 06:36

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


13. 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. :/


14. 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!


15. 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?


16. 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


17. crayz Jul 10, 2007 at 21:43

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


18. 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!


19. 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.


20. Ryan Bates Jul 15, 2007 at 08:19

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


21. 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.


22. 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.


23. 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?


24. 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.


25. 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!


26. 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.


27. 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.


28. 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.


29. 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?


30. Ryan Bates Aug 12, 2007 at 21:59

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

if item == items.last


31. 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!


32. PabloC Feb 20, 2008 at 09:31

Your work is amazing valuable. Thank you very much!


33. 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)


(use pastie or gist for code)

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