Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

value_changed? helper method

#2281

Added a new helper method to TextHelper called value_changed?, also includes test cases and documentation.

value_changed? tracks the value passed in and returns true whenever the value changes from its previous setting. It can be useful when iterating through a set of data that is organized in subsets to display a new title for each subset.


# Assuming people has been sorted by occupation...
<% @people.each do |person| %>
  <%= "<h2>#{person.occupation.pluralize}</h2>" if value_changed?(person.occupation) %>
  <%= person.name %><br/>
<% end %>

This produces:


<h2>Doctors</h2>
Jane Doe
John Smith
<h2>Programmers</h2>
Rails Rules

This little bit of code replaces the common pattern of:


<% previous_value = nil %>
<% @people.each do |person| %>
  <% if previous_value != person.occupation %>
    <% previous_value = person.occupation %>
    <h2><%= person.occupation.pluralize %></h2>
  <% end %>
  <%= person.name %><br/>
<% end %>

Also, value_changed? accepts a name parameter to support nesting in loops (by default, the value is named "default").

I hope this is useful for others. It sure has been handy in my projects. Thanks!

Reported by Jason Arora · March 17th, 2009 @ 11:21 PM

State: wontfix
Milestone: 2.x
Assigned to: nobody
Importance: none

Activity

  1. Ian Terrell
    Ian Terrell

    Are there other use cases?

    Do you see this as much better than using Enumerable#group_by? (http://api.rubyonrails.org/class...)

    
    <% @people.group_by(&:occupation).each do |occupation, peeps| %>
      <h2><%= occupation %></h2>
      <% peeps.each do |person| %>
        <%= person.name %>
      <% end %>
    <% end %>
    

    March 18th, 2009 @ 04:35 PM

  2. Jason Arora
    Jason Arora

    Thanks for posting, Ian. You are correct, Enumerable#group_by is the best way to handle this pattern when ordering by a model attribute.

    However, the value_changed? method works really well for dynamic cases, such as:

    
    <% @people.each do |person| %>
      <%= "<h2>#{person.name.first}</h2>" if value_changed?(person.name.first) %>
      <%= person.name %><br/>
    <% end %>
    
    # => <h2>A</h2>
    # => Alan
    # => Amy
    # => <h2>B</h2>
    # => Barry
    # => ...
    

    Is this more acceptable? Thanks again for the feedback.

    Regards, Jason

    March 21st, 2009 @ 02:01 AM

  3. Ian Terrell
    Ian Terrell

    For this use case, Enumerable#group_by still seems best. The &:symbol syntax is shorthand for a block; you can spell it out for cases where you wish to group by something that isn't a method:

    
    <% @people.group_by{|person|person.name.first}.each do |initial, peeps| %>
      <h2><%= initial %></h2>
      <% peeps.each do |person| %>
        <%= person.name %>
      <% end %>
    <% end %>
    

    March 21st, 2009 @ 08:12 PM

  4. Jeremy Kemper
    Jeremy Kemper
    • State changed from new to wontfix

    Nice patch, but agreed that group_by is a better choice for the problem it's solving

    March 22nd, 2009 @ 01:42 AM

  5. Jason Arora
    Jason Arora

    Duh. :-P

    You're totally right, Ian. Thanks!

    March 22nd, 2009 @ 05:55 AM