Forum: Ruby on Rails Nooby Help with created_at, updated_at, and if/then

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
E1555235468e98aa1800f5e3d9bc9601?d=identicon&s=25 Ben Goering (phoghawk)
on 2007-07-27 20:58
Hola. I'm super-new to actually doing things in rails and with ruby, so
pardon me if this is an easy question to everyone else.

I'm making a web app, and at this time am designing the news/blog
portion of it. I have a controller (posts) and a model (post) designed
to coordinate this. I started out with a basic scaffold and went from
there. At this point, I'm trying to get rails to print "Updated by
author on 1/1/07 at 3:45PM" if the updated_at time is different than the
created_at time. Here's my code:

<% for post in @posts.reverse %>
  <div class="post" id="post<%= post.id %>">
    <h2 id="posttitle<%= post.id %>" class="posttitleline">
      <%= link_to post.title, {:action => 'show', :id => post}, {:class
=> 'posttitle'} %>
      <%= link_to 'Edit',{ :action => 'edit', :id => post }, { :class =>
'postedit' } %>
      <%= link_to(image_tag('destroypost.png'), {:action => 'destroy',
:id => post}, :confirm => 'Are you sure?', :method => :post)%>
    </h2>
    <div id="postbody<%= post.id %>" class="postbody">
      <%= textilize(post.body) %>
    </div>
    <div id="postfooter<%= post.id %>" class="postfooter">
      <i>Written by <%= post.author %> on <%=
post.created_at.strftime("%B %d, %Y at %I:%M%p") %></i>
    </div>
  </div>
<% end %>

However, that string never shows up, and even weirder is that in the
default scaffold code, the updated_at and created_at values are the same
for every row. For the record, the default scaffold code is this:

<table>
  <tr>
  <% for column in Post.content_columns %>
    <th><%= column.human_name %></th>
  <% end %>
  </tr>

<% for post in @posts %>
  <tr>
  <% for column in Post.content_columns %>
    <td><%=h post.send(column.name) %></td>
  <% end %>
    <td><%= link_to 'Show', :action => 'show', :id => post %></td>
    <td><%= link_to 'Edit', :action => 'edit', :id => post %></td>
    <td><%= link_to 'Destroy', { :action => 'destroy', :id => post },
:confirm => 'Are you sure?', :method => :post %></td>
  </tr>
<% end %>
</table>

Any insight? Tips?
E1555235468e98aa1800f5e3d9bc9601?d=identicon&s=25 Ben Goering (phoghawk)
on 2007-07-27 21:25
Okay, I'm dumb. I copied that after I deleted the defective code. But
could anyone show me the best way to do that comparison?

If created_at isn't equal to updated_at, print "Updated by author on
1/1/07 at 3:45PM"
Ef0db53920b243d6758c2f6b1306df0d?d=identicon&s=25 Steve Ross (cwd)
on 2007-07-27 21:35
(Received via mailing list)
Some might debate this, but I find the best way is to factor the
whole thing into a helper or a model. E.g.:

# my model.rb

def timestamp_string
   updated_at > created_at ?
     "Updated by #{author} at #{updated_at.to_formatted_s(:short)}" :
     "Created by #{author} at #{created_at.to_formatted_s(:short)}" :
end

# my view.rhtml

<%= post.timestamp_string %>

This should clean up your view. If you feel this couples your model
too tightly with the display of the data, then create a helper instead.

Does this help?
E1555235468e98aa1800f5e3d9bc9601?d=identicon&s=25 Ben Goering (phoghawk)
on 2007-07-27 22:05
Steve Ross wrote:
> def timestamp_string
>    updated_at > created_at ?
>      "Updated by #{author} at #{updated_at.to_formatted_s(:short)}" :
>      "Created by #{author} at #{created_at.to_formatted_s(:short)}" :
> end

Yes, that should be good for cleaning things up, but I could still use
some interpretation of this.

How does the:
'updated_at > created_at ?'
line translate?

If updated_at is greater than created_at, then execute this block. Is
that right?

Does this take into account that I'd rather not have that "Updated
by..." string in there if updated_at and created_at are the same or do I
need to change this to:

