【问题标题】:Method not returning variables in Ruby model方法不返回 Ruby 模型中的变量
【发布时间】:2018-02-25 01:55:25
【问题描述】:

我正在尝试使用 Vacuum gem (v. 2.0.2) 从亚马逊请求信息。但是,我不确定我应该如何返回我得到的结果。目前,我已经为我的方法制作了这段代码:

def self.isbn_lookup(val)
  request = Vacuum.new('US')
  request.configure(
  aws_access_key_id: 'access_key_goes_here',
  aws_secret_access_key: 'secret_key_goes_here',
  associate_tag: 'associate_tag_goes_here'
  )
  response = request.item_lookup(
    query: {
      'ItemId' => val,
      'SearchIndex' => 'Books',
      'IdType' => 'ISBN'
    },
    persistent: true
  )
  fr = response.to_h #returns complete hash
  if fr["ItemLookupResponse"]["Items"]["Item"]["ItemAttributes"]["Author"]
    @author = fr.dig("ItemLookupResponse","Items","Item","ItemAttributes","Author")
  end
  if fr["ItemLookupResponse"]["Items"]["Item"]["ItemAttributes"]["Author"]
    @title = fr.dig("ItemLookupResponse","Items","Item","ItemAttributes","Title")
  end
  if fr["ItemLookupResponse"]["Items"]["Item"]["ItemAttributes"]["Manufacturer"]
    @manufacturer = fr.dig("ItemLookupResponse","Items","Item","ItemAttributes","Manufacturer")
  end
  if fr["ItemLookupResponse"]["Items"]["Item"]["ItemAttributes"][6]["URL"]
    @url = fr.dig("ItemLookupResponse","Items","Item","ItemLinks","ItemLink",6,"URL")
  end
end

我想调用能够在我的控制器中使用此方法中创建的变量。如何访问控制器中的作者、标题、制造商和 url 实例变量?我想这样当用户输入他们的 ISBN 时,它会向服务器发送一个 AJAX 请求以请求相关信息(作者、标题等)。目前,这是我的控制器的样子:

def create
    @listing = Listing.new(listing_params)
    @listing.user = current_user
   if @listing.save
     flash[:success] = "Your listing was successfully saved."
     redirect_to listing_path(@listing)
   else
     render 'new'
   end
end    
def edit
  @isbn = Listing.isbn_lookup(1285741552)
end

【问题讨论】:

  • 您的实例变量永远不会被设置。你看到return fr这行了吗?该行之后的所有内容都不会执行。
  • 好的。我已经更新了代码。
  • 但是我如何才能返回所有我发现存在的变量呢?然后如何在我的控制器中实现它?

标签: ruby-on-rails ruby scope


【解决方案1】:

一个快速的解决方法是让该方法将值作为 PORO(普通的旧 ruby​​ 对象)返回,然后将它们分配给控制器中的实例变量。在isbn_lookup方法的最后,放上:

return {title: title, author: author, manufacturer: manufacturer, url: url}

不要在isbn_lookup 方法中使用实例变量——它们不会按照您希望的方式工作。您可能需要进一步了解 Ruby 类的工作原理才能理解这一点。但总而言之,您的控制器方法在控制器的 instance 中运行(为每个请求创建一个实例),而您的 isbn_lookup 被编写为 类方法,所以实例变量在那里没有真正意义。请参阅Using Instance Variables in Class Methods - Ruby 了解更多说明。

如果您觉得像这样列出所有键很难看,您可以逐步构建对象,例如在方法的开头放isbn = {},然后做isbn[:author] = fr.dig(...)之类的东西,最后return isbn

在控制器方法中:

@isbn = Listing.isbn_lookup(1285741552)
@title = @isbn[:title]
@manufacturer= @isbn[:manufacturer]
@author = @isbn[:author]
@title = @isbn[:title]

@title@manufacturer 等实例变量的设置有点不必要,因为您可以在视图中使用 @isbn[:author]


回答您的后续问题:

这里很奇怪:

if fr["ItemLookupResponse"]["Items"]["Item"]["ItemAttributes"][6]["URL"]
    @url = fr.dig("ItemLookupResponse","Items","Item","ItemLinks","ItemLink",6,"URL")
end

我不确定您是否了解 dig 的工作原理。这是一种挖掘嵌套对象的安全方法。如果在参数中找到的键项不存在,它将返回nil。例如{}.dig(:a, :b, 1, 2, :etc) == nil。所以你可以这样做:

url = fr.dig("ItemLookupResponse","Items","Item","ItemLinks","ItemLink",6,"URL")
if url
  # etc

甚至使用内联赋值:

if url = fr.dig("ItemLookupResponse","Items","Item","ItemLinks","ItemLink",6,"URL")
  # etc

虽然您可能会收到来自 Ruby 的警告,本质上是说“您的意思是 ==?” (你没有)。

我认为您在这里并不需要条件句。例如,即使 url 为 nil,您仍然可以让该方法返回带有 :url 键的哈希(恰好有一个 nil 值)。然后,无论您实际上需要知道该 url 是否存在(例如,出于演示目的的视图),您都可以使用if @isbn[:url]

【讨论】:

  • 好的,由于某种原因,当我使用它时,我收到错误:“未定义的方法 `[]' for nil:NilClass。”我认为这可能是我将元素引用为 url 变量的数字 [6] 的方式。有什么简单的方法可以避免这个错误?
猜你喜欢
  • 2018-03-15
  • 2012-05-17
  • 1970-01-01
  • 2019-06-17
  • 2012-09-22
  • 1970-01-01
  • 1970-01-01
  • 2015-12-16
  • 1970-01-01
相关资源
最近更新 更多