Alrighty, so I have searched on here repeatedly on this as well as other places but have yet to find the solution that relates to me. Probably because the previous questions were some time ago.
My problem is that I had first added pagination and then I was required to add a search so that users could search for products. When they do the search it's just supposed to open the products page. If I took out the search, the pagination doesn't give me an error.
The error I get now is
''undefined method `total_pages' for # Product::ActiveRecord_Relation:''
and the line of code highlighted for the error is the pagination in the index.html.erb.
What am I missing? Thanks for any guidance, this newbie needs it!
This is the products_controller:
def index
if Rails.env == "development"
name_env = "name LIKE ?"
else
name_env = "name ilike ?"
end
if params[:q]
search_term = params[:q]
#products = Product.search(search_term)
else
#products = Product.all
#products = Product.paginate(:page => params[:page], per_page: 4)
end
end
This is the index.html.erb :
<div class="pagination">
<%= will_paginate #products %>
</div>
You have missed paginate method when the search, it #products = Product.search(search_term) will be like this
.....
if params[:q]
search_term = params[:q]
#products = Product.search(search_term).paginate(:page => params[:page], per_page: 4)
else
#products = Product.all.paginate(:page => params[:page], per_page: 4)
.....
Additionally Remove this #products = Product.all don't need this.
After all, you just paste this instead of your code, it reduced
def index
if Rails.env == "development"
name_env = "name LIKE ?"
else
name_env = "name ilike ?"
end
if params[:q]
search_term = params[:q]
#products = Product.search(search_term)
else
#products = Product.all
end
#products = #products.paginate(:page => params[:page], per_page: 4)
end
Modify index action as follows:
def index
if Rails.env == "development"
name_env = "name LIKE ?"
else
name_env = "name ilike ?"
end
#products = params[:q] ? Product.search(params[:q]) : Product.scoped
#products.paginate(:page => params[:page], per_page: 4)
end
you should use paginate for searching too.
Related
I have a controller method for searching and listing invoices, sales orders and homes based on params name, how to simplify this index method`
def index
#so = QbwcSalesOrder.paginate(:page => params[:page], :per_page => 30)
if params[:qs] == "Sales Orders"
#so = #so.where("ref_number = ? ",params[:keyword]) if params[:keyword].present?
elsif params[:qs] == "Invoices"
#so = QbwcInvoice.paginate(:page => params[:page], :per_page => 30)
#so = #so.where("ref_number = ? ",params[:keyword]) if params[:keyword].present?
elsif params[:qs] == "All Homes"
#so = QbwcHome.paginate(:page => params[:page], :per_page => 30)
elsif params[:qs] == "Existing Homes"
#so = QbwcHome.where(record_type: "FromQB").paginate(:page => params[:page], :per_page => 30)
end
end
First of all unify hash syntax and indentation, it's hard to read.
Second paginate once at the end of the index method, looks like you paginate always the same way.
Third think about scopes or query object https://mkdev.me/en/posts/how-to-use-query-objects-to-refactor-rails-sql-queries
Here is simplified version, you can use it in index or move to the query object:
def index
#so = QbwcSalesOrder.all
#so = #so.where("ref_number = ? ", params[:keyword]) if params[:keyword] && params[:qs] == "Sales Orders"
#so = #so.where("ref_number = ? ", params[:keyword]) if params[:keyword] && params[:qs] == "Invoices"
#so = #so.where(record_type: "FromQB") if params[:qs] == "Existing Homes"
#so = #so if params[:qs] == "All Homes"
#so = #so.paginate(page: params[:page], per_page: 30)
end
To me this looks like the method is doing way to much and needs to be split into managable parts:
def index
#so = qs_model_scope(params[:qs])
.paginate(page: params[:page], per_page: 30)
.then do |scope|
filter_by_keyword(scope)
end
end
# ...
private
def qs_model_scope(qs)
case qs
when "Invoices":
QbwcInvoice.all
when "All Homes":
# Smelly - should be a model scope
QbwcHome.where(record_type: "FromQB")
else
QbwcSalesOrder.all
end
end
def filter_by_keyword(scope)
if params[:keyword].present? && ["QbwcSalesOrder","QbwcInvoice"].include?(scope.model.name)
# no need to use a SQL string
scope.where(ref_number: params[:keyword])
else
scope
end
end
If the complexity of this continues to grow you should consider moving this filtering process out of the controller and into a separate object (such as a form object or service object or just a PORO) so that it can be tested in isolation.
I'd split the logic into separate methods. As already mentioned in another answer it makes sense to move it to a query object or something.
def index
scope = invoices || all_homes || existing_homes || sales_orders
#so = scope.paginate(:page => params[:page], :per_page => 30)
end
private
def invoices
return if params[:qs] != 'Invoices'
return QbwcInvoice if params[:keyword].blank?
QbwcInvoice.where(ref_number: params[:keyword])
end
def all_homes
QbwcHome if params[:qs] == 'All Homes'
end
def existing_homes
QbwcHome.where(record_type: 'FromQB') if params[:qs] == 'Existing Homes'
end
def sales_orders
if params[:qs] == 'Sales Orders' && params[:keyword].present?
QbwcSalesOrder.where(ref_number: params[:keyword])
else
QbwcSalesOrder
end
end
I am using sunspot 2.2.2 in my rails app for searching results,
I have this code for grouping in my model:
def self.search_products(params, currency = nil, page_uri = nil)
search_products = Sunspot.search(VariantPrice) do
group :code do
if params[:gallery_order].present?
order_by :price, params[:gallery_order].downcase.to_sym
elsif params[:new_arrival].present? || params[:name] == "new-arrivals"
order_by :product_created_at, :desc
else
if params[:fashion_type] == "fashion"
order_by :price, :asc
elsif params[:sort] != "lowhigh"
order_by :price, :asc
else
order_by :price, :asc
end
end
limit 1
end
end
and I have this code in my controller :
variant_prices = Product.search_products(params, #currency, request.original_fullpath)
#variant_prices = []
variant_prices.group(:code).groups.each do |group|
group.results.each do |result|
#variant_prices << result
end
end
#variant_prices = #variant_prices.paginate(:page => params[:page], :per_page => PER_PAGE_VALUE)
#variant_prices_count = variant_prices.group(:code).total
now I am getting the expected count that is #variant_prices_count, which is 1400 in my case, but I am getting #variant_prices count as 60 which is wrong in my case , here I was expecting to get 1400.and then I want to paginate with this result. cant understand whether it's will_paginate issue or something else.
Help!
You can get 1400 from the paginate instance also by Total entries
by this way replace count with total_entries
#variant_prices = #variant_prices.paginate(:page => params[:page], :per_page => PER_PAGE_VALUE)
#variant_prices.total_entries#it will return toal entries 1400
Rails 3.2.8
I have the following:
def index
params[:direction] ||= "desc"
params[:sort] ||= "status"
#products = product.solr_search( include: [:customer] ){
fulltext params[:query] if params[:query].present?
with :status, (params[:status] || params[:filter]) if (params[:status] || params[:filter]).present?
order_by( params[:sort], params[:direction] ) if params[:sort].present? && params[:direction].present?
paginate page: params[:page], per_page: params[:per_page]
}.results
end
What I would like to do is do the initial sort with a priority when the status column = 'new'. In MySQL, it would be something like this:
SELECT * from product ORDER BY case when status = 'new'
Any idea what my syntax should be?
i am trying to delete from list but when i am trying this it is getting deleted from database
#course = Course.find(params[:id])
#search = Lesson.search(params[:q])
#lessons = #search.result.paginate(:page => params[:page], :per_page => 10)
#search.build_condition if #search.conditions.empty?
#course.lessons.each do |lesson|
#lessons.each do |l|
if lesson.id == l.id
#lessons.delete(l)
end
end
end
I am getting this error: delete_all doesn't support limit scope
Thanking you
Delete is an ActiveRecord method. I assume you don't want to delete it from the database but from the result list. You can do it like this:
#course.lessons.each do |lesson|
#lesson.reject { |l| l.id == lesson.id }
end
I have the following bit of code:
def index
#games = Game.gamsearch(params[:gamsearch])
#games = Game.consearch(params[:consearch]) if params[:consearch].present?
#games = Game.gensearch(params[:gensearch]) if params[:gensearch].present?
#games = Game.where("game_name LIKE ?", "#{params[:game_name]}%") if params[:game_name].present?
#games = Game.where("console = ?", params[:console]) if params[:console].present?
end
What I wish to do is have all of these results paginate. Now I know how to paginate from a singular search as I have done here:
def index
user_relation = case params[:username].present?
when true then User.where("username LIKE ?", "#{params[:username]}%")
else User
end
#users = user_relation.paginate :page=>params[:page], :order => 'created_at desc', :per_page => 10
end
But the games controller has 5 possible methods of search and was wondering how I would apply pagination to it.
Any help would be great, thanks.
This should be possible by appending the search results all to the same array and than paginate this array.
like:
def index
#games = Array.new()
#games << Game.gamsearch(params[:gamsearch])
#games << Game.consearch(params[:consearch]) if params[:consearch].present?
#games << Game.gensearch(params[:gensearch]) if params[:gensearch].present?
#games << Game.where("game_name LIKE ?", "#{params[:game_name]}%") if params[:game_name].present?
#games << Game.where("console = ?", params[:console]) if params[:console].present?
end
and then just paginate the #games object.
hope this helps!