At the risk of sounding like a dumb*ss, my most frequent error in Production is when an unexpected data condition results in a .erb.html receiving a null value for a variable, resulting in the screen not displaying at all.
a made up example → up to now, every book has a title. Somehow a new book is created without one…I don’t know, maybe because it hasn’t been decided on yet…and the data model lets this happen as nobody really expected it and maybe it is actually valid. Screens blow up left, right, and centre. Support run around trying to find the offending book and give it a blank title, or Dev have to rush a patch fix through.
Am I the only one? Can it not be just a little bit more forgiving than to crash the entire screen? Is there a magic setting for “erb, don’t freak out if you try to display a null field, just display a blank”?
I know that I can liberally sprinkle '&.'s for <%= @foo.bar&.baz %> but it is easy to forget.
I can write extensive system tests, but in practice there is a limit to ‘extensive’.
…and checking before trying to render a partial <%= render(@foo) if @foo %> feels a bit wrong
Hi, I mean in particular nil by associations <%= @user.organisation.name %> or <%= render(@user.organisation) %> when most users have an organisation then an unexpected case turns up when one doesn’t.
Sure, it is a nil association and shouldn’t work, but in practice Devs often write erb like this. Does it really have to be fatal? could @user.organisation.name not be nil if organisation is nil rather than blowing the whole screen?
Ah yes, I see what you mean. For your first example, <%= @user.organisation.name %> I often have methods in the first model (user in your case) along the lines of:
def organisation_name
organisation ? organisation.name : ""
end
… and then use user.organisation_name in the erb.
For the second example there is not much to be done except the changes in the erb as you suggest.
I agree that there should probably be a more elegant way to handle this.
Your app needs to decide if something like a book title is actually valid or not. If it’s valid, the template needs to handle it. If it’s not valid, then your “backend” need to make sure it doesn’t happen.
So not to sound unhelpful, but either the frontend side doesn’t know what data is expected or the backend side doesn’t and things break.
This sort of method chaining is often said to be violating the Law of Demeter. Not all method chaining is bad. For example when operating on a collection it can be a good way to break things down such as:
some_collection.map(&:upcase).sort.first 5
But in other scenarios, such as user.organization.name you enter the anti-pattern and risk the blow-up you encountered. Luckily Rails has a solution through delegation. In your User model you have:
class User < ApplicationRecord
delegate :name, to: :organization, prefix: true, allow_nil: true
end
Now when using the user model you no longer need to be concerned with how it relates to the organization model. You just ask the user for the organization name with:
<%= @user.organization_name %>
It feels like a small difference turning a . into a _. And you don’t necessarily always needs prefix: true. Sometimes the attribute is clear enough in scope enough as is. But it now just means your template is only concerned with the user object and anything that it internally uses (such as the organization) your template is no longer concerned about. It just needs to care about the user object and it’s public interface.
Thank you. I did not know of ‘delegate’. It feels much more Rails Way than adding methods like ‘def organization_name’…even though it does a similar thing.