簡體   English   中英

使用 Ruby Controller 讀取 Instagram JSON 並傳遞給 View,使用 HTTParty gem

[英]Reading Instagram JSON with Ruby Controller and passing to View, using HTTParty gem

我正在嘗試學習用 Ruby 處理 JSON。 我經歷了很多教程,但更加困惑,所以我嘗試通過這樣做來學習。

在這里,我試圖從 Instagram 獲取用戶數據並顯示在我的視圖中。 我可以訪問下面的 JSON,但如何訪問某些字段和用戶名或循環帖子?

# users_controller.rb
require 'httparty'

class UsersController < ApplicationController
    include HTTParty

    def show
        @user = User.find(params[:id])
        fetch_instagram("elonofficiall")
    end

    private
    def fetch_instagram(instagram_username)
        url = "https://www.instagram.com/#{instagram_username}/?__a=1"
        @data = HTTParty.get(url)
        return @data
    end
end

# show.html.erb
# the code below is just to try if I get anything
<%= @data %>
<% @data.each do |data| %>
  <p><%= data %></p>
<% end %>

https://www.instagram.com/elonofficiall/?__a=1

在此處輸入圖片說明

首先不要直接從控制器進行 HTTP 調用。

而是創建一個與 instagram API“對話”的單獨類:

# app/clients/instagram_client.rb
class InstagramClient
  include HTTParty
  base_uri 'https://www.instagram.com'
  format :json

  def initialize(**options)
    @options = options
  end

  def user(username, **opts)
    options = @options.reverse_merge(
      '__a' => 1 # wtf is this param?
    ).reverse_merge(opts)

    response = self.class.get("/#{username}", options)
    if response.success?
      extract_user(response)
    else
      Rails.logger.error("Fetching Instagram feed failed: HTTP #{response.code}")
      nil
    end
  end

  private 
  def extract_user(json)
    attributes = response.dig('graphql', 'user')&.slice('id', 'biography')
    attributes ? InstagramUser.new(attributes) : nil
  end
end

還有一個類,用於規范應用程序中使用的 API 響應:

# app/models/instagram_user.rb
class InstagramUser
  include ActiveModel::Model
  include ActiveModel::Attributes
  attribute :id
  attribute :biography
  attribute :username
  # etc
end

這只是一個沒有保留在數據庫中的直接 Rails 模型。 ActiveModel::ModelActiveModel::Attributes使您可以像使用 ActiveRecord 支持的模型一樣傳遞用於批量分配的屬性散列。

這為您提供了一個對象,您可以通過以下方式簡單地進行測試:

InstagramClient.new.feed('elonofficiall')

你可以像這樣將它集成到你的控制器中:

class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    fetch_instagram(@user.instagram_username)
  end

  private
  def fetch_instagram(instagram_username)
    @instagram_user = InstagramClient.new.user(@user.instagram_username)
  end
end

HTTParty混合到您的控制器中是一個直接的壞主意,因為控制器很難測試,並且控制器已經負責響應客戶端請求並且不需要更多。

在您的視圖中處理“原始”JSON 響應也不是一個很好的做法,因為它在外部 API 和您的應用程序之間創建了一個硬耦合,並大大增加了您的視圖的復雜性。 首先在單獨的對象中規范化數據。

<% if @instagram_user %>
  <p><%= @instagram_user.username %></p>
<% end %>

如果您想真正從用戶的 Instagram 提要中獲取媒體項目,您需要發出另一個 HTTP 請求來GET https://graph.facebook.com/{ig-user-id}/media 請參閱官方 API 文檔

最好先把它從Rails取出。 那只會使事情復雜化。 許多開發人員回復Rails === Ruby 它不是。

編寫一個簡單的 ruby​​ 腳本並對其進行測試:

rec = HTTParty.get(url)
puts rec.headers                    # content-type is 'text/html' and should be 'application/json'
res = rec.parsed_response           # getting error
puts res.class

Instagram 的問題在於,我認為它迫使用戶返回一個糟糕的content-header 它可能是一個安全層。 我似乎也無法將回復強制轉換為jsonhash 所以這就是httparty不適合我的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM