I followed a tutorial on setting up a search box and got it to work on exact phrase searches. I want to make it search for results that have all keywords being searched for.
For example, a search for "Red Necklace" should return a product that is called "Red Chain Necklace" but should not return "Red Earrings".
I've looked at couple railscasts on gems like searchlogic and ransack but they seem like too much for what I'm trying to do.
#model code
def self.search(query)
where("description like ? or name like ?", "%#{query}%", "%#{query}%")
end
#controller code
def search
#listings = Listing.search(params[:search])
end
#view
<%= form_tag(search_path, :method => "get", id: "search-form", class:"navbar-form navbar-right") do %>
<%= text_field_tag :search, params[:search], placeholder: "Search by color or style...", class:"form-control search-form" %>
<button type="submit" class="btn btn-default btn-md"><span class="glyphicon glyphicon-search"></span></button>
<% end %>
I read some other answers on SO that mention the .split method. I tried it out in a couple ways but couldn't get it to work.
Suppose,
#products = Product.all
search_query = "Red Necklace"
search_query = "Red Necklace".split(" ")
// now the search_query becomes ["Red", "Necklace"]
Now, search those values in every product for finding the correct product.
result = []
#products.each do |p|
c = 0
search_query.each do |q|
if p.name.include?(q)
c +=1
end
end
if c == search_query.length
result << p
end
end
Its a slow process and complexity is high.
Full Text Search
What you're looking for is full text search, which is relatively difficult to achieve using standard MYSQL.
The problem you have is that the db engines are not specifically designed to be "search" engines. They are meant as a way to store & organize data. As such, the "full text" search facilities of these systems is merely based on the query interface.
I'm sure someone more experienced & knowledgeable than I can explain the specifics of this; I'll just say that in order to create the search functionalit you want, you'll want to use one of the third party search applications:
Sunspot Solr
ElasticSearch
Sphinx
The difference here is that all of these recommendations index your data, allowing much more in-depth, efficient & specific searching. Although I've not used them specifically, I would highly recommend using one of the above.
--
Solr
You'll want to check out this Railscast on how Solr works:
That's as much help I can give I'm afraid. I know you don't want this, but it's the best way for you to achieve the functionality you desire
Related
I am still a beginner in ruby on rails and I'm trying to create a simple search option for a website that I'm developing.
I have number of models such as Sundries, Curry and Starter.
My search works fine if I have one model but how do I search all models title or name?
I have added following method to each of the models and tried to display results in home page. but no luck!
def self.search(search)
where("LOWER(title) LIKE ?", "%#{search.downcase}%")
#where("content LIKE ?", "%#{search}%")
end
Can someone please help me figure this out with an example please?
Thank you.
You can add ActiveRecord_Relations together, and it will give you a simple array
#results = Sundries.search(search_term) + Curry.search(search_term) + Starter.search(search_term)
In the view...
<% #results.each do |result| %>
<%= "#{result.title} part of our fine #{result.class.name} choices" %>
<% end %>
Answering for anyone looking at this in 2019+... scenic is the gem you want to use (as long as your database is postgres).
There are several approaches how you can implement this. You can use advanced search engines such as ElasticSearch or Sphinx. Or you can use (for example) pg_search gem in case you are using Postgresql as your DataBase.
You can find RailsCasts for each of these approaches (some of them are probably for subscribers only).
As soon as you learning Rails, I would recommend to try out pg_search at first and avoid using search engines. Because it can be tricky sometimes for beginners. You can get to them later than you will have more data in your DB, or you would need to improve your skills. Try to make working solution in the first place and then improve it.
You can use this ransack to implement search functionality.
In your view side
<%= form_tag search_path, method: :get do %>
<%= text_field_tag :q, nil %>
<%= end %>
and in your controller action method,
q = params[:q]
#sunderies = Sundries.search(title_cont: q).result
#curry = Curry.search(title_cont: q).result
#starter = Starter.search(title_cont: q).result
#total_results = #sunderies + #curry + #starter
My party registry Rails 3 app needs a search function for visitors to search a partyname and then be able to click on the party and go to the show page of that party. Must be very simple ajax list that pops up without reloading etc.
The app is almost done and runs off a sqlight3 database.
Any suggestions - tried all the RailsCasts ones and nothing fits right 100%.
Thanks in advance.
I think you want two different things.
1) To create a simple search you can do something like this.
2) To autocomplete while typing (partyname for example) you can use the autocomplete gem.
You must decide which approach you want to follow.....
I hope if helps in some way...
EDIT - to show how to implement the simple search.
let's say you have a model called Party
your form (index page for example):
...
<%= form_tag parties_path, method: :get do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", name: nil %>
<% end %>
...
#display results
<% #parties.each do |party| %>
...
<% end %>
model Party:
...
def self.search(search)
# if search is not empty
if search
find(:all, :conditions => ["partyname LIKE ?", "%#{search}%"])
# if search is empty return all
else
find(:all)
end
end
...
controle parties_controller:
#parties = Party.search(params[:search])
Try smart_search gem
gem install smart_search
Does everything that needs to be done to make your model searchable!
I'm creating an application that tracks users and achievements (think, xbox live, etc.) These tables are linked via a join table. I would like to have a search form on my index that lets users type in a users name and a new page is loaded with a list of all achievements that user has earned. I'm not entirely sure how to set up this search form, on the index, to actually search the user table and return the results on a new page. Any help would be greatly appreciated. If you require more information then I'll be happy to provide it.
Here's a bit of skeleton code to get you started based off what I think you need from what you have said. I hope this is useful.
For the search bit you could do something like this in your index view:
<%= form_for User.new, :url => "search" do |f| %>
<%= f.label :name %>
<%- f.text_field :name %>
<%- end %>
In your controller:
def search
q = params[:user][:name]
#users = User.find(:all, :conditions => ["name LIKE %?%",q])
end
and in your search view:
<%-#users.each do |user| %>
Name: <%=user.name %>
<%- user.achievements.each do |achievement| %>
<%= achievement.name %>
<%- end %>
<%- end %>
You would, of course, need to ensure the users and achievement models are correctly linked:
class User << ActiveRecord::Base
has_many :achievements
end
There are plenty of tutorials and things about this e.g.:
http://blog.devinterface.com/2010/05/how-to-model-a-custom-search-form-in-rails/
Look the thing is every basic explanation in Rails3 starting with the Initial Tutorial provided by them explains you how to setup a new Controller/Model. The example was only one of thousands explaining the same problem.
It is a very broad range of different things you can do to achieve this. Basically you have to put some code in the controller:
which handles the search (including the activerecord stuff or whichever technique you use to access your model)
which sets some variables necessary for the search form
Setup two routes etc... Its to broad and completely covered even by the basic official rails3 tutorial.
Here is an application based on searchlogic is very useful and you can search by whatever you want
https://github.com/railscasts/176-searchlogic
You may want to check out the Ransack gem. https://github.com/activerecord-hackery/ransack
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.
I'm having a tough time deciding how to refactor this method in my controller. The idea is that (in this case) it graphs the users that joined (or were created) in the past two weeks.
You might be wondering why I did the #graph_limit thing, and that is because I always want the day that has the most results to be the tallest bar on my bar chart (which in the view are just created with css by making the height of the <div> using css).
Basically I want to dry it up and... ya know just about improve this method as much as possible:
# Controller
def index
two_weeks_ago = Date.today - 13.days
#users_graphed = User.count(:conditions=>["created_at >= ?", two_weeks_ago], :order => 'DATE(created_at) DESC', :group => ["DATE(created_at)"])
two_weeks_ago.upto(Date.today) do |day|
#graph_limit = 100/#users_graphed.values.max.to_f
#users_graphed[day.to_s] ||= 0
end
end
Also I should mention, that you guys are probably going to rip my code to shreds... so I'm bracing for the outcome.
# View
<% #users_graphed.sort.reverse.each do |user| %>
<li>
<% content_tag :div, :style => "height: #{number_with_precision(user[1] * #graph_limit, :precision => 2)}px; ", :class => "stat_bar" do %>
<%= content_tag(:span, user[1]) unless user[1] == 0 %>
<% end %>
</li>
<% end %>
Ultimately and what my real goal here is to put this into my application controller and be able to chart any models by it's create_at times. maybe something like tasks.chart_by(2.weeks). How would you guys get this separated out into something I can use throughout the whole app?
I agree with Joseph that your controller here is doing a lot of work that should be done in the model. Any time you're specifying multiple find parameters in your controller, ask yourself whether or not that should be in your model instead.
You're doing a lot of iterating here that seems needless. Firstly, You shouldn't be calculating #graph_limit inside the loop. You're recalculating it 14 times, but the value is going to be the same every time. Do that outside the loop.
Secondly, that sort.reverse in your view sticks out. You're already sorting in your finder (:order => 'DATE(created_at) DESC'), and then you're sorting again in your view and then reversing it? You should instead be asking the database for the values in the final order you want them. Then to make your zero-filling code work you can just reverse it, doing Date.today.downto(two_weeks_ago) instead of upto.
I would say that you should really be doing this all in SQL, but unfortunately (as perhaps you've discovered) MySQL makes it difficult to fill in missing days without creating a calendar table to join against.
Thanks Jordan, per your ideas (which were really great by the way) I've created a helper that is like such:
def graph_by_time(klass, time_ago)
time_range_start = Date.today - time_ago
#elements_graphed = klass.count(:conditions=>["created_at >= ?", time_range_start], :order => 'DATE(created_at) DESC', :group => ["DATE(created_at)"])
#graph_limit = 100/#elements_graphed.values.max.to_f
time_range_start.upto(Date.today) do |element|
#elements_graphed[element.to_s] ||= 0
end
return #elements_graphed.sort.reverse
end
The biggest issue here is zero filling the days which have no records associated with them, your method of switching to from upto to downto didnt work and only returned the records which did result in a integer other than zero.