SNS 로그인 구현 예제

이 글에서는 Rails 환경에서 SNS 로그인을 구현하는 방법을 예제 코드와 함께 자세히 안내해 드립니다.

class User < ApplicationRecord

  # Include default devise modules. Others available are:

  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable

  devise :database_authenticatable, :registerable,

         :recoverable, :trackable, :rememberable, :validatable, :omniauthable



  validates :name, presence: true, :length => { :maximum => 7 }



  # SNS 로그인

  has_one :identity, dependent: :destroy



  # 번개

  has_many :events, dependent: :destroy



  # 번개 참가신청

  has_many :user_events, dependent: :destroy



  # 댓글

  has_many :comments, dependent: :destroy



  # 댓글 좋아요

  has_many :likes, dependent: :destroy



  # 알림

  has_many :notifications, dependent: :destroy



  # 팔로우

  has_many :follower_relations, foreign_key: "followed_id", class_name: "Follow"

  has_many :followers, through: :follower_relations, source: :follower, dependent: :destroy

  has_many :following_relations, foreign_key: "follower_id", class_name: "Follow"

  has_many :followings, through: :following_relations, source: :followed, dependent: :destroy



  # 메시지

  has_many :messages, dependent: :destroy



  # 신고

  has_many :report, dependent: :destroy



  # sms

  has_many :sms_messages



  before_save :set_location



  mount_uploader :image, UserUploader



  acts_as_mappable :default_units => :kms,

                   :default_formula => :sphere,

                   :distance_field_name => :distance,

                   :lat_column_name => :lat,

                   :lng_column_name => :lng



  enum grade: [:normal, :admin]

  enum gender: [:not_choose, :man, :woman]





  def self.find_for_oauth(auth, signed_in_resource = nil)

    identity = Identity.find_for_oauth(auth)

    user = signed_in_resource ? signed_in_resource : identity.user



    if user.nil?

      auth_email = auth.info.email

      user = User.where(email: auth_email).first

      unless user.present?

        if auth.info.email.nil?

          if auth.provider == "kakao"

            user = User.new(

                email: "kakaoUser@#{auth.uid}.com",

                remote_image_url: auth.info.image,

                name: auth.info.name,

                password: Devise.friendly_token[0,20]

              )

          elsif auth.provider == "facebook"

            user = User.new(

                email: "facebookUser@#{auth.uid}.com",

                remote_image_url: auth.info.image,

                name: auth.info.name,

                password: Devise.friendly_token[0,20]

              )

          end

        else

          user = User.new(

              email: auth.info.email,

              remote_image_url: auth.info.image,

              name: auth.info.name,

              password: Devise.friendly_token[0,20]

          )

        end

        # user.skip_confirmation! # 이메일 인증이 있는 경우 인증을 자동 완료해줌

        user.save!

      end

    end



    if identity.user != user

      identity.user = user

      identity.save

    end



    user #user 리턴

  end



  def set_location

    if self.en_address.present?

      results = HTTParty.get("https://maps.googleapis.com/maps/api/place/textsearch/json?input=#{self.en_address}&inputtype=textquery&key=AIzaSyATof4VolMTPTEz78KgGKAOVAzlFzO3QmY")

      result_hash = JSON.parse(results.body)



      if result_hash["results"] == [] ## 검색결과가 비어있는 경우

        splited_num = self.en_address.split(',').size

        remade_adress = self.en_address.split(',')[1..splited_num].join



        results = HTTParty.get("https://maps.googleapis.com/maps/api/place/textsearch/json?input=#{remade_adress}&inputtype=textquery&key=AIzaSyATof4VolMTPTEz78KgGKAOVAzlFzO3QmY")

        result_hash = JSON.parse(results.body)



        unless result_hash["results"] == []

          self.lat = result_hash["results"][0]["geometry"]["location"]["lat"]

          self.lng = result_hash["results"][0]["geometry"]["location"]["lng"]

        end

      else

        self.lat = result_hash["results"][0]["geometry"]["location"]["lat"]

        self.lng = result_hash["results"][0]["geometry"]["location"]["lng"]

      end

    else

      self.lat = 0

      self.lng = 0

    end

  end



  def self.gender_options

    options = [['선택안함', "not_choose"], ['남자', "man"], ['여자', "woman"]]

    options.unshift(["성별을 선택해주세요.", -1])

    options

  end



  def is_apply(event)

    UserEvent.find_by(user: self, event: event, _type: "apply").present?

  end



  def is_keeping(event)

    UserEvent.find_by(user: self, event: event, _type: "keeping").present?

  end



  def is_follower(user)

    self.followings.include?(user)

  end



  def is_like(comment)

    Like.find_by(user: self, comment: comment).present?

  end



  def is_waiting(event)

    UserEvent.find_by(user: self, event: event, _type: "apply", _state: "waiting").present?

  end



  def is_accept(event)

    UserEvent.find_by(user: self, event: event, _type: "apply", _state: "accept").present?

  end



  def allow(event)

    user_event = UserEvent.find_by(user: self, event: event, _type: "apply", _state: "waiting")

    if user_event.present?

      user_event._state = "accept"

      user_event.save

    end

  end



  def unallow(event)

    user_event = UserEvent.find_by(user: self, event: event, _type: "apply", _state: "accept")

    if user_event.present?

      user_event._state = "waiting"

      user_event.save

    end

  end



  def rooms

    (Room.where(user1: self) + Room.where(user2: self)).sort_by(&:created_at).reverse

  end



  def not_read_messages

    Message.includes(:room).where.not(user: self).where(is_check: false, rooms: {user1: self}) + Message.includes(:room).where.not(user: self).where(is_check: false, rooms: {user2: self})

  end

end

 


이것도 읽어보세요