62

Possible Duplicate:
What does the operator ||= stands for in ruby?

I am confused with the usage of ||= operator in Rails. I couldn't locate anything useful on the web. Can anyone please guide me?

Do let me know if there are any weblinks that you are aware of.

I would like what the following statement means:

@_current_user ||= session[:current_user_id] &&
      User.find(session[:current_user_id])
Community
  • 1
  • 1
geeky_monster
  • 8,672
  • 18
  • 55
  • 86

4 Answers4

109

Lets break it down:

@_current_user ||= {SOMETHING}

This is saying, set @_current_user to {SOMETHING} if it is nil, false, or undefined. Otherwise set it to @_current_user, or in other words, do nothing. An expanded form:

@_current_user || @_current_user = {SOMETHING}

Ok, now onto the right side.

session[:current_user_id] &&
      User.find(session[:current_user_id])

You usually see && with boolean only values, however in Ruby you don't have to do that. The trick here is that if session[:current_user_id] is not nil, and User.find(session[:current_user_id]) is not nil, the expression will evaluate to User.find(session[:current_user_id]) otherwise nil.

So putting it all together in pseudo code:

if defined? @_current_user && @_current_user
  @_current_user = @_current_user
else
  if session[:current_user_id] && User.find(session[:current_user_id])
    @_current_user = User.find(session[:current_user_id])
  else
    @_current_user = nil
  end
end
t-mart
  • 890
  • 11
  • 27
Mike Lewis
  • 63,433
  • 20
  • 141
  • 111
  • Thanks Mike. This makes it very clear. – geeky_monster Apr 17 '11 at 04:30
  • Glad I could help @mad.geek. Good Luck :) Remember, if you feel as though this answered your question properly, make sure you mark it as correct. – Mike Lewis Apr 17 '11 at 04:36
  • 11
    To be pedantic, `a ||= b` is actually equivalent to `a || a = b`. – Rein Henrichs Apr 17 '11 at 04:48
  • Watch out not to put this in rails after_initialize method if you are using boolean as data type for variable. Because if you try to set default value to true in after_initialize using variable ||= true it will set the variable almost always to true. I did this and lost 2 days to find error since I thought it will set value to true only if nil is value that variable has when object is entering into after_initialize. – gljivar Mar 27 '13 at 19:49
  • @ReinHenrichs Isn't it `a = a || b`? – Ilya Kogan Feb 07 '14 at 13:06
  • @IlyaKogan No. That is true for `+=`, `-=`, etc, but Ruby optimizes the boolean operators to `a || a = b`. To see this, add debug printing to, say, `Hash#[]=` and test when it's called. – Rein Henrichs Feb 07 '14 at 18:34
  • What is `a || a = b` supposed to mean? How can you have an expression on the left side of an assignment? – Angelos Makrygiorgos Feb 22 '17 at 13:40
  • Michael Hartl explains it very well here in Box 8.1: https://www.railstutorial.org/book/basic_login – MSC Jan 31 '19 at 06:21
18

This is caching abilities.

a ||= 1  # a assign to 1
a ||= 50 # a is already assigned, a will not be assigned again

puts a
#=> 1

this is useful when u load current user from DB, if this is loaded prior, statement will not try to evaluate right part of equation, which DRY, therefore u can consider it as caching operator.

REF: http://railscasts.com/episodes/1-caching-with-instance-variables

c2h2
  • 11,911
  • 13
  • 48
  • 60
12

First made popular in C, the binary operator shorthand, for example:

a += b      # and...
a ||= b

acts like:

a = a + b   # and ... note the short circuit difference ... 
a || a = b

The rearrangement for a more effective short circuit is a graceful way of dealing with a check for nil as it avoids the assignment altogether if it can. The assignment may have side effects. Just another example of seriously thoughtful design in Ruby.

See http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html for a more wordy explanation.

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
  • 2
    -1. This answer is not actually correct. `a ||= b` is NOT equivalent to `a = a || b`. See http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html or even the accepted answer. This is a common misconception. The accepted answer is actually the correct one. `a ||= b` is equivalent to `a || a = b`, i.e. if `a` is not *falsy* (`false` or `nil`), then set `a` to the value of `b`. – adino Feb 20 '17 at 07:58
  • ^^^ Classic case of [Muphry's law](https://en.wikipedia.org/wiki/Muphry's_law) there. I meant: if `a` **is falsy** (`false` or `nil`), then set `a` to the value of `b`. – adino Feb 20 '17 at 08:09
  • Good catch, and I've now learned about [Muphry's Law,](https://en.wikipedia.org/wiki/Muphry's_law) hehe. Answer fixed. – DigitalRoss May 13 '20 at 21:08
5

If you have C# experience, I believe it is similar ( but more of a Ruby-trick ) to the null-coalescing (??) operator in C#

int? y = x ?? -1

x is assigned to y if x is not null, otherwise the "default" value of -1 is used.

Similarly, ||= is called the T-square operator I believe.

a || = b

or

a || a = b

Coming to your statement

@_current_user ||= session[:current_user_id] &&
    User.find(session[:current_user_id])

Basically, it sees if @_current_user is nil or not. If it has some value, leave it alone ( the current user. ) Else, get the current user from the session using the user id. It first sees if the id is in the session, and then gets from the User.

Look at the blog below for more info on the "T-square" operator:

http://blogs.oracle.com/prashant/entry/the_ruby_t_square_operator

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
manojlds
  • 290,304
  • 63
  • 469
  • 417