will_paginate usage with web call - ruby-on-rails

my index action calls out to the web
response = HTTParty.get('http://www.ask.com/open')
I added pagination to the index, because there were too many results
#asks = ask.paginate(:page => params[:page], :per_page => 5)
and the corresponding call to will_paginate in my view
The problem I have is when the user clicks to move to the next page, it results in the service all being made to the server. I want to just have it fetch the results from model if it is a pagination call, but call the service if the index is being called directly.

Related

Can I Check if a Controller is Being Called from an AMP page in Rails?

I'm starting to implement AMP pages in my Rails 5.2 app. On desktop, I'm using the Will Paginate gem.
However, with AMP I'm using the framework's infinite scroll JS, and I don't want to paginate the results.
So in the controller action, I want to determine if the user is viewing an AMP page (the URL ends with .amp) to determine what I have for this line (include paginate or exclude):
#products = #products.order('price DESC, RANDOM()').paginate(page: params[:page], per_page: 24)
How do I do this?
The simple solution is just test request.format. So you could write
if request.format == :amp
# do not paginate
else
# all other formats we paginate
end
But inside a controller, we can also use an explicit respond_to block:
def index
respond_to do |format|
format.amp do
#products = #products.order('price DESC, RANDOM()')
end
format.html do
#products = #products.order('price DESC, RANDOM()').paginate(page: params[:page], per_page: 24)
end
end
end
This will explicitly specify all the formats the controller method accepts and responds to.
As you probably already do, but you will have to provide a view for index.amp and a index.html.
To be clear: this will also block all non-specified formats! E.g. retrieving a index.json will get a 405 Not allowed.

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

Slow third party API requests in Rails

I'm building a single page Rails 4 app that uses the Soundcloud and Instagram gems. I have noticed that sometimes these API requests slow down my app. I am unsure on what the best approach/practice is for handling such requests so that they do not adversely effect the performance of my app? I've looked into asynchronous requests, sidekiq and have also found this example: http://www.jonb.org/2013/01/25/async-rails.html
My Index Controller looks like this:
require 'soundcloud'
class HomeController < ApplicationController
def index
# register a new client, which will exchange the username, password for an access_token
soundcloud_client = Soundcloud.new(
:client_id => ENV['SOUNDCLOUD_ID'],
:client_secret => ENV['SOUNDCLOUD_SECRET'],
:username => ENV['SOUNDCLOUD_USERNAME'],
:password => ENV['SOUNDCLOUD_PASSWORD']
)
# Soundcloud
#activity = soundcloud_client.get('/me/favorites').first(12)
# Instagram
#instagram = Instagram.user_recent_media("1111111", {:count => 12})
end
end
maybe a better approach to this, is to load your index as you would, but do not load the list from soundcloud on that index.
Instead have an Ajax call on your view that calls a pure JSON action inside your controller, doing it that way you will serve the page rapidly, and not block on soundclock. You can put a spinner on your view indicating that the page is still loading. Looking into jquery load method.
https://api.jquery.com/load/
good luck.

Pagination of search form results returns nothing for subsequent pages (Kaminari + Rails)

So I have a search form that returns a Kaminari paginated array. The first page always returns a list of results, however the "GET" of all subsequent page links returns no results and I'm not sure why!
Here are my search methods in my controller
def writer_search
#writers = Kaminari.paginate_array(#results).page(params[:page]).per(10)
end
def writer_search_submit
#results = #my big array of results, this part works fine
#writers = Kaminari.paginate_array(#results).page(params[:page]).per(10)
render 'writer_search'
end
View Code
=form_tag(writer_search_submit_path, :method => 'post') do
%input{:name => 'keywords', :id => 'keywords', :value => params[:keywords]}
= submit_tag "Search"
- #writers.each do |writer|
#show the results
= paginate #writers
Server Log when clicking a pagination link
Started GET "/editors/writer_search?commit=Search&keywords=business&page=2"
Processing by EditorsController#writer_search as HTML
Parameters: {"commit"=>"Search", "keywords"=>"business", "page"=>"2", "utf8"=>"✓"}
The first rendered page has the first 10 results of my array (in this case, there are hundreds of results). Clicking on any of the pagination links makes a GET and returns a page with no results.
Any ideas?
Looks like you have #results defined in writer_search_submit but not writer_search.
The GET request to "/editors/writer_search?commit=Search&keywords=business&page=2" goes through EditorsController#writer_search where #results is undefined (and so you get a page with no results).
Update: (Thanks Thilo)
Perhaps you could use a before_filter to load #results for all the actions that need it?
Rails doesn't render the search results on an actually search page but on the default index page of whatever route you're searching for.

What's a better way to use helper methods with will_paginate?

I'm using the latest version of will_paginate with rails 3. I'd like to use out_of_bounds? to set the current page to the last page if the page parameter is higher than the last page. I found a way to do it like this:
people = People.all.paginate :page => params[:page], :per_page => 20
#people = people.paginate(:page => (people.out_of_bounds? ? people.total_pages : params[:page))
The problem with this is that I have to call paginate twice. The first time to create a WillPaginate::Collection in order to use the out_of_bounds? and total_pages methods, and the second time to actually set the current page. I also need to do this with more actions so it's getting kinda out of hand. I can't use a before_filter or an after_filter, either (I don't think?). Is there a better way to achieve this?
I don't know the best solution, but at least you can do the check before the second call to the method (I suppose that in most of the cases, the page parameter will be ok, so you wont have to call paginate twice):
people = People.all.paginate :page => params[:page], :per_page => 20
#people = people.out_of_bounds? ? people.paginate(:page => people.total_pages) : people

Resources