Cleaner Ruby in a rails view

Hi –

On Fri, 3 Mar 2006, Brian Cully wrote:

I would love for ruby’s nil to behave properly, as it does in lisp and
objc.

A bit of a conversation-stopper, but we’ll just agree to disagree :slight_smile:

David


David A. Black ([email protected])
Ruby Power and Light (http://www.rubypowerandlight.com)

“Ruby for Rails” chapters now available
from Manning Early Access Program! Ruby for Rails

The only time this nil problem occurs for me is with rails views. With
all other ruby (about half my time is spent in ruby and the other half
web apps) code, I never have the nil problem unless I’ve written bad
code. I feel like web templates should not throw errors if you pass nil
values.

On Fri, 2006-03-03 at 03:07 +0900, Yukihiro M. wrote:

something like nil in Objective-C by yourself, using the combination
swallowed so many errors, and made my debugging horrible. Perhaps
a separated special value dedicated for the purpose might be
better.

Charlie B.
http://www.recentrambles.com

On Mar 2, 2006, at 1:06 PM, [email protected] wrote:

pass nil
values.

Probably the best thing is to do whatever’s necessary in the
controller to make sure the template can coast. So you could, for
example, put list.items (or whatever) in @items, making sure in
advance that it’s an empty array if there aren’t any.

Bingo. I think that’s the perfect answer here.

Remember that you can always declare Helper methods that deal with
the nils for you too.

James Edward G. II

I think that is the best answer so far…but that seems to go against
everything that makes ruby so great. Something just doesn’t feel right
about creating an object just to say that it’s empty. I guess I should
ask this on the rails list, but I like this list much better :slight_smile: , Is is
possible to add methods to the nil class in only the views? If so, that
would be awsome!

Probably the best thing is to do whatever’s necessary in the
controller to make sure the template can coast. So you could, for
example, put list.items (or whatever) in @items, making sure in
advance that it’s an empty array if there aren’t any.

Charlie B.
Programmer
Castle Branch Inc.

Charlie B. wrote:

controller to make sure the template can coast. So you could, for
example, put list.items (or whatever) in @items, making sure in
advance that it’s an empty array if there aren’t any.

Charlie B.
Programmer
Castle Branch Inc.

Hi Charlie,

I think that David’s plan is a good one. I also think that his answer
has less to do with Ruby and more to do with the appropriate use of the
Model-View-Controller framework (if that’s the right word).

As I understand it, the role of the controller is to be the setup guy
for the view. You really want to have as little significant Ruby code
as you can in the view, and that’s what David’s answer is getting at.
Make the controller ensure that the view has an Array to deal with
rather than let the view worry about what you’ve given it.

Hope that helps.

Regards,
Matthew

Hi –

On Fri, 3 Mar 2006, Charlie B. wrote:

The only time this nil problem occurs for me is with rails views. With
all other ruby (about half my time is spent in ruby and the other half
web apps) code, I never have the nil problem unless I’ve written bad
code. I feel like web templates should not throw errors if you pass nil
values.

Probably the best thing is to do whatever’s necessary in the
controller to make sure the template can coast. So you could, for
example, put list.items (or whatever) in @items, making sure in
advance that it’s an empty array if there aren’t any.

David

Objective-C.


David A. Black ([email protected])
Ruby Power and Light (http://www.rubypowerandlight.com)

“Ruby for Rails” chapters now available
from Manning Early Access Program! Ruby for Rails

Hi –

On Fri, 3 Mar 2006, Charlie B. wrote:

I wrote:

Probably the best thing is to do whatever’s necessary in the
controller to make sure the template can coast. So you could, for
example, put list.items (or whatever) in @items, making sure in
advance that it’s an empty array if there aren’t any.
I think that is the best answer so far…but that seems to go against
everything that makes ruby so great.

That doesn’t say much for all the other answers :slight_smile:

Something just doesn’t feel right about creating an object just to
say that it’s empty. I guess I should ask this on the rails list,
but I like this list much better :slight_smile: , Is is possible to add methods
to the nil class in only the views? If so, that would be awsome!

I suppose you could engineer a way to do that, but it sounds awfully
fragile, and like an awful lot of trouble to go to. I’d rather
normalize the data to an array (or whatever) and then just let each
array take care of itself.

David


David A. Black ([email protected])
Ruby Power and Light (http://www.rubypowerandlight.com)

“Ruby for Rails” chapters now available
from Manning Early Access Program! Ruby for Rails

On 3/2/06, [email protected] [email protected] wrote:

Probably the best thing is to do whatever’s necessary in the
controller to make sure the template can coast. So you could, for
example, put list.items (or whatever) in @items, making sure in
advance that it’s an empty array if there aren’t any.

David

Just to illustrate a point about Rails, I had a similar problem. Some
other code allowed a record to be posted to the DB w/o a good
referential link. IOW, the FK in the record pointed to a missing
record in the linked to table. The Rails view just spit out an
attribute of the linked table and that caused the app to crash because
table1.table2 was nill and table1.table2.field => ‘field’ was not a
valid method of nil.

So I tried the trick posted earlier and it cleaned it up nicely. I’m
sure that this problem comes up all the time, and there are probably
better ways to handle it, but this abstraction was quite nice:

In the controller’s helper, I added a method_missing dispatcher:

module MycontrollerHelper
def method_missing(methodname, *args)
“MISSING RECORD”
end
end

In the view: (in my case rxml)

xml << (table1.table2 || self).field

Hopefully, you have no other need for method_missing in your view.

I’d be interested in others take on this common problem.

Ed

Charlie B. wrote:

Something just doesn’t feel right about creating an object just to
David

Charlie B.
http://www.recentrambles.com

You know, I don’t much monitor the rails list but I think that maybe
this is something that you would want to run by those folks before you
make any big design decisions. The folks over there really do spend a
lot of time on rails-specific issues and you’ll probably get more
discussion over there if not better. I’d be curious to hear what they’d
say about this myself since I’ve been where (I suspect) you are before.

Regards,
Matthew

I think the “and-call” operator discussed recently would be a very very
very nice addition, especially since in Rails Views (or any
presentation layer on most any framework in most languages) has the
ever-so-common “obj ? obj.value : nil” mini-pattern.

Of course it doesn’t really apply in this specific case since there’s
an empty array available, but:

item.cart_item_option_values &? each do { |ov| blah }

Would be nice.

I guess I am being a little picky. ruby and rails both are the best at
what they do and it’s hard to watch it fall short ( in my very picky
eyes ) in this one area. I am going to work on adding a plugin to rails
that will fix the nil problem. At least then I won’t have to call a
helper method, rescue nil, or create an empty object just to display a
view. This has been a great discussion! It’s too bad that it wasn’t on
the rails list…

David

Charlie B.
http://www.recentrambles.com

Forgot to add that with the second example, you’d probably want an <%
else -%> clause to output something useful in that event, but you’re a
clever bunch. :wink:

Hi all,

Interesting discussion… I’ll just add that the following:

<% item.cart_item_option_values.each do |ov| %>

Can be:

<%= render :partial => ‘foo’, :collection =>
item.cart_item_option_values %>

_foo.rhtml would contain the markup used to render each item in the
collection. Sometimes I also like to do this, however:

<%= render :partial => ‘foos’, :object => some_collection %>

And then in _foos.rhtml have logic like:

<% if foos -%>

    <%= render :partial => 'foo', :collection => foos %>
<% end -%>

In the latter example, you also might want to forego the collection
rendering capability and use ERb tags to do an each() block, simple
because too many levels of partials becomes cumbersome.

Either way, it’s generally more pleasing (if not outright useful, say,
for less savvy designers) to remove more complicated logic from the
‘root level’ view templates. The reason being, I think, because once
you get to a certain point, you’re logic is solid, but you’re markup
structure and flow might demand tweaking.