简体   繁体   中英

Why is this ruby method not being defined in my class?

Here's the code:

module Dog
  class Breed < Animal::Base

    class << self
      def all
        get '/v1/breeds'
      end

      def find(hashed_id)
        get "/v1/breeds/#{breed_id}"
      end
    end

    def bark
      "woof"
    end
  end
end

And for the base:

module Dog
  class Base < ActiveRecord::Base
    include HTTParty

    base_uri 'https://api.dogs.com'
    format :json
    default_params api_password: ENV['ANIMAL_PASSWORD']
  end
end

module HTTParty
  module ClassMethods
    def get(path, options = {}, &block)
      response = perform_request(Net::HTTP::Get, path, options, &block)
      if response.is_a? Array
        methodize_array response
      elsif response.is_a? Hash
        new_ros response
      end
    end

    def methodize_array(response)
      array = []

      response.each do |res|
        array << new_ros(res)
      end

      array
    end

    private

    def new_ros(object)
      RecursiveOpenStruct.new(object, recurse_over_arrays: true)
    end
  end
end

This is a silly example, but it should work in theory. What happens is is that we grab some data from an API. When that data is grabbed, we discover that its a Hash. We don't like Hashes, so we reopen the get request within HTTParty and have it perform a recursive open struct to make it an object.

We perform this get as Dog::Breed.all . We receive an array that, thankfully to ROS, was converted to an object.

Now, when I call Dog::Breed.all.bark it doesn't work:

undefined method `bark' for #<Array:0x007fc7acbb6108>

If I make it:

def self.bark
  "woof"
end

And then call Dog::Breed.bark , it will woof at me. How do I make it so that I can add methods to the Breed class so that I can do Dog::Breed.all.bark or Dog::Breed.find(2).bark ?

The output from Dog::Breed.all was a #<RecursiveOpenStruct> . Disclaimer: That was an example case, not real life, dog.com leads to petsmart.

Dog::Breed.all returns an Array of Breed , not Breed . If you want all dogs to bark you need to iterate over the array, and make each one bark:

Dog::Breed.all.each(&:bark)

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