def timestamp_string
    updated_at > created_at ?
      "Updated by #{author} at #{updated_at.to_formatted_s(:short)}"
      "Created by #{author} at #{created_at.to_formatted_s(:short)}"
    else
      "Created by #{author} at #{created_at.to_formatted_s(:short)}"
end
Aa51486286524e73ecb228aeb9687da8?d=identicon&s=25 Jim Gagne (Guest)
on 2007-07-27 22:55
(Received via mailing list)
> def timestamp_string
>    updated_at > created_at ?
>      "Updated by #{author} at #{updated_at.to_formatted_s(:short)}" :
>      "Created by #{author} at #{created_at.to_formatted_s(:short)}" :
> end

I've not seen the one-line if-then-else statement form like:
   <condition> ? <action_to_do_if_true> : <action_to_do_if_false>

expanded into MORE than one line. I just tried it in irb. It works --
SORT OF -- but it's hard to follow. These both work:

true ? 1 : 2

true ?
1 :
2

... generating an output of "1". But you can't leave anything out. So
these generate an error:

true ? 1

true ?
1

.. as do:

true ? 1 :

true ?
1 :

Besides, as Ben notes, they're not clear. So indeed, do it the easy
way:
  def timestamp_string
      if updated_at > created_at
        "Updated by #{author} at
#{updated_at.to_formatted_s(:short)}"
        "Created by #{author} at
#{created_at.to_formatted_s(:short)}"
      else
        "Created by #{author} at
#{created_at.to_formatted_s(:short)}"
      end
  end

But this won't work either, because methods return only the LAST
assignment statement, unless you include an explicit "return
<expression>". So regardless of the values of updated_at and
created_at, the above would return ONLY the line starting with
"Created by". (Try it in irb.)

Let's try again, eliminating the duplicate assignment while we're at
it. I added an end-of-line character so the strings wouldn't just run
together. And because you can't use the "+=" method unless a variable
has been initialized as a string, number, array, or something similar,
you wind up with something like:

  def timestamp_string
      s = ""
      if updated_at > created_at
        s = "Updated by #{author} at
#{updated_at.to_formatted_s(:short)}\n"
      end
      s += "Created by #{author} at
#{created_at.to_formatted_s(:short)}"
  end

If you REALLY wanted, you could shorten this to:

  def timestamp_string
      updated_at > created_at ? s = "Updated by #{author} at
#{updated_at.to_formatted_s(:short)}\n" : s = ""
      s += "Created by #{author} at
#{created_at.to_formatted_s(:short)}"
  end

---Jim Gagne---
Ef0db53920b243d6758c2f6b1306df0d?d=identicon&s=25 Steve Ross (cwd)
on 2007-07-27 23:04
(Received via mailing list)
Did I inadvertently stick a colon at the end of that? Oops. The
ternary operator, ?, is equivalent to an if/else. So:

updated_at > created_at ? stmt_a : stmt_b

is equivalent to:

if updated_at > created_at
   stmt_a
else
   stmt_b
end

It all depends on what you're used to.
Ef0db53920b243d6758c2f6b1306df0d?d=identicon&s=25 Steve Ross (cwd)
on 2007-07-27 23:07
(Received via mailing list)
That's why I used the ternary operator. It seems obvious to me that
the last evaluation will depend on the result of the conditional.

irb(main):001:0> a = 1
=> 1
irb(main):002:0> b = 2
=> 2
irb(main):003:0> a > b ? 'a is greater than b' : 'a is not greater
than b'
=> "a is not greater than b"
irb(main):004:0> a = 2
=> 2
irb(main):005:0> b = 1
=> 1
irb(main):006:0> a > b ? 'a is greater than b' : 'a is not greater
than b'
=> "a is greater than b"
irb(main):007:0>
E1555235468e98aa1800f5e3d9bc9601?d=identicon&s=25 Ben Goering (phoghawk)
on 2007-07-28 17:16
(Received via mailing list)
Thanks Everyone. Very Helpful :)
This topic is locked and can not be replied to.