这是我第一次尝试从API获取数据,并将数据输出到视图。
我想在搜索表单中输入一个ISBN编号,并使用http://isbndb.com/.这就是我目前所拥有的:
控制器:
require 'open-uri'
class BookController < ApplicationController
def searchbook
resp = open("http://isbndb.com/api/books.xml?access_key=#{'API KEY HERE'}&results=texts&index1=isbn&value1=#{params[:isbn]}")
doc = Nokogiri.XML(resp.read)
# ... process response here
end
end
形式:
<%= form_tag({:controller => 'book', :action => 'searchbook'}, {:method => 'get'}) do |select| %>
<%= label_tag :isbn, "Enter ISBN Number" %>
<%= text_field_tag :isbn, params[:isbn] %>
<%= submit_tag "Search" %>
<% end %>
要返回的XML
<?xml version="1.0" encoding="UTF-8"?>
<ISBNdb server_time="2005-07-29T03:02:22">
<BookList total_results="1" page_size="10" page_number="1" shown_results="1">
<BookData book_id="paul_laurence_dunbar" isbn="0766013502">
<Title>Paul Laurence Dunbar</Title>
<TitleLong>Paul Laurence Dunbar: portrait of a poet</TitleLong>
<AuthorsText>Catherine Reef</AuthorsText>
<PublisherText publisher_id="enslow_publishers">Berkeley Heights, NJ: Enslow Publishers, c2000.</PublisherText>
<Summary>A biography of the poet who faced racism and devoted himself to depicting the black experience in America.</Summary>
<Notes>"Works by Paul Laurence Dunbar": p. 113-114. Includes bibliographical references (p. 124) and index.</Notes>
<UrlsText></UrlsText>
<AwardsText></AwardsText>
</BookData>
</BookList>
</ISBNdb>
我如何处理XML请求,或者我可以阅读什么来了解如何处理?
在哪里可以查看控制台中返回的数据(如果有的话)?我甚至还不确定这是否有任何作用,但在我的表格中点击"搜索"后,我就进入了搜索簿操作,目前这是一个空白页面。
我可能离完整的答案还有很长的路要走,但这是我第一次这样做。
解析XML很容易:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="UTF-8"?>
<ISBNdb server_time="2005-07-29T03:02:22">
<BookList total_results="1" page_size="10" page_number="1" shown_results="1">
<BookData book_id="paul_laurence_dunbar" isbn="0766013502">
<Title>Paul Laurence Dunbar</Title>
<TitleLong>Paul Laurence Dunbar: portrait of a poet</TitleLong>
<AuthorsText>Catherine Reef</AuthorsText>
<PublisherText publisher_id="enslow_publishers">Berkeley Heights, NJ: Enslow Publishers, c2000.</PublisherText>
<Summary>A biography of the poet who faced racism and devoted himself to depicting the black experience in America.</Summary>
<Notes>"Works by Paul Laurence Dunbar": p. 113-114. Includes bibliographical references (p. 124) and index.</Notes>
<UrlsText></UrlsText>
<AwardsText></AwardsText>
</BookData>
</BookList>
</ISBNdb>
EOT
isbn_data = doc.search('BookData').map{ |book_data|
hash = {}
%w[ book_id isbn ].each do |p|
hash[p.downcase.to_sym] = book_data[p]
end
%w[ Title TitleLong AuthorsText PublisherText Summary ].each do |t|
hash[t.downcase.to_sym] = book_data.at(t).text
end
hash
}
pp isbn_data
哪个输出:
[{:book_id=>"paul_laurence_dunbar",:isbn=>"0766013502",:title=>"Paul Laurence Dunbar",:titlelong=>"保罗·劳伦斯·邓巴:诗人肖像",:authorstext=>"凯瑟琳礁",:publishertext=>"伯克利高地,新泽西州:恩斯洛出版社,c2000。",:summary=>"一本诗人的传记,他面对种族主义,致力于描绘美国的黑人经历。"}]
此代码基于您可能收到多个<BookData>
块的想法,因此它返回了一系列哈希。如果你只有一个用途:
hash = {}
book_data = doc.at('BookData')
%w[ book_id isbn ].each do |p|
hash[p.downcase.to_sym] = book_data[p]
end
%w[ Title TitleLong AuthorsText PublisherText Summary ].each do |t|
hash[t.downcase.to_sym] = book_data.at(t).text
end
pp hash
现在的输出看起来像:
{:book_id=>"paul_laurence_dunbar",:isbn=>"0766013502",:title=>"Paul Laurence Dunbar",:titlelong=>"保罗·劳伦斯·邓巴:诗人肖像",:authorstext=>"凯瑟琳礁",:publishertext=>"伯克利高地,新泽西州:恩斯洛出版社,c2000。",:summary=>"一本面对种族主义并致力于描绘美国黑人经历的诗人传记。">我强烈建议通过将与ISBNdb相关的代码移动到其自己的模型来简化控制器。一个很好的方法是通过HTTParty:
class ISBNdb include HTTParty base_uri "http://isbndb.com/api" @key = "API_KEY_HERE" def self.get_book(isbn) params = {'value1' => isbn, 'results' => 'texts', 'index1' => 'isbn', 'access_key' => @key} get('/books.xml', :query => params)['ISBNdb']['BookList']['BookData'] end end
然后,在你的控制器中,你可以这样使用它:
book = ISBNdb.get_book('1934356166') puts book['Title'] #=> "Agile Web Development with Rails"
正如您所看到的,HTTParty为您解析响应,因此您可以像散列一样访问它。
此解决方案使您的控制器保持简单,并且如果您需要其他功能,还提供了一个方便的位置来添加其他API调用的方法。这就是实践中的单一责任原则。
当您正在寻找正确方向的基本指向时,以下是我认识的几个点。
1) 对于通过HTTP获取任何源,通常使用HTTP客户端gem。我可以推荐Excon和被低估的HTTP客户端gem,尽管你会在Ruby工具箱中找到更多的选项。
2) 为了深入了解API响应,您可以例如引发一个输出结果的异常。我从RailsCast中学到了这项技术。
# Example with Curb http = Curl.get("http://www.google.com/") body = http.body_str # Raise an exception displaying the value you want to see raise body.inspect # or in nicely structured yaml format raise body.to_yaml
你可以在任何地方使用这种技术,对我来说,当你想查看刚刚发送给某个控制器动作的参数时,它会派上用场。
甚至可以通过最近的better_errorsgem来与返回值交互(例如,尝试一些方法调用)。它附带了一个控制台,您可以随时通过浏览器与当前环境进行交互。