boydenhartog
boydenhartog

Reputation: 752

Rails way to call external API from view?

I'm trying to include some sort of 'widget' in one of my views that allows the user to consume an external 'search' API. The external API returns a JSON set of results. I would like to use this JSON to show the user a list of results.

What is the 'rails way' to make this happen?

For example, I would like to put a search input on the homepage, with a button to search the external API. I have created a PORO that calls the API and this PORO will return the results, but how do I take the users search string and post it to this PORO?

Upvotes: 1

Views: 3440

Answers (1)

Alexandre Angelim
Alexandre Angelim

Reputation: 6773

Just summing up what we discussed in the comments. The simplest way to accomplish what you want will need a view to render the widget and a route + controller to handle the search request.

This is all untested code, but you can get the gist of it.

# routes.rb
# this can be named and pointed to anywhere you want.
# It's using get just so you can see the search params in the url, which is preety common for the search feature.
get '/search', to: 'searches#show', as: 'search'

# models/search.rb
# Your PORO
class Search
  attr_reader :results
  def initialize(query)
    # perform request and assign results
    @results = HTTParty.get(url, query: { keyword: query })
  end
end

# controllers/searches_controller.rb
def show
  if params[:query]
    @search = Search.new(params[:query])
  end
end

# views/searches/show.html.erb
<%= form_tag search_path, method: :get do %>
  <%= text_field_tag :query, params[:query] %>
  <%= submit_tag %>
<% end %>

# .... renders contents if they're present.
<%= @search.results if @search %>

What you could additionally do is turn Search into a model, so it would inherit Naming and you could deal with it as a regular resource.

# routes.rb
# A singular resource will do.
resource :search, only: [:show]

# models/search.rb
include ActiveModel::Model
attr_reader :results
attr_accessor :query
validates :query, presence: true
def perform
  @results = HTTParty.....
end

# controllers/searches_controller.rb
def show
  if search_params = params[:search] && params[:search][:query]
    @search = Search.new(query: search_params)
    @search.perform if @search.valid?
  else
    @search = Search.new
  end
end

# views/searches/show.html.erb
<%= form_for @search, method: :get do |f| %>
  <%= f.text_field :query %>
  <%= f.submit %>
<% end %>

<%= @search.results %>

Now... You probably want to render your widget everywhere and not only in /search, so you can extract the form into a partial and render it in application.html.erb.

If you went for the ActiveModel approach don't forget to initialize @search in every request you render the form. You can use a before_action for that.

Upvotes: 3

Related Questions