search form in nav bar doesn't render anything - ruby-on-rails

I have a search form in my nav bar
<%= simple_form_for :query, url: clients_products_path, method: :get, wrapper: :inline_form, html: {class: 'form-inline'} do |f| %>
<%= f.input :keyword, placeholder: "Recherche" %>
<%= f.submit "Valider" %>
<% end %>
In my product_controller.rb
class Clients::ProductsController < ApplicationController
def index
filter_products if params[:query].present?
#products ||= Product.all
end
private
def filter_products
return if params[:query].blank?
#products = Product.where('lower(title) LIKE ?', params[:query][:keyword]) if params[:query][:keyword].present?
end
end
My query seems to be correct as I can find product in the rails console.
but it doesn't display anything in the product#index...
Where am I wrong?
update
All products are well displayed, and everything disapear when I make a query
clients/products/index.html.erb
<% #products.each do |product| %>
<%= link_to clients_product_path(product) do %>
<%= image_tag(product.attachments.first.url) %>
<%= product.title %>
<%= product.price %>
<% end %>
<% end %>
here is the result
http://localhost:3000/clients/products?utf8=%E2%9C%93&query%5Bkeyword%5D=jean&commit=Valider

I believe your issue lies here:
#products = Product.where('lower(title) LIKE ?', params[:query][:keyword])
You need to either prepend, append or wrap your query with %. For example:
#products = Product.where('lower(title) LIKE ?', "%#{params[:query][:keyword]}%")
# Think it's the above, though could be the following:
# #products = Product.where('lower(title) LIKE "%?%"', params[:query][:keyword])
If you have a read on SQL's LIKE operator, the % operates something like a wildcard. Without these, you're searching for an exact match, rather than a phrase contained within the title. Docs are here.
Give that a shot and let me know how you get on.

First of all you are checking params[:query] twice(once when calling filter_products and second time in that function)
And their is something wrong with you filter_products function.
When you do #products ||= Product.all you get blank ActiveRecordRelation if query returns empty relation. In other words #products will always be blank if query[:keyword] doesn't match the title.
Try changing your index function to:
def index
#products = Product.where('lower(title) LIKE %?%', params[:query][:keyword].downcase) if params[:query][:keyword].present?
puts #products
#products ||= Product.all
end
If it still returns blank, then try to print #products variable.

Related

How to render search results only when the user press search

Does anyone know how to only display search results once you have clicked the search button?
At the moment, my page is currently displaying everything from my #flights.each. But I only want this information to become visible once they have clicked search :)
my index.html.erb
<h1>Flights#index</h1>
<p>Find me in app/views/flights/index.html.erb</p>
From Airport:
<%= form_for(flights_index_path, method: :get) do %>
<%= text_field_tag :from_airport_id, params[:from_airport_id] %>
<%= submit_tag 'Search' %>
<% end %>
<% #flights.each do |f| %>
<br>
<br>
Flight from <%= f.from_airport_id %>
Arriving at <%= f.to_airport_id %>
<% end %>
my controller
class FlightsController < ApplicationController
def index
if params[:from_airport_id]
#flights = Flight.where('from_airport_id LIKE ?', "%#{params[:from_airport_id]}%")
else
#flights = Flight.all
end
end
private
def flights_path
params.require(:flight).permit(:flight, :from_airport_id)
end
end
I believe it's because you have #flights = Flight.all in the else condition. When there is no query(such as after hitting the submit button and passing over the params) it will default to show all the flights. I'd take this line out and only have
def index
if params[:from_airport_id]
#flights = Flight.where('from_airport_id LIKE ?', "%#{params[:from_airport_id]}%")
else
#flights = []
end
end
Or you can look to have an AJAX request from your flights search and render the form that way.

Creating site-wide search in a Rails app

I'm trying to create a search form that retrieves results based on a user's query for a restaurant's name. So far I've setup its route, controller, and index view.
routes.rb
resources :search, :only => [:index]
search_controller.rb
class SearchController < ApplicationController
def index
if params[:query].present?
#restaurants = Restaurant.search(params[:query])
else
#restaurants = Restaurant.all
end
end
end
search/index.html.erb
<% #restaurants.each do |restaurant| %>
<%= restaurant.name %>
<% end %>
Here is how the search for is setup:
layouts/_header.html.erb
<%= form_for search_index_path, method: :get do |f| %>
<%= text_field_tag :query, params[:query] %>
<%= submit_tag "Search", name: nil %>
<% end %>
Right now I'm running into two problems. The first being that if I enter a query and submit, the page doesn't go to the index page. All it does is append the query to the current page I'm on:
localhot:3000/restaurant?utf8=✓&query=pizza
Second is that I'm getting every restaurant in my db on the index page (as expected). Is there a way that I can make it so the page is blank for anything other than on search requests?
Question 1
Use form_tag instead of form_for, since the latter is used to handle specific model objects and this is not the case.
Question 2
You can achieve that by:
if params[:query].present?
#restaurants = Restaurant.search(params[:query])
else
#restaurants = [] # or Restaurant.none if you need a chainable scope
end

Why does my search show all results with searching?

