I’m missing something stupid. Help?
lib/api.rb
require 'httparty'
module API
def self.call_api(query)
base_url = "http://myapi.com"
return HTTParty.get("#{base_url}/#{query}.json")
end
end
models/job.rb
require 'api'
class Job
include API
def self.all(page=1)
self.call_api "jobs?page=#{page}"
end
end
Job::all
NoMethodError: undefined method `call_api’ for Job:Class
If I move my “call_api” directly into the Job class, it works. What am I missing?
The other answers have pointed out your issue you should have extend instead of include:
You might also like to consider using the following pattern which aside from being useful can also help to alleviate the confusion, since you can tell straight away that your class methods are in the
ClassMethodsmodule while your instance methods are directly in theMyModulemodule.This uses Ruby’s
includedcallback (which is fired every time a module in included in a class), we redefine the callback (which normally doesn’t do anything), to extend the class in which the module was included with theClassMethodssub module. This is a very common metaprogramming pattern in Ruby. If you use this pattern you no longer have to worry about extend, just useinclude:then:
You can also take this pattern a little bit further:
Notice that the parent module includes its child
ClassMethodsmodule directly. This waymy_class_methodbecomes both an instance and a class method:You have to be a bit careful if you do that about how you code your method in the
ClassMethodschild module. But I have found this pattern extremely handy on occasion.