if current_user.guest?
Although I don't like how the example given returns an OpenStruct instead of a NullUser, for instance.You also could make use of ActiveModel::Conversion#to_partial_path, like so:
<%= render partial: current_user %>
This implicitly calls to_partial_path on the current user object and looks up a template to render based on that result. So the user model would return "users/user" and your guest object could return "users/guest".The problem with using nil here is that you have to remember to check it everywhere, all of your tests have to exercise both the nil and not-nil cases, and most of the "else" clauses are just going to substitute default values anyways.
In my opinion if your views know so much about your user model that substituting a "guest" object is hard, maybe it's a sign you need to pull some logic back out of your views.
Generally you will have sections of your app that are only for logged in users, so your ACL logic in your controller handily takes care of that, while still giving you the convenience of being able to call current_user and know that you actually have a user, while still being able to say things like `if current_user` where you need it.
I do like your render partial example, but in most cases you will want to be doing something like showing a like button if the user is signed in, in which case you can do:
<%= render partial: current_user %>
And if the current_user is nil the partial will just be skipped. current_user.usernameYour example is pretty simple, so my solution will sound like overkill, but I would use some other type of object such as a Presenter to handle the rendering logic.
I've worked on very large and well used applications (billions of loads, multiple data centers, hundreds of thousands of lines of code), not that that should really matter to the argument (logical fallacy and all that), but the thing that I've found messes up Rails applications is large model objects ("god objects"), poorly thought out data relationships, and inconsistent assumptions across systems that lead to hacks. Not nils.
Sorry, you're completely wrong. Polymorphism and duck typing exist specifically so that you don't have to do `is_a?` checks.
> but the thing that I've found messes up Rails applications is large model objects ("god objects"),
How do you think god object models get created in the first place? By not extracting out logic. When you have models that have very different state, you actually have very different objects. Those differences should be extracted into different classes.
embrace OO
>There are lots of places in an application that you'll want to conditionally show logic, like whether or not to show a "reply" button, and it is more natural to say "if current_user" than "if current_user.name != 'Guest'".
"if current_user.name != 'Guest'" is way more natural (not saying that is good or bad.) I read that as "if the current user is 'Guest'" whereas the former reads, "if there is a current user". There is obviously a user. When isn't there one?
Don't read too much into this, I am just speaking about what looks natural in your specific comment.
If instead you'd have a car object in the context of an app that sells junkyard items, it would make sense to return '0' instead of 'nil' when it concerns wheels (wow, this might be a terrible example...).
It seems to me that using too much of this implicit 'semantic thinking' is to be avoided, especially when the semantic meaning is not entirely clear or always agreed upon, like with user objects.
And if you look at this that way, it might be best to avoid returning nil in general (except perhaps for 'primitives?), and instead always go for a boolean return value.
(I have little experience in these matters, so please correct me if I'm wrong!)
I find this pattern to be the most manageable especially in large projects.
But I agree with your point. "if current_user" is miles better than "if current_user.name != 'Guest'".
Edited to add: As far as this articles use of current_user.name being guest, it makes sense to use a presenter to display the data in the view. Conditionally displaying a user name or 'Guest' in a view is kinda gross. Again I'll suggest a gem for this pattern https://github.com/drapergem/draper
All objects coming into the view should be wrapped, especially and ActiveRecord objects.
It is even more natural to say `if signed_in?` :)
Devise provides such a method that checks for effective auth in warden, afaik (so it should know to make difference between a NullObject and an actual User). It would be easy to implement it yourself :
def signed_in?
current_user.is_a? User
end