I setup a search on my Products index page with PgSearch and Will-Paginate like this:
ProductsController
def index
#products = Product.text_search(params[:query]).page(params[:page]).per_page(5)
end
Products Model
include PgSearch
pg_search_scope :search,
def self.text_search(query)
if query.present?
search(query)
else
scoped
end
end
Product index page
<%= form_tag products_path, method: :get do %>
<%= text_field_tag :query, params[:query] %>
<%= submit_tag "Search", name: nil %>
<% end %>
<% if #products.blank? %>
No Results
<% else %>
<% #products.each do |product| %>
<%= product.name %>
<% end %>
<% end %>
But the problem I'm having now is that when I go to the Product index page, it shows all of the products when I want it to show nothing until a search is done. If the search is blank, return No Results but when you first hit the page it should show nothing. How would this be done?
You probably want to only run a text_search when a search parameter is present. You can put this logic into the view, the controller, or in the model.
In the view
<% if params[:query].present? %>
<% if #products.blank? %>
No Results
<% else %>
<% #products.each do |product| %>
<%= product.name %>
<% end %>
<% end %>
<% end %>
In the controller
def index
if params[:query].present?
#products = Product.text_search(params[:query]).page(params[:page]).per_page(5)
else
#products = Product.none # NOTE: Rails 4 only
end
end
In the model
# create a new method to encapsulate this search logic then use it in the controller
def self.search(value)
if value.present?
Product.text_search(value)
else
Product.none # NOTE: Rails 4 only
end
end
The old saying goes "fat model, skinny controller" so you might want to opt for the model method which will keep your controller and views simpler.
Put your display logic inside an if statement:
<% if params[:query].present? %>
<% if #products.blank? %>
No Results
<% else %>
<% #products.each do |product| %>
<%= product.name %>
<% end %>
<% end %>
<% end %>
Although I'm not familiar with how pg search works, you could do something like this in your method.
It's a nice refactoring as well as it avoids checking for existence and making decisions on params (code smell)
def self.text_search(query = "")
search(query)
end
As I said, not sure how pg_search works. Maybe when you browse for nothing, it returns all records. If that's the case, you can just have it return an empty array. Something like this would do
def self.text_search(query)
return [] if query.nil?
search(query)
end

Complex Rendering in Rails

For about a week now I have been trying to get a view to render. I have an application that needs to be able to export collections so I decided to use a line partial that renders as a .txt and .csv in the web browser. So far so good in terms of getting the entire collection to render (line by line). However, I am having trouble getting certain collection objects (in this case products) to duplicate themselves based on a certain attribute (size element).
The code below is kind of where I am stuck at now
Controller
class PexportController < ApplicationController
layout 'csv'
def index
end
def show
#feed_template = params[:id]
#products = Product.find :all
#products.each do |product|
unless product.size.nil? || product.size.empty? || product.size.kind_of?(Fixnum)
#products << new_products_for(product)
end
end
respond_to do |format|
format.html
format.text
end
end
private
def new_products_for(product = {})
products = Array.new
product.size.each do |p|
products << Product.new(p.attributes)
end
products
end
end
View
<%= render partial: 'pexport/p', collection: #products %>
Partial
<%= p.sku %> <%= p.name %> <%= p.price %> ......
I basically just need to get the controller method to work. The attribute :size that I am using for the line duplicator is simply an array like so [1,2,3]. And I would like products that contain this size attribute to duplicate themselves based on the number of sizes in their size array. I am not even sure if I am going about it the right away but it has gotten to that point where I am going in circles so I figured I would post it.
Alternative answer: is there some reason you need to duplicate the entire object in the controller? You could simplify things by just doing something like this in your view:
<% if p.size.is_a?(Array) %>
<% p.size.each do |s| %>
<%= p.sku %> <%= p.name %> <%= p.price %> <%= s %>
<% end %>
<% else %>
<%= p.sku %> <%= p.name %> <%= p.price %> <%= p.size %>
<% end %>
Or something to that effect.
If I understand what you're doing, you have a list of products, but some of those product entries should be displayed as more than one product if they have more than one size. Assuming that's correct, your logic is a bit off: new_products_for is returning an array which is being added as a single element at the end of your #products array. So your partial won't know how to deal with it. You could try something like this:
#my_products = Product.find :all
#products = []
#my_products.each do |p|
if p.size.blank? || p.size.kind_of?(Fixnum)
#products << p
else
#products += new_products_for(p)
end
end
Also, I suggest you make the Product.new line more explicit:
products << Product.new(:sku => p.sku, :name => p.name, ...)
p.attributes will give you all the attributes of the model, including id, created_at, updated_at which may interfere with what you're doing.

Ruby/Rails Simple search form and white spaces

I've implemented a "simple search form" (railscasts #37) in my app, but I wonder how:
1.) I cannot display any results if the keywords field is empty, or if the index page is loaded (I've tried search != "". Maybe there is a better way)
2.) I can add a function which avoid multiple white spaces in the search. (if users wrote something like "benoit+++" or "++benoit" in the search box, it should display results)
I don't want to use thinking sphinx as I would deploy on heroku
Here is the code:
In my user model (user.rb)
def self.search(search)
if search and search != ""
find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
end
In my view (views/users/index.html.erb)
<% form_tag users_path, :method => 'get' do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
<% end %>
<% if #users and not #users.empty? %>
<% #users.each do |user| %>
<p><%= link_to "#{user.name}", user %></p>
.
.
.
<% end %>
<% end %>
and in my controller ( users_controller.rb)
def index
#users = User.search(params[:search])
end
Thanks for any help or ressources!!
I would change the search method:
def self.search(search)
search.blank? ? [] : all(:conditions => ['name LIKE ?', "%#{search.strip}%"])
end
something.blank? returns true if something is nil or blank.
something.strip removes all the spaces at the beginning or end of a string. If name could be made of more than 1 word and you wanted to prevent from having more than one space between the words, you could do search.strip.squeeze(" ")
Oh, I don't think you need the if #users && !#users.empty? clause in your view now.

Resources