Kaminari error when collection is smaller than per(x) - ruby-on-rails

I am running the Kaminari gem for my pagination.
Controller
def dashboard
#projects = Project.find_by_user_id(current_user)
if #projects.size > 10
#projects.page(params[:page]).per(10)
end
end
Dashboard view
= paginate #projects, :theme => 'twitter-bootstrap-3', :remote => true
In my case, the #projects is sometimes only 1 record or even zero records. When it is nil, I get an error on the params[:page] being nil.
So this works
def dashboard
#projects = Project.page(params[:page]).per(10)
end
This gets error undefined method 'page' for #<Project:0x007f8cac5f14b0>
def dashboard
#projects = Project.find_by_user_id(current_user).page(params[:page]).per(10)
end
I think it is because the #projects is only a couple of records which is less than the 10 specified in .per
I tried adding a #projects.count or #projects.size but I get the error undefined method 'size' for #<Project:0x007f8c996865f0>
def dashboard
#projects = Project.find_by_user_id(current_user)
if #projects.size > 10
#projects.page(params[:page]).per(10)
end
end
What the hell am I doing wrong!? haha
I am guessing I can fix this in the first instance instead of trying to fix the second or third options. Any help would be greatly appreciated.

The issue is Project.find_by_user_id(current_user) returns an Array, not an ActiveRecord::Relation
You should do something like:
current_user.projects.page(params[:page]).per(10)
If your relationships are correctly setup.
Or:
Project.where(user_id: current_user.id).page(params[:page]).per(10)

Related

Kaminari Pagination TypeError

I`m using kaminari in rails 7 to make the apgination of my API, but when i try to see a page different of the first page, im taking a type error, when i try access "http://localhost:3000/products?page=3":
TypeError (no implicit conversion of Symbol into Integer)
My paginated products index:
# GET /products
def index
page_number = params[:page].try(:[], :number)
per_page = params[:page].try(:[], :size)
#products = Product.all.page(page_number).per(per_page)
paginate json: #products
end
Anyone has a clue to how solve this?
EDIT:
I created a initializer named api_pagination.rb and put on him:
ApiPagination.configure do |config|
config.page_param do |params|
params[:page][:number] if params[:page].is_a?(ActionController::Parameters)
end
config.per_page_param do |params|
params[:page][:size] if params[:page].is_a?(ActionController::Parameters)
end
end
And now i can access "http://localhost:3000/products?page%5Bnumber%5D=2&page%5Bsize%5D=12" , but it doesn't look right to me, or this is the right way?
Maybe you need to set default values? Try with:
page_number = params[:page].try(:[], :number) || 1
per_page = params[:page].try(:[], :size) || 20
if that doesn't work, check what's coming in those number and size params or share more information of your issue, like the whole error stacktrace, even better the full request log.

Ruby on Rails: custom rendering in controller

So basically I have this for my index page:
def index
#articles = Article.paginate(:per_page => 15, :page => params[:page])
end
I implemented soft deletion, which basically works like this: there is an additional boolean column in db that is called is_active and is true by default. Deleting is rewritten to just change that to false instead of destruction, and made a page to view soft-deleted entries.
The issue: current workaround I found for paginate is to simply add
<% if article.is_active %>
in my index.html.erb. The flaw is: when I delete something it still considered there by paginate, so instead of say 15 entries I will see 14. Even worse, on undeleting page it shows same amount of blank pages, and deleted entries are on their would-be-appropriate pages (so for example first entry may end up being on page 14 instead of 1). It is not critical flaw, but I'd like to know if I can fix it without rewriting too much.
Maybe I can change something in controller so it doesn't send any entries that have true or false in that field depending on what I want to output?
Can't you just filter by this field?
#articles = Article.where(is_active: true).paginate(per_page: 15, page: params[:page])
You can use a scope or a where clause to get only active articles:
def index
#articles = Article.where("is_active = ?", true).paginate(:per_page => 15, :page => params[:page])
end

kaminari undefined method 'page'

I am trying to add Kaminari to my Rails app. I have included the gem and this is what my controller looks like:
def index
if params[:year]
if params[:year].size > 0
#songs = Song.where("year like ?", params[:year]).page(params[:page])
elsif params[:artist].size > 0
#songs = Song.where("artist_name like ?", params[:artist]).page(params[:page])
elsif params[:song].size > 0
#songs = Song.where("title like ?", params[:song]).page(params[:page])
end
else
#songs = Song.first(10).page(params[:page])
end
end
and then adding
<%= paginate #songs %>
in my view, the error I am getting is:
undefined method `page' for #<Array:0x007fab0455b4a8>
Not sure why this is coming up as I followed the docs step for step.
Kaminari uses paginate_array to paginate an array. 2 solutions:
First, you can use limit(10) instead of first(10):
#songs = Song.limit(10).page(params[:page])
Second, use paginate_array
#songs = Kaminari.paginate_array(Song.first(10)).page(params[:page])
I'd advise you rewrite your controller slightly. Better yet, move your filters to the model or a filter class. Look into present? for testing existence of params as that will check for nil and empty.
def index
#songs = Song
#songs = #songs.where("year like ?", params[:year]) if params[:year]
#songs = #songs.where("artist_name like ?", params[:artist]) if params[:artist]
#songs = #songs.where("title like ?", params[:song]) if params[:song]
#songs = #songs.limit(10).page(params[:page])
end
Tl;DR If you use Mongoid, use kaminari-mongoid instead of kaminari alone.
At Github it said, Kaminari supports Mongoid...so I went and installed gem 'kaminari' with the result: unknown method :page...later i found the mongoid adapter: kaminari-mongoid and that works now.

