I am practicing making third-party api calls using the rest-client gem. Right now, my code for making a call to a third-party api is stored in a show
method in my search_controller.rb
. I'm assuming it would be better to store that logic somewhere other than a controller, in order to follow the "skinny controller" practice of ruby on rails. Where would be a better place to put this type of logic, or is this an ok place to have it?
I would say two different kinds of objects in conjunction.
These are classes that simply do HTTP calls and touch the application boundary. The reason you want to isolate this in a discrete object is that it allows you mock it in tests. It also keeps the responsibilities clear.
# adapted from the HTTParty readme
class StackExchangeClient
include HTTParty
base_uri 'api.stackexchange.com'
def initialize(service, page)
@options = { query: { site: service, page: page } }
end
def questions
self.class.get("/2.2/questions")
end
def users
self.class.get("/2.2/users")
end
end
/lib
is a pretty good place to store clients since they rarely should contain any application specific logic.
Service objects are Plain Old Ruby Objects (PORO) that are designed to execute one single action in your domain logic and do it well.
-- Rails Service Objects: A Comprehensive Guide
class QuestionImporterService
def initialize(service, page, client: nil)
@client = client || StackExchangeClient.new(service, page)
end
def call
questions = @client.get_questions
questions.map do |attributes|
Question.new(attributes)
end
end
end
This example uses constructor injection to allow you to mock out the HTTP calls for testing.
You can place services in /app/services
. Sometimes Spring gets "stuck" and does not pickup new folders in /app
for autoloading in which case you restart it by calling $ spring stop
.
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.