Last week, while developing a feature I had some code like this in a view:
link_to_unless @post.url.blank?, "Link to post", @post.url
Where url is an attribute of type String
. As people usually don’t like negative conditionals, we can easily rewrite this code as:
link_to_if @post.url.present?, "Link to post", @post.url
However, we can clean our code a little bit using the #{attribute}?
method.
link_to_if @post.url?, "Link to post", @post.url
The #{attribute}?
method is a method defined automatically by Active Record. Intuitively, you may think that it is equivalent to !!url
and then would evaluate to true when an empty string, but Rails is smart enough to detect that the attribute is a string and returns the equivalent of !url.blank?
, as you may see in these lines in Rails source code, which proved itself very useful.
Active Record defines many other attribute methods like that, for example url_changed?
. What about you? What is your favorite Rails attribute method?
I tend to favor clear code over concise code, and here `@post.url.present?` feels more clear to me than `@post.url?`. If it’s a boolean attribute on the other hand, I’m all for the query method.
You have a point :). When developing an application, we should always measure conciseness over clarity.
But as this method is not widely used, it is not clear what it does, but maybe after getting used to it we may have it clear (like when we use [] instead of Array.new). I like to say that it is some kind of sugar (and Rails is full of sugars) to create beautiful code 🙂
+1 for the clear codes. Specially with a dynamic language like ruby I think we should always try to write clear codes. When I say clear, what I meant is that method names should implies what it does.
in the above case I prefer @post.url.present? over @post.url?
anyway thanks @Rodrigo for the blog post, AR ‘attribute’ indeed be useful
Well, of course we have a conflict. A conflict among principles! @post.url.present? might seem clearer than @post.url? And it is.
On the other hand, @post.url.present? seems to be a violation of the law of Demeter, which is more than a trivial “too many dots” rule at the end of the day. And it is.The solution to both concerns, might best be rendered thus: @post.url_present? Clearer and no Demeter violation. On the other hand, it seems a pain to be typing all of those ourselves, suggesting perhaps a change to the Rails structure, or at least, a concession to clarity for the sake of what we know to be a Rails convention. Leading finally to the possibility that yet another OO design issue is presented — that of not using the persistence layer itself as though it were the domain object. Since it is highly unlikely that each and every attribute will be .present?-tested, perhaps if we simply entered these only on an as-needed basis to a distinct domain-object as part of our TDD then rely on automagic? I leave these disputes to those more expert than I.Still, the more I read these nuanced discussions these days, the more I think that the DDD contingent may have it right, that this kind of logic really does belong at the end of the day in distinct business objects, which objects ultimately are used in connection with ActiveRecord through an architecture layer as a thin veneer over the database.Just saying.
I am certainly in favor of all things Ruby/Rails. I also believe that things like this becomes an issue of choice. Whether you use `@post.url.present?` or `@post.url?` is simply up to the programmer. I think using `@post.url.present?` will bode better results if someone comes in behind you to do some programming.
I don’t consider @post.url.present? a violation of the Law of Demeter. It is a method present on every Ruby object, so it does not require special knowledge of that object to call it.
i vote for this being semantically confusing
if you have boolean field on your post, say named ‘visible’ then asking post if it’s visible or not using post.visible? is semantically perfect
what does the question post.url? mean? are you trying to figure out if post is a url? because that is what my “least surprise principle” suggests you are doing
i would say it’s a mistake in rails to generate #{attribute}? for non-boolean attributes