Google custom search API with pagination - ruby-on-rails

I have this method that puts the links of the 10 results from the Google custom search API into an array:
require 'json'
require 'open-uri'
def create
search = params[:search][:search]
base_url = "https://www.googleapis.com/customsearch/v1?"
stream = open("#{base_url}key=XXXXXXXXXXXXX&cx=XXXXXXXXXX&q=#{search}&start=#{i}&alt=json")
raise 'web service error' if (stream.status.first != '200')
result = JSON.parse(stream.read)
#new = []
result['items'].each do |r|
#new << r['link']
end
end
and my view:
<% #new.each do |link| %>
<p><%= link %></p>
<% end %>
I'm having trouble figuring out how to add pagination with this so that on the second page would return the next 10 results. I'm using the Kaminari gem for pagination.
I want for when a user clicks a link to another page, I fetch the next 10 results from Google's API. You can do this with the API's start parameter that specifies the first result to start with, which I pass as i. I was thinking of doing something like this:
i = (params[:page] - 1) * 10 + 1
where params[:page] is the current page number, but for some reason it is undefined. Also I'm unsure about how to setup pagination for an array that is not an AR object, and what would go in my view. I'd appreciate any help, and feel free to use any pagination gem you know.

How are you setting params[page]? It needs to be passed in with the other parameters in your request in some way.
Perhaps you need something like this in your controller:
#page = params[:page] || 1
i = (#page - 1) * PER_PAGE + 1
stream = open("#{base_url}key=XXXXXXXXXXXXX&cx=XXXXXXXXXX&q=#{search}&start=#{i}&alt=json")
raise 'web service error' if (stream.status.first != '200')
result = JSON.parse(stream.read)
#new = result['items'].map{|r| r['link']}
In your view you need to make sure that you are passing the page via the query parameter in the link to fetch the next set of results. Most likely that you would want to return #page + 1.
Handling pagination with non ActiveRecord objects depends on your pagination library. You might want to check out how will_paginate handles this.

Related

How can I send paginated requests to third party API in rails

Im building a web application in rails to fetch records from a third party API. This third party API accepts page parameter. For eg: GET http://thirdpartyapi.com/records?page=2
How can I build my html in paginated format, so that when user clicks on number 2, it should send page=2 and when user clicks on number 4, it should send page=4 in the requests. Is there any gem for that?
class DemoController < ApplicationController
def index
response = HTTP.get('http://thirdparty.com/records', {query: {page: params[:page]}}) # it will return 30 items by default
#items = response['items'].paginate(page: params[:page], per_page: 10)
end
end
This is my views
<%= will_paginate %>
If you want to do this manually it's more work than just using the will_paginate gem
First you would need to get a count of records so that you know how many pages (aka how many links at the bottom you will have for pages)
#num_of_records = Object.count / per_page
Then you will need to handle that through JS depending on the number of links you want to display.
Once a user clicks on yourlink.com/?page=2 it should load with the correct data, or if you choose to you can remove elements from the div/table and insert new ones by returning them if you do an AJAX call.
Your controller would look something like this:
def index
page = params[:page] || 1
per_page = 10
#num_of_records = Object.count / per_page
objects_to_append = Object.paginate(:page => page, :per_page => perPage)
render json: { success: true, objects_to_append: objects_to_append }
end
I highly recommend to use kaminari instead. they have a way to do this easily.
https://github.com/kaminari/kaminari#paginating-a-generic-array-object

How to set up kaminari correctly

I'm using kaminari gem for pagination. The problem is that I need to paginate on the first page after 4 elements, and on the all other pages after 25 elements. It it possible to configure kaminari to solve my problem?
Here is a usage:
.pagination
.pagination__back
- if params[:page] && params[:page].to_i > 1
= link_to "Previous news", news_items_path(page: params[:page].to_i - 1)
- else
= ""
.pagination__forward
- if params[:page]
= link_to "Next news", news_items_path(page: params[:page].to_i + 1)
- else
= link_to "Next news", news_items_path(page: 2)
First of all you can leave out all the code related to forward/previous pages. Kaminari solves this with its helper already.
For that matter, inside your view, use the following code:
= paginate #your_resource
This will render several ?page=N pagination links surrounded by an HTML5 tag.
(Source)
To have a paginated resource, you want to add the following code to your controller:
#your_resource = YourResource.order(:foobar).page(params[:page])
# params[:page] will get added to each "paginated" request by Kaminari
# if you use its previously mentioned helper method.
Now you want a dynamic limit. For that matter I suggest adding something like this:
def index
#your_resource = YourResource.order(:foobar).page(params[:page]).per(dynamic_limit(params[:page]))
end
private
def dynamic_limit(current_page = 1)
if current_page == 1
return 4
else
return 25
end
end
This way you will check for the current page, and if it's the first page it'll limit the results to 4. Otherwise, 25.

How to do SEO link tag for two/multiple pagination in single page?

I wrote an application in rails 4. In that app, I have two pagination in single page 'x (page)'. Params like groups and page in the url.
Url looks like:
https://example.com/x?page=2&group=4
Initial page:
https://example.com/x
If pagination page params, then
https://example.com/x?page=2
If paginating groups params, then
https://example.com/x?group=2
If paginating both,then
https://example.com/x?page=2&group=2
and so on.
I am using Kaminari gem to do pagination. In that gem I used rel_next_prev_link_tags helper to show link tag for prev/next.
How to show link tags for multiple pagination?
I created an custom helper to process the URL and based on params create the categorized link tags. ex: In view,
pagination_link_tags(#pages,'page') for pages pagination
pagination_link_tags(#groups,'group') for groups pagination
def pagination_link_tags(collection,pagination_params)
output = []
link = '<link rel="%s" href="%s"/>'
url = request.fullpath
uri = Addressable::URI.parse(url)
parameters = uri.query_values
# Update the params based on params name and create a link for SEO
if parameters.nil?
if collection.next_page
parameters = {}
parameters["#{pagination_params}"] = "#{collection.next_page}"
uri.query_values = parameters
output << link % ["next", uri.to_s]
end
else
if collection.previous_page
parameters["#{pagination_params}"] = "#{collection.previous_page}"
uri.query_values = parameters
output << link % ["prev", uri.to_s]
end
if collection.next_page
parameters["#{pagination_params}"] = "#{collection.next_page}"
uri.query_values = parameters
output << link % ["next", uri.to_s]
end
end
output.join("\n").html_safe
end
You can't show search engines two-dimensional pagination. In your case it looks more like grouping/categorizing + pagination.
Like:
Group 1 pages:
https://example.com/x
https://example.com/x?page=2
https://example.com/x?page=3
Group 2 pages:
https://example.com/x?group=2
https://example.com/x?page=2&group=2
https://example.com/x?page=3&group=2
Etc.

keep meta_search parameters for edit page?

I'm using meta_search gem.I have url like this for admin projects index page with search parameters.
admin/projects?utf8=✓&search%5Bid_equals%5D=&search%5Btitle_contains%5D=&search%5Bstage_in%5D=completed
Then user choose one project and url will be this
admin/projects/a--15/edit?page=1
When user update this form,The search parameters will be lost.
How can i keep these parameters.I mean with session or meta_search have some method to fix this?
First, create a filter that fires for every action that might want access to the search parameters:
ProjectsController < ApplicationController
before_filter :save_searches
def save_searches
#addons = ''
[:page, :id_equals,:title_contains,:stage_in].each do |k|
if params[k]
pval = params[k].is_a?(Array) ? params[k].join(',') : params[k]
#addons << k.to_s + "=" + pval + "&"
end
end
#addons.chop!
end
Now, when your actions fire, #addons will be set, and then you can do this:
<%= link_to 'Edit' , edit_path(#project.id) + #addons.length > 0 ? "?" + #addons : '' %>
That said, I'm willing to bet this is somewhat of a hack, and there is a cleaner way to do it. But this works for me.
The :page key makes it so that if you have pagination running and using the :page param to track current page, your pagination should be remembered as well.
Also note that in the event of you getting an Array in your params, (i.e. the result of a select with :multiple=>true), this is handled.

kaminari - redirect to last page

So I've got pagination with Kaminiari set up on my app, which is a forum. When someone replies to the thread, I want to direct them to the last page of the thread. It seems like it'd be easy enough to hard code the logic to get the last page based on what I'm using for record numbers, but is there a built in method to get the last page?
In my current version of kaminari (v0.12.4) the following works:
users = User.page(params[:page])
last_page = users.num_pages
num_pages is defined in https://github.com/amatsuda/kaminari/blob/master/lib/kaminari/models/page_scope_methods.rb.
If you want to add a last_page method, I suggest the following:
module Kaminari
module PageScopeMethods
def last_page
num_pages
end
end
end
It seems that this thread has an answer.
You can write a method to achieve this if not already present in Kaminari . This should be present since Kaminari also renders the page numbers for navigation.
Say, #records is list of db records where you performed #records.page(1) to show the get the current set of records,
The last page number is defined by (#records.total_count / per_page.to_f).ceil .
For other people's sake, I'll share what worked for me.
Associations
Conversation has_many Messages
Message belongs_to Conversation
In Conversation show page, I want to paginate every 10 messages
messages = conversation.messages.page(params[:page]).per(10)
last_page = messages.total_pages
Then I want to create a link to this show page which will show me the last page. I just made a helper method
def create_link_to_last_page(conversation)
content_tag :div do
link_to("Show", url_for(controller: 'conversations', action: 'show', id: conversation.id, page: last_page))
end
end

Resources