简体   繁体   中英

Why do we need question mark in this rails try block?

I'm reading Rails Devise gem documentation and it says:

If the page could potentially not have a current_user set then:

if current_user.try(:admin?) # do something end

I have tried it without question mark

current_user.try(:admin)

and it works the same way returning true or false .

Do I miss something? Is there any difference and how can I see it?

Ruby is somewhat unusual in that it lets you include a wide range of characters in the names of methods including ? and ! .

They have no special significance to the interpreter but the language convention is that:

  • methods ending with ? are interrogative - they should ALWAYS return true or false.
  • methods ending with ! either mutate the object the are called on or may raise a exception.

So why does it matter at all? In this particular case it does not matter since your user class has an accessor for the @admin instance variable created by ActiveRecord - just like any other column.

If it did not however current_user.try(:admin) would always return nil. Remember that instance variables are always private in Ruby until you provide an accessor*.

# Just a plain old Ruby class - not an ActiveRecord model 
class User
  def initialize
    @admin = true
  end

  def admin?
    @admin
  end
end

User.new.try(:admin) # is always nil...

This is because User does not respond to :admin and .try prevents a NoMethodError and just returns nil instead.


ActiveRecord and accessors:

In a plain old ruby class you would add accessors to make the instance variable @admin available:

class User
  def initialize
    @admin = true
  end

  attr_accessor :admin
end

Which does this:

class User
  def initialize
    @admin = true
  end

  # getter
  def admin
    @admin
  end

  # setter
  def admin=(val)
    @admin = val
  end
end

ActiveRecord reads the schema from your database and uses metaprograming to auto-magically add accessors to your model classes. They are a bit more complex than the example above but its the same basic principle. Thats why your User model responds to #admin .

There is probably no functional difference, in this case.

I'm guessing admin is a boolean field in the users database table. So, user.admin will return either true or false -- no surprises here!

For each column in the table, Rails will also automatically generate an associated method prepended with an ? . For example, if you have a column foo , then there will be a method foo? - which will return true or false depending on the value of foo .

For example, if current_user.name == "Tom" then current_user.name? == true current_user.name? == true . And if current_user.name == nil , then current_user.name? == false current_user.name? == false .

It's very rarely necessary to use the ? methods in your code, since all objects are either "truthy" or "falsey" in ruby anyway. But it can sometimes be useful to show intent, and makes the code easier to read, as it's clear that the value is only being used in a boolean manner.

By default, rails ActiveRecord object attributes that are boolean can either be called with or without a question mark (?).

By convention, it is easier to read if you add the ? , and that also shows that it is boolean at first glance.

So, reading this gives the impression that you are asking a question in English.

Therefore, my guess is that admin is a boolean field on the user.

Also, Tom above is very correct.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM