2017-09-11 3 views
0

레일스에서 ​​HTTParty gem을 사용하여 API 호출을 작성했지만 성공했습니다. 그러나 컨트롤러에서 변수를 정의한 후에 아무런 오류가 발생하지 않아 루프를 생성 할 수 없습니다.보기에서 올바르게 표시하기 위해 레일스에서 ​​API 호출 문제 (HTTParty 사용)

< % = @variable %>를 입력하면 예상 한 Active Record 개체 만 표시됩니다. 내가 똑같이하지만 variable.name을 포함하면 문자열을 제공하지만 정확히 원하는 것은 아닙니다. 나는 몇 가지 HTTParty 튜토리얼을 따라 API 연구를 많이 해왔다. 그러나 나는 이것을 알아낼 수 없다. 외부 API에서 간식 목록을 검색하려고합니다. 여기에 내가 가진 것이 있습니다 (내 견해에있는 것들 중 일부는 테스트하는 것입니다).

API 호출 (나는 별도의 폴더 서비스에 넣어) :

class SnackAPI 
    include HTTParty 
    base_uri 'https://api-snacks.nerderylabs.com/v1/' 
    SNACK_ACCESS = "/snacks?ApiKey=#{ENV['SNACK_API_KEY']}" 

    def get_snacks 
    response = self.class.get(SNACK_ACCESS) 
    JSON.parse(response.body) 
    end 
end 

처음 게시 코드가 적절한 들여 쓰기에 게시하는 방법을 확신하지 니펫하지만 내 응용 프로그램에 올바른 것입니다.

컨트롤러 :

class SnacksController < ApplicationController 
    def index 
    @snacks = Snack.all 
    @permanent_snacks = Snack.where(optional: false) 
    @optional_snacks = Snack.where(optional: true) 
    end 
end 

모델 : 간식 폴더에

class Snack < ApplicationRecord 
    validates :name, presence: true 
    validates_uniqueness_of :name 
end 

보기 (index.html.erb) :보기

<h1> Welcome to SnaFoo! </h1> 

<!-- I am attempting to get these loops to display each snack item included in the API but nothing appears --> 

<% @permanent_snacks.each do |snack| %> 
    <%= snack.name %> 
<% end %> 

<% @optional_snacks.each do |snack| %> 
    <%= snack.name %> 
<% end %> 

<%= @snacks %> 
<%= @optional_snacks %> 
<%= @permanent_snacks %> 

<br /> 

Snack with name paramater (to test): 

<%= @snacks.name %> 

<!-- So it recognizes the fields and datatypes --> 

결과 : 객체 자체 (대한 각 하나.이 API를 테스트했다 그냥 정보를 검색했다.) < % = @ snacks.name % > Snack을 출력하여 적어도 스키마의 필자 필드와 데이터 유형을 인식합니다. 주요 문제는 루프를 작동시켜 API의 각 간식을 표시하는 것입니다.

본인 혼자서이 문제를 해결하기 위해 노력했지만 시간이 많이 걸렸습니다. 올바른 방향으로 나를 가리킬 수있는 도움을 주시면 감사하겠습니다.

이 문제를 해결하기 위해 스키마가 필요/도움이된다면 게시 할 수도 있습니다.

터미널 출력 I 페이지 (우분투 일반적으로 코드를로드하지만 때문에 내 파티션 몇 가지 문제에 Windows에서이 코딩하고 때

는 GET 시작 "/"10.0.2.2에 대한 2017년 9월 11일에서 21:49:49 +0000 콘솔을 10.0.2.2에서 렌더링 할 수 없음 허용 된 네트워크 : 127.0.0.1, :: 1, 127.0.0.0/127.255.255.255 SnacksController # index에서 HTML 렌더링 처리 snacks/index.html.erb 레이아웃/응용 프로그램 내 스낵 스누킹 부하 * (0.5ms) 스낵로드 "옵션"= $ 1 [[ ""옵션 ","f "] 스낵로드 선택 "간식". * FROM "간식"WH "옵션"= $ 1 내의 레이아웃/스낵/index.html.erb 레이아웃/응용 프로그램 (3.5ms) 401ms에서 200 초 완료 (조회수 : 374.1ms ) | 액티브 : 0.8ms) 클라이언트를 고정하여

답변

0

시작 :

# place this in /lib or app/clients as it is not a service object. 
# app/clients/snack_api.rb 
class SnackAPI 
    include HTTParty 
    base_uri 'https://api-snacks.nerderylabs.com/v1/' 
    format :json 

    def initialize(*opts) 
    @options = opts.reverse_merge({ 
     ApiKey: ENV['SNACK_API_KEY'] 
    }) 
    end 
    def get_snacks 
    response = self.class.get('/snacks', @options) 
    end 
end 

사용 format :json 대신하는 대신 수동으로 JSON 응답을 구문 분석. 이는 API 오류가 발생하여 빈 응답 JSON을 반환하기 때문에 매우 중요합니다.

: API를 소비

class SnacksController < ApplicationController 
    def index 
    response = SnackAPI.get_snacks 

    if response.success? 
     @snacks = response[:snacks] 
    else 
     flash.now[:error] = "Could not fetch snacks" 
     @snacks = [] 
    end 
    end 
end 

그렇지 않으면 서비스 개체를 만들 : 당신은 당신이 모델을 필요로하지 않는 API에서 바로 기사를 표시하려면

irb(main):002:0> JSON.parse('') 
JSON::ParserError: 745: unexpected token at '' 

: 불면을 구문 분석

# app/services/snack_import_service 
class SnackImportService 

    attr_accessor :client 

    def intialize(client = nil, **opts) 
    # this is a trick that lets you inject a spy or double in tests 
    @client = client || SnackAPI.new(opts) 
    end 

    def perform 
    response = client.get_snacks 
    # Remember that HTTP requests can and will fail 
    if response.success? 
     response[:snacks].map do |data| 
     Snack.find_or_create_by!(name: data[:name]) 
     end 
    else 
     Rails.logger.error "SnackAPI request was unsuccessful #{response.code}" 
    end 
    end 
end 

이것을 클라이언트와 별도의 서비스 객체로 사용하는 것은 단일 책임 원칙을 준수하고 클라이언트를 재사용 가능한 구성 요소로 뽑아 낼 수있는 좋은 아이디어입니다. 응용 프로그램 논리와 별개입니다.

class SnacksController < ApplicationController 
    def index 
    @snacks = SnackImportService.new.perform 
    @permanent_snacks = Snack.where(optional: false) 
    @optional_snacks = Snack.where(optional: true) 
    end 
end 
+0

모든 정보를 제공해 주셔서 감사합니다. reverse_merge 방법에 대한 한 가지 질문입니다. 이 사건에서 일반적으로 정확히 무엇이 이루어지는 지에 대한 세부 사항을 찾을 수 없었습니다. 클라이언트에서 무엇을하고 있는지 설명해 주시겠습니까? –

+0

또한 명확하게하기 위해 API 호출을 클라이언트 또는 lib에 넣거나 서비스로 만듭니다. 아니면 둘 다합니까? 그냥 궁금해서 SnackImportService에서 전화를받지 못합니다. 다시 한번 고마워요. 나는 답변과 가이드를위한 나의 모든 탐구에서 이렇게 된 것을 보지 못했습니다. 나는 그것을 즉시 시험 할 것이다 –

+0

나의 마음을 미끄러 뜨린 코멘트를 스패밍하는 것을 유감스럽게 생각하는 한 가지. 이 방법으로 API 호출을 구현하면 스낵을 표시하는 루프가 올바르게 작동해야합니까? –