我正在尝试学习使用 Ruby 处理 JSON。我浏览了很多教程,但更加困惑,所以我尝试边做边学。
在这里,我尝试从 Instagram 获取用户数据并显示在我的 View 中。我可以访问下面的 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 %>
最佳答案
首先不要直接从 Controller 进行 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::Model
和 ActiveModel::Attributes
让您可以传递属性的哈希值以进行批量分配,就像使用 ActiveRecord 支持的模型一样。
这为您提供了一个可以简单测试的对象:
InstagramClient.new.feed('elonofficiall')
您可以将其集成到您的 Controller 中,如下所示:
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
混合到 Controller 中是一个彻头彻尾的坏主意,因为 Controller 很难测试,而且 Controller 已经负责响应客户端请求,不需要更多。
在您的 View 中处理“原始”JSON 响应也不是一个好的做法,因为它会在外部 API 和您的应用程序之间创建硬耦合,并大大增加您的 View 的复杂性。首先在单独的对象中标准化数据。
<% if @instagram_user %>
<p><%= @instagram_user.username %></p>
<% end %>
如果您想实际从用户的 Instagram Feed 获取媒体项目,您需要向 GET https://graph.facebook.com/{ig-user-id}/media 发出另一个 HTTP 请求
.请参阅official API documentation .
关于ruby-on-rails - 使用 Ruby Controller 读取 Instagram JSON 并使用 HTTParty gem 传递到 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63820669/