Rails: External API Integration using RestClient (

2020-05-04 17:51发布

问题:

I am building a digital library, and I have completed a lot of the functionalities needed. I am currently having an issue with integrating the digital library with a Learning Management System (LMS).

I already have an admin authentication system for the digital library using the Devise gem. My goal is to allow users who want to access the digital library to login to the digital library using their Learning Management System (LMS) credentials (username and password).

I have been provided with the Login API endpoint and other needed parameters of the Learning Management System (LMS), and I have created the User Model, the Sessions Controller and the Sessions View Templates.

I am currently using the RestClient Gem for the API call, and I just want to save the login information after succesful API call to the session[:user_id] = user.id, but I having an error undefined local variable or method `user' for #SessionsController. I can't figure out went wrong.

Below is my source code

Sessions Controller

require 'rest-client'

class SessionsController < ApplicationController
  def new
  end

  def create
    response = RestClient::Request.execute(
      method: :post,
      url: 'https://newapi.example.com/token',
      payload: { 'username': params[:username],
                 'password': params[:password],
                 'grant_type':'password' },
      headers: { apiCode: '93de0db8-333b-4f478-aa92-2b43cdb7aa9f' }
    )

    case response.code
    when 400
      flash.now[:alert] = 'Email or password is invalid'
      render 'new'
    when 200
      session[:user_id] = user.id
      redirect_to root_url, notice: 'Logged in!'
    else
      raise "Invalid response #{response.to_str} received."
    end
  end

  def destroy
    session[:user_id] = nil
    redirect_to root_url, notice: 'Logged out!'
  end
end

Sessions New View

<p id=”alert”><%= alert %></p>
<h1>Login</h1>
<%= form_tag sessions_path do %>
  <div class="field">
    <%= label_tag :username %>
    <%= text_field_tag :username %>
  </div>
  <div class="field">
    <%= label_tag :password %>
    <%= password_field_tag :password %>
  </div>
  <div class="actions">
    <%= submit_tag 'Login' %>
  </div>
<% end %>

User Model

class User < ApplicationRecord
  has_secure_password

  validates :username, presence: true, uniqueness: true
end

Any form of help with code samples will be greatly appreciated. I am also open to providing more information about this integration if required. Thank you in advance.

回答1:

In your sessions controller, the line session[:user_id] = user.id, user is undefined i.e. You never assigned a value to the user variable.

Assuming your User database(in digital library, not LMS) have the record of user currently logging in, then you should use something like this:

when 200
  session[:user_id] = response.body.data.user.id
  redirect_to root_url, notice: 'Logged in!'

Now another case, When the user signs up in your LMS, then when he visits digital library app, and tries to login, he won't be able to. Because your digital library app doesn't have the user linked with LMS or knows anything about LMS. So, whenever user creates a session, you'll need to check if User record is present in your digital library DB or not, if not create one. You can do something like this:

when 200
  if User.find(response.body.data.user.id).present?
    session[:user_id] = response.body.data.user.id
    redirect_to root_url, notice: 'Logged in!'
  else
    user = User.create(id: response.body.data.user.id, username: response.body.data.user.username, passord: params[:password], password_confirmation: params[:password])
    session[:user_id] = response.body.data.user.id
    redirect_to root_url, notice: 'Logged in!'
  end

The above method is just for reference, you must add more validations if required.