Simple search form is not working in rails - ruby-on-rails

I'm following Railscast: http://railscasts.com/episodes/37-simple-search-form?autoplay=true
The result shows well in my implementation. But because I have first_name and last_name columns instead of just "name" as in the example above, I need a way to search for both no matter what the search term is. How can I do this? Right now only first name search works.
user.rb
def self.search(search)
if search
where('first_name LIKE :search OR last_name LIKE :search', search: "%#{search}%")
else
all
end
end
people_controller, index function:
#users = User.search(params[:search])
index.html.erb (for people controller):
<%= form_tag people_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag("Search users", first_name: nil, last_name: nil) %>
</p>
<% end %>
<ul>
<% #users.each do |user| %>
<li>
<%= link_to profiles_path(user_id: user.id) do %>
<%= user.first_name %>
<%= user.last_name %>
<% end %>
</li>
<% end %>
</ul>
UPDATE:
So this is weird. I have 4 users. For the first 3, only first name search works. Last name or full name (or partial name) doesn't. For the last user, only last name search works.
...what could be going on? Just made three more users and tested. The first new user got searched only by first name. The second new user got searched by only last name. His first name is part of the last name of 3rd user, and that 3rd original user name was returned when searched by that new user's first name (...why? didn't work like this before; partial name search doesn't work for other users). And third user's last name only was searched.
UPDATE:
OK, didn't do anything. But now the first original's user gets searched by either last name or first name (only first name before). WHY? Second original user as well. And partial search for two users works now. WHY? And the last new user whose last name (only) was searchable is now not searchable by any. WHY?
And tried it again just now and returned to previous, searchable by first name only, no partial search, etc. Why is this keep changing? How can I make the search term simply search for either first name or last name or both?
UPDATE:
I got the answer (to the above, not in general). The search is CASE-SENSITIVE. Now my question is: how can I make it non-case-sensitive and have the search term that includes both first name and last name (eg "Tom Paulson") work? (right now only searching for either works)
UPDATE:
So I solved case sensitivity by changing LIKE to ILIKE. I'm using Postgres.
If you could help with searching for both first name and last name, I'd appreciate it!
UPDATE:
So I'm now using this to search for both or either first name and last name. But now partial search does not work. Is there a way to make that work here as well?
where("first_name ilike :search or last_name ilike :search or first_name || ' ' || last_name ilike :search", search: "%#{search}")
UPDATE:
Solved it by adding % to %#{search}
%#{search}%
The case seems resolved. Thank you! I will maybe post an answer later.

UPDATE:
ooh, you wanted to search in both columns.
one way is to use 'concat'.
assuming you put a space in between first and last name:
where("CONCAT(first_name, ' ', last_name ) ILIKE ?","%#{search}%")
FIRST ANSWER:
def self.search(search)
if search
buff=search.downcase
where('lower(first_name) LIKE ? OR lower(last_name) LIKE ?', "%#{buff}%", "%#{buff}%")
should be working.
or ILIKE if you prefer.
where('first_name ILIKE ? OR last_name ILIKE ?', "%#{search}%", "%#{search}%")
can you check the value of 'params[:search]' if it is not nil?

Related

How do I use a button to update the order of a filtered category?

