简体   繁体   中英

Method not returning variables in Ruby model

I am trying to request information from Amazon using the vacuum gem (v. 2.0.2). However, I am not sure how I am supposed to return the results I get. Currently, I have made this code for my method:

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

I would like to call be able to use the variables created in this method in my controller. How can I access the author, title, manufacturer, and url instance variables in my controller? I want to make it so that when users type in their ISBN, it will send an AJAX request to the server to request the relevant information (author, title, etc.). Currently, this is what my controller looks like:

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

A quick fix would be to make the method return the values as a PORO (plain old ruby object) and then assign them to instance variables from the controller. At the end of the isbn_lookup method, put this:

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

Don't use instance variables in the isbn_lookup method - they don't work the way you want them to do there. You'd maybe need to do a little more learning about how Ruby classes work to understand this. But to summarize, your controller methods run in an instance of the controller (one instance is created for each request), whereas your isbn_lookup is written as a class method , so instance variables don't really make sense there. See Using Instance Variables in Class Methods - Ruby for more explanation about this.

If you feel it is ugly to list out all the keys like this you could build the object incrementally, eg at the beginning of the method put isbn = {} , then do stuff like isbn[:author] = fr.dig(...) and at the end return isbn

and in the controller method:

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

The setting of the @title , @manufacturer , etc. instance variables is kind of unnecessary because you could just use @isbn[:author] from the view.


in response to your follow up question:

this right here is odd:

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

I'm not sure you understand how dig works. It is a safe way to dig into a nested object. If the items at the keys found in the arguments don't exist, it will return nil . eg {}.dig(:a, :b, 1, 2, :etc) == nil . So you could just do this:

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

or even making use of inline assignment:

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

although you may get a warning from Ruby essentially saying "did you mean ==?" (which you didn't).

I don't see you really having a need for conditionals here. For example even if the url is nil you can still have the method return a hash with a :url key (that happens to have a nil value). Then wherever you actually need to know whether or not the url exists (eg the view, for presentational purposes), you can do if @isbn[:url]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM