Why does single `=` work in `if` statement?

后端 未结 4 1192
囚心锁ツ
囚心锁ツ 2021-01-18 02:28

This code is provided as an example in for use with devise and OmniAuth, it works in my project.

class User < ActiveRecord::Base
  def self.new_with_sessi         


        
相关标签:
4条回答
  • 2021-01-18 03:09

    Ruby doesn't care about types in conditionals, unlike Java. As long as the value is neither nil or false then it will pass.

    In your example you actually discriminate against nil: the if conditionnal ensures that data actually exists and isn't nil, so we can use it, assuming it's a hash. This is a common pattern in Ruby.

    0 讨论(0)
  • 2021-01-18 03:13

    The only necessary thing for an if statement to be valid is a boolean expression. In this case, since = returns the result of the assignment, what's actually being tested is the falsiness of session["devise.facebook_data"].

    IntelliJ has a good point to lodge a complaint about code like this, as it's difficult to read without knowing a thing or two about Ruby. A recommendation would be to move that to an explicit assignment statement instead. This has the added benefit of DRYing up a reference to it twice.

    class User < ActiveRecord::Base
      def self.new_with_session(params, session)
        super.tap do |user|
          data = session["devise.facebook_data"]
          if data && data["extra"]["raw_info"]
            user.email = data["email"] if user.email.blank?
          end
        end
      end
    end
    
    0 讨论(0)
  • 2021-01-18 03:23

    In Ruby, a single equals sign is used for assignment. The expression

    data = session["devise.facebook_data"]
    

    assigns the result of evaluating session["devise.facebook_data"] to a local variable named data.

    If the session hash doesn't have a "devise.facebook_data" key, it will return nil and data will be assigned nil. Assignments evaluate to the value being assigned, so the assignment will evaluate to nil as well. nil is considered falsey in a boolean context, so the right operand of the && will not be evaluated. That way, you won't get a NoMethodError trying to call nil["extra"]["raw_info"].

    If the session hash does have a "devise.facebook_data" key, data will be set to the value associated with it. Any value other than nil and false is considered truthy, therefore the right-hand operand of the && operator will be evaluated.

    If the condition is truthy, the then clause will be evaluated, which uses the data variable assigned in the condition.


    Note: I believe one could also use the data variable within the right-hand side of the && operator, i.e. the condition could read like this instead:

    if data = session["devise.facebook_data"] && data["extra"]["raw_info"]
    

    But I'll have to check that.

    0 讨论(0)
  • 2021-01-18 03:29

    A assignment operator (=) returns the assigned value, which is then evaluated by the if. In ruby, only false and nil are considered as false. Everything else evaluates to true in a boolean context (like an if).

    0 讨论(0)
提交回复
热议问题