Setting default search parameter on Ransack for rails

I've been wracking my brain over this but can't get it. I feel like the answer is probably obvious.
What I'm trying to do is the following:
I have an index controller which lists a series of Jobs which I can search using Ransack. Each job has a completion date which either has a date in it or is null (unfinished). Currently, the search itself works great. I would like to make it so that the index page loads up showing only the unfinished work, but I also want it to work so that when someone does run a search, returns results for both finished and unfinished work.
Any help would be greatly appreciated. In the code below, :actual is the name of the field with the completion date. I also was looking around the web and thought that maybe something like the DEFAULT_SEARCH_PARAMETER={} that I have in the Job model might work but I couldn't seem to get it to.
Here is the code:
class Job < ActiveRecord::Base
DEFAULT_SEARCH_PARAMETER ={}
attr_accessible :items_attributes, :actual
end
def index
#search = Job.search(params[:q] || Job::DEFAULT_SEARCH_PARAMETER)
#search.build_condition
#results = #search.result
#job = #results.paginate(:per_page => 10, :page => params[:page])
end
Late to the party, but thought I'd suggest an alternate approach in case someone else comes across this.
The answer above works, but its disadvantage is that the default is not added to Ransack's search object, so - if you are using a search form - the default selection is not shown in the form.
The following approach adds the default to the search object and therefore will appear in your search form.
def index
#search = Job.search(params[:q])
#search.status_cont = 'Open' unless params[:q] #or whatever, must use Ransack's predicates here
#results = #search.result
#job = #results.paginate(:per_page => 10, :page => params[:page])
end
I think you could just apply your own filter when the search parameters don't exist:
def index
#search = Job.search(params[:q])
#results = #search.result
#results = #results.where(:your_date => nil) unless params[:q]
#job = #results.paginate(:per_page => 10, :page => params[:page])
end
Many years later I found myself with this exact problem so I thought I'd chime in with a solution I'm using. Set default search params in the controller and reverse merge them into params[:q]:
def index
default_search_params = {
status_cont: "open"
}
#search = Job.search((params[:q] || {}).reverse_merge(default_search_params))
...
end
So by default, you want the page to load with records where actual is nil. And later when the user searches you want to go back to how your search was working before.
Give this a try.
def index
#search = Job.search(params[:q] || Job::DEFAULT_SEARCH_PARAMETER)
#search.build_condition
#results = #search.result
if #results.nil?
#results=Job.find(:all, :conditions => ["actual = NULL"] )
end
#job = #results.paginate(:per_page => 10, :page => params[:page])
end

How do I create a link to a list of records where field X contains Y in Ruby on Rails?

I get the exact result I want if I change...
def index
#listings = Listing.all
end
to...
def index
#listings = Listing.where("general_use == 'Industrial'")
end
... in listings_controller.rb
The Listings index view shows a list of all Listings where the general_use field contains the word Industrial. However, I can no longer use the index view to show all listings if I do this.
I want to add a link at the top of my listings index view that narrows the listings down from "all" to just the "industrial" listings.
I don't know what code should go in any, all or none of the following places:
controllers\listings_controller.rb
helpers\listings_helpers.rb
models\listing.rb
views\listings\index.html.erb
config\routes.rb
Any help would be greatly appreciated.
Thanks,
Chip
Simple, use a GET parameter:
def index
if params[:use]
#listings = Listing.find(:all, :conditions => {:general_use => params[:use]})
else
#listings = Listing.all
end
end
In your view, add a link to ?use=industrial and you're all set.

Resources