I am new to Rails, but slowly making progress. I can't quite wrap my head around how to achieve my next task.
I have a controller (IdeasController) with an index that looks like this:
def index
if params[:round].blank? && params[:challenge].blank?
#ideas = Idea.all.order(params[:sort])
# #ideas = Idea.all.order(created_at: :desc, cached_votes_up: :desc)
end
if params[:round].present?
#round_id = Round.find_by(name: params[:round]).id
#ideas = Idea.where(round_id: #round_id).order("created_at DESC")
end
if params[:challenge].present?
#challenge_id = Challenge.find_by(name: params[:challenge]).id
#ideas = Idea.where(challenge_id: #challenge_id).order("created_at DESC")
end
end
I am updating the view and filtering by category with the above :round and :challenge with the code below in my index.html.erb:
<%= link_to "All", ideas_path %>
<% Round.all.each do |round| %>
<%= link_to round.name, ideas_path(round: round.name) %>
<% end %>
<% Challenge.all.each do |challenge| %>
<%= link_to challenge.name, ideas_path(challenge: challenge.name) %>
<% end %>
Now, my problem is that I want to create a button that orders by created_at DESC or ASC. I want the button to essentially be a toggle. I also want another button to order by cached_weighted_average DESC or ASC. This is from acts_as_votable so I can sort by vote counts.
The problem I am running into is that I can create a link or button that orders by created_at or cached_weighted_average, but it replaces all of the URL that was previously filtered by :round or :challenge. For example, if a user clicks "Round 1" and sees all ideas marked for "Round 1" and then they click the link to order by cached_weighted_average, the URL replaces:
/ideas?round=Round+1
With this:
/ideas?sort=cached_weighted_average+ASC
What I want is:
/ideas?round=Round+1&?sort=cached_weighted_average+ASC
I know this is a very new question, but everything I have tried has failed so far. It feels like I am missing something very easy. What I noticed I can do easily is inside the controller I can do something like:
if params[:round].present?
#round_id = Round.find_by(name: params[:round]).id
#ideas = Idea.where(round_id: #round_id).order("cached_weighted_average DESC")
end
Which is perfect. This button just needs to switch between cached_weighted_average DESC and created_at DESC.
Any help is appreciated, thanks.
passing multiple parameters is one way to handle:
<%= link_to object.name, object_path(first: something, second: something_else) %>
then alter your conditionals to contemplate presence of multiple params.
to differentiate between round and challenge when attempting to allow the user to choose how they'd like to sort you could use the same name and then pass it different values.
something like:
params["round_or_challenge"]
this would change your conditional to something like:
if params["round_or_challenge"] == "round" && params["asc_or_desc"] == "asc"
# query
elsif params["round_or_challenge"] == "challenge"
# query
end
or whatever. it's basically the same...just pass the values you need. you can also pass the existing parameters from the view the same way you access them in the controller.
Thanks for the response, #toddmetheny. I didn't implement your solution, but your solution helped me understand passing multiple parameters a bit more.
I ended up creating a helper, sortable. I also used the url_for to append at the end of whatever the current URL might be. I liked this approach because it meant I could sort on any parameter. I'm not sure that it's the best solution, but it works.
def sortable (name, sort)
link_to name, url_for(params.merge(sort: sort))
end

simple rails search form not working

I have a very simple, typical search form in rails. Input a string, and it checks a column for that model if any strings match it. A few weeks ago it was working just fine. I came back today, and suddenly doesn't work.
Here is my code. My search form:
<%= form_tag("/search/products", method: "get") do %>
<%= label_tag(:q, "Search for:") %>
<%= text_field_tag(:q) %>
<%= submit_tag("Search") %>
<% end %>
My Controller:
def search
term = params[:q]
puts "the term is #{term}"
#resultats = Product.search_products(term)
end
In my model, the search_products method:
def self.search_products(search_term)
if search_term == ""
return []
else
where("name LIKE ?", "%#{search_term}")
end
end
in the controller code, the puts "the term is #{term} prints the correct term every time. So I know that is being picked up correctly. just, when i search for something, it doesn't return the correct results. Here is a screenshot from my terminal:
"Les résultats sont" in the terminal means "the results are..." and then empty, because it returns nothing. What could be wrong here?
Your code currently searches for LIKE '%term' (string must end in term)
You probably need to have it search for LIKE '%term%' (string must contain term)
Just add a %:
where("name LIKE ?", "%#{search_term}%")
Why don't you do lower(?) and search_term.downcase to make sure its not case sensitive

combine two search results ruby on rails

I am trying to have two search fields, that however end up combining the two results.
In one filed you can search for the location of a listing and in the other for a keyword, which will look for title and description of the listing.
When a location and keyword is entered, listings that match both the location and keyword should show. So if I enter San Francisco and Retail, only listings located in SF and with the description or title Retail should pop up.
Feng Chen suggested to do this in one query by the following:
self.where("location like ? and (title like ? or description like ?)", query, query)
However this does not show a result that matches both the location and the keyword(title, description).
Do I need to change something in my view or anywhere else?
Here is what I have listing.rb
def self.locsearch(search)
query = "%#{search}%"
if search
self.where("location like ? and (title like ? or description like ?)", query, query)
else
self.all
end
end
end
Static_pages_controller.rb
def home
#listings = #listings.locsearch(params[:search]) if params[:search].present?
home.html.erb
<%= form_tag findjobs_path, :controller => 'listings', :action => 'locsearch', :method => 'get' do %>
<p>
<%= text_field_tag :search, "location" %>
<%= text_field_tag :search, "keyword" %>
<%= submit_tag "search" %>
</p>
</div>
<% end %>
You need a descsearch method in your listing model and you need to do
# Right now you have #listings = #listings.locsearch(...)
# You need #listings = Listing.locsearch(...)
#listings = Listing.locsearch(params[:search][:location], params[:search][:keyword])
And in your listing model
def self.locsearch(location, keyword)
location = "%#{location}%"
keyword = "%#{keyword}%"
if !location.bllank? && !keyword.blank?
self.where("location like ? and (title like ? or description like ?)", location, keyword)
else
self.all
end
end
end
If you are using a postgres database, you could try to use the full text search feature to do the above. There is gem pg_search enter link description herewhich will allow you to do so easily. The overhead incurred would be trivial and would provide you greater flexibility in this search problem and any such other ones you might have to solve later.

Rails Search result issue

I am trying to create a search function in Rails 4. I have it implemented properly and it is displaying the result I want, however it is also returning and displaying the entire database query - All columns from table including password digest etc. I have done this before but haven't run into an issue like this. Would like to know if I am doing something wrong.
here is my controller:
def index
if params[:search]
#pro = Admin.search(params[:search])
else
#pro = Admin.all
end
end
Admin Model:
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
else
scoped
end
end
And here is my views:
<%= #pro.each do |ind| %>
<ul>
<li><%= ind.name %></li>
</ul>
<% end %>
in Chrome, I see the returned name of the individual from the search, as I would like, plus meta data such as id: 1, admin_id: 2, name "", email: "", password_digest: "" etc. in an array format. This is what's stumping me, not sure why it's displaying this.
When I inspect the page in chrome, the array is just pasted right under the tags.
It goes away when I remove the entire .each method on #pro. Any insight anyone can provide is appreciated.
The line in view should be <% #pro.each do |ind| %>. If you're doing <%= %> the result is the actual #pro array, which is why you're getting it pasted under the tags.

Display search query in results of basic search in Rails

I built a basic search form that queries one column in one table of my app. I followed episode 37 Railscast: http://railscasts.com/episodes/37-simple-search-form
Here's my problem. I want to display the search query that the user makes in the view that displays the search results. In my app, the search queries the zip code column of my profile model, and returns a list of profiles that contain the right zip code. On the top of the list of profiles returned from the search, I want it to say "Profiles located in [zip code that was queried]."
I'm sure I can do this because the queried zip code gets passed into the url displaying the results. So if the url can pick it up, there must be some way to display it in the view on the page as well. But I don't how.
Please keep in mind that I'm not using any search pluggins and I don't want to use any for now. This is my first app, so I don't want to add complexity where it's not needed.
Per Ryan's instructions in the Railscast, here's my setup:
PROFILES CONTROLLER
def index
#profiles = Profile.search(params[:search])
end
PROFILE MODEL
def self.search(search)
if search
find(:all, :conditions => ['zip LIKE ?', "%#{search}%"])
else
find(:all)
end
end
PROFILE/INDEX.HTML.ERB
<% form_tag ('/profiles', :method => :get) do %>
<%= text_field_tag :search, params[:search], :maxlength => 5 %>
<%= submit_tag "Go", :name => nil %>
<% end %>
The search itself is working perfectly, so that's not an issue. I just need to know how to display the queried zip code in the view displaying the results.
Thanks!
Just set it to an instance variable and use that.
def index
#search = params[:search]
#profiles = Profile.search(#search)
end
In your view, you can reference #search.
Also, as a friendly tip, please use an indent of 2 spaces for Rails code. It's the standard way to do it, and others who are reading your code will appreciate it.

Resources