rails search form that works on all pages of application - ruby-on-rails

I have a search form which appears on all pages because I want someone to be able to search and be redirected to search results regardless of where they are on the site. To achieve this i placed the form in a partial which i included in the application layout. It looks like this
<form class="form-search center">
<%=form_tag search_url, method: :get do%>
<%=text_field_tag :query, params[:query] ,{:class=>"input-xxlarge search-query"}%>
<button type="submit" class="btn">Search</button>
<%end%>
</form>
I have created a controller called SearchResults with an index action to display the results.
The named route looks like this
match '/search', to: 'search_results#index'
The search works perfectly fine on the search page, but cannot work anywhere else.My index action looks like this
class SearchResultsController < ApplicationController
def index
#restaurants = Restaurant.text_search(params[:query]).page(params[:page]).per_page(3)
end
end
I want to be able to redirect to this action whenever i carry out a search regardless of where i am in the application.The text_search method is defined in the restaurant model like so
def self.text_search(query)
if query.present?
where("restaurant_name ilike :q or description ilike :q", q: "%#{query}%")
else
scoped
end
It doesn't work in that nothing happens when i search but if i go to the search page it returns the results.
I have noticed something interesting. When I search from the home page for a term like eats. The url looks like this localhost:3000/?utf8=✓&query=eats and when I search from the real search page which works perfectly it looks like this localhost:3000/search?utf8=✓&query=eats. How can i get it point to the latter url regardless of where am searching from?

Its because you have a nested form.
<form class="form-search center">
<%=form_tag search_path do%>
Get rid of the form you have in raw HTML and just let Rails generate it via the helper in the 2nd line.

Why don't you do a proper routing entry for your search controller?
resources :search_results, :only => :index
And then in your search form you let it POST to searches_path. Then you don't have to fiddle around with this :match routing.
Edit
I also noticed that you GET your form. Technically it doesn't really matter, but it's not very clean. So maybe, you could do something like this:
resources :searches_results do
post :query
end
And then in your controller you simply have the query function.
Edit 2
And I think the real problem here is that you are having is that you have a form tag in a form tag. The first form tag gets evaluated and it probably points to /. Therefore it works in the controller itself, but not anywhere else.

for my case i use somethig like this: in view
<%= form_tag url_for(:controller => '/searchresults', :action => 'index') , :method => 'get' do %>
<%= text_field_tag :query, params[:query] ,{:class=>"input-xxlarge search-query"} %>
<%= submit_tag 'search' %>
<% end %>
and in model
q = "%#{params[:query]}%"
where("restaurant_name LIKE ? or description LIKE ?", q, q)

Related

How do I set my rails app up so that I can click a letter and see only the entries starting with that letter?

My rails app basically displays a dictionary of sorts, which is stored in a database. I've set up a basic rails app with scaffold to display this on a webpage, but I can't for the life of me figure out how to set this next bit up. Basically I want a row of the 26 alphabetical letters, and when you click on a letter (say 'A'), I only want to see the dictionary entries of that letter.
My index.html.erb file:
<% for char in 'A'..'Z' %>
<%= link_to( "#{char}", "/words/lettersearch", :id => "#{char}") %>
<% end %>
my words_controller.rb file method for doing this:
def lettersearch
#word = Word.find(:all, :conditions => ["word LIKE ?", "#{params[:word]}%"])
end
It then outputs the #word to another page.
My problem is that it just outputs the entire dictionary again, no matter what letter I click on the index page. I know it's to do with the routing, as it never seems to actually run the 'lettersearch' method - it's always trying to run through the 'Show' method that's defined by default earlier in the controller.
Anyone able to give me a quick hand with how to route this thing through? I'm pretty new to rails and I don't understand the workings of link_to very well at all.
routes.rb:
Dictionary::Application.routes.draw do
resources :words do
post 'search', :on => :collection
post 'lettersearch', :on => :collection
end
#Rest of routes.rb still commented apart from
match ':controller(/:action(/:id))(.:format)'
You are passing in a param called :id but in your controller you use a param called :word
Also, update your code to use newer syntax
World.where(["word like ?", "#{params[:id]}%"])
And your view code can be cleaned as well
<% for char in 'A'..'Z' %>
<%= link_to char, "/words/lettersearch", :id => char %>
<% end %>
Your routes file only has a POST route to letter search, but a link_to is a GET request. So whats happening is the GET request is hitting /words/:id via GET which is the show action by default, and the params[:id] inside that request will be "lettersearch"
You could run the search in your index. I think that might be what you want to do. In your index controller you could put:
#orders = Order.lettersearch(params[:word])
and then in your model:
def lettersearch(word)
if lettersearch
#word = Word.find(:all, :conditions => ["word LIKE ?", "#{word}%"])
else
all
end
end

ruby on rails search form

I'm new to RoR and I've managed to make a basic search form but keep getting errors when trying to expand the search tags (name).. I have a model with various data (location, website, email, telephone) and was wondering how I can add these to my current search code.
/models/ciir.rb
def self.search(search)
if search
find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
else
find(:all)
end
end
static_pages_controller.rb
def home
#ciirs = Ciir.search(params[:search])
end
/home.html.erb
<%= form_tag ciirs_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag " Search Database Records ", :name => nil %>
</p>
<% end %>
When clicking the submit button (no search terms) the url is:
ciirs?utf8=✓&search=
but when modifying the name condition to something like 'website' the url changes to
ciirs?utf8=✓&search=&commit=+Search+Database+Records+ –
Since you mentioned you are new to RoR, I must share the way I learned RoR was reading, using and analyzing one issue at a time. I would suggest you to take a look at following points one at a time and try & learn how RoR treats them and how these fit your question:
How form_tag works?
How text_field_tag works?
Once you have understood form_tag, difference between text_field_tag and f.text_field?
How params objects are created, and it uses names of form controls?
How and when to use GET and/or POST form methods? Inadvertently, what are different types of method and when to use them?
How URL are used in the form_tag and what components are they made of?
Sprinkle a bit of knowledge of Ruby language by learning between Arrays and Hashes? In fact, learn Ruby as much as you can.
Answering your question,
/home.html.erb
<%= form_tag "/static_pages/home", :method => 'post' do %>
<p>
<%= text_field_tag "search[name]", params.has_key?("search") && params[:search].has_key?("name") ? params[:search][:name] : "" %>
<%= submit_tag " Search Database Records " %>
</p>
<% end %>
/models/ciir.rb
def self.search(search)
if search
find(:all, :conditions => ["name LIKE '%?%'", search[:name]])
else
find(:all)
end
end
So I modified your form, and told RoR about search params containing data for name.
params is a Hash (which is a key-value pair) having key named search, which further is a Hash having key named name.
The same principle is followed in the model code. We passed the Hash of key search to the function and in there, used the value of key named name.
I also updated the url in form_tag, to point it to home action of your controller. Assuming that you have added it to your routes.rb file, it usually follows the pattern controller_name/action_name or the function name action_name_controller_name_path or action_name_controller_name_url. Run rake routes command at your root directory to list out all paths in your application.
Also note, I used POST method instead of original GET. You may wish to use GET here, so please change it back.
I hope this works.
I found no error in your code. the url changed to ciirs?utf8=✓&search=&commit=+Search+Database+Records+ is normal. submit_tag generates a button named "commit" defaultly, it will be parsed in the params. I see you add :name => nil , it will fix the problem, the other part of your code needn't to be modified. I copied your code and tested it, it ran smoothly.

using Bootstrap Navbar Search with form_tag to redirect to resource index with search params

I'm trying to put a quick keyword search in my navbar, using Bootstrap's Navbar Search component. Currently this is using a form_tag as follows
<form class="navbar-search pull-left">
<%= form_tag(recipes_path, :method => :get) do %>
<%= text_field_tag :keywords, nil,
{:class => "search-query", :placeholder => "recipes quick search"} %>
<%= hidden_field_tag :use_keywords, "true" %>
<%= hidden_field_tag :wide_search, "true" %>
<% end %>
</form>
This is for a recipe lookup. I'm using the form to (try to) get keywords, which will be passed as params to the search, which resides in the recipes index action.
def index
if params[:wide_search].present?
#search = Search.new
#search.use_keywords = params[:use_keywords]
#search.keywords = params[:keywords]
... (more params for other search types)
if params[:wide_search] == "true"
#recipes = #search.wide_search
elsif params[:wide_search] == "false"
#recipes = #search.narrow_search
end
#recipes = #recipes.paginate(:page => params[:page])
else # no params, just index all
#recipes = Recipe.paginate(:page => params[:page])
end
end
Note that "Search" is a ruby class. I was thinking of making it into a full-blown resource so I could create and view old searches (maybe they could be looked at to offer suggested searches based on past history, etc), but decided against it. I still dunno if that was a good idea or not. If it was an actual resource, it could have RESTful actions and maybe save some problems. This is not my actual problem, but does anyone have suggestions for this?
Sorry, back to the actual problem -- From the root page or wherever, I would like to be able to type in keywords, press the enter key (within the search bar) and have it redirect to the Recipe Index with the params needed so it can run the search and display the results.
Right now, if I go to the index page and do this, it works fine. BUT, if I'm in any other page (like the root page, or wherever) and try to type keywords and press enter, it just reloads the current page, although I do see the params in the URL. So it's not redirecting to Recipe Index. I must be missing something, but I'm not sure what. I'm kind of suspicious of the form_tag since there's no actual submit button. But then it works when I'm in the index page, so I dunno. Any suggestions appreciated!

Search query not showing up in URL in simple search app

I'm trying to build an app that searches twitter for images. Before I get there, I need to jump over the intimidating hurdle of constructing a working search field that feeds a value into a function.
In my index.html.erb file that's controlled by the Pages controller, I have this code:
<%= form_tag root_path ({:controller => "pages", :action => "search", :method => "get", :class => "grabTweets" }) do %>
<%= text_field_tag :tweets, params[:tweets] %>
<% end %>
In my Pages controller I have:
def search
def grabTweets
#tweet = Twitter.search(params[:tweets] + "[pic] "+" path.com/p/", :rpp => 3, :result_type => "recent").map do |status|
#tweet = "#{status.text}" #class = string
#urls = URI::extract(#tweet, "http") #returns an array of strings
end
end
end
Two problems:
My search query isn't being passed into the grabTweets function as proven by the URL after the search is performed:
http://localhost:3000/?action=search&class=grabTweets&method=get (the search query was the word "bridge"
What's wrong with my code that the search query isn't performing correctly.
Should my code that's in the controller be placed in def home or def search, given that I want the search results to show up in the root_path and don't intend to change pages?
Thanks in advance for the help! I'm thoroughly stumped.
I think you need to read a book introducting Rails, as there seem to be many fundamentals you are missing.
You have an action for the page you are on (which you seem to call 'home') and an action for the search results. Your form needs to call the url for the search action. That would look like this:
<%= form_tag({:controller => "pages", :action => "search"}, {:method => "get", :class => "grabTweets"}) do %>
...
(See the API for more details on the form_tag method)
In that state, it will call the search action (which should not have another method called grabTweets nested inside it - that makes no sense) which will then render search.html.erb (presumably a page of search results).
In your routes file, you need a route for both home and search.
If you want the page to update without refreshing the page, then you need to use :remote => true on the form and handle the response using AJAX.
If you want the two pages to be the same, but with one containing results, then either move the search functionality into the home action and only call it if params[:tweets] is populated, or just have both actions render the same template.
I would recommend reading through the Rendering Guide and the Controllers Guide to learn more.

ransack search form in header partial: No Ransack::Search object was provided to search_form_for

First of all, I'm new to RoR, so the answer may be obvious, in which case I apologize. I've looked around and haven't found anything that helps.
I'm trying to have a search form at the header of every web page on my app that will search through the names of all my "buckets". Here is the relevant code:
In app/views/layouts/_header.html.erb (within a nav bar):
<% search_form_for #q do |f| %>
<%= f.label :name_cont %>
<%= f.text_field :name_cont %>
<%= f.submit %>
<% end %>
In app/controllers/buckets_controller.rb:
def index
unless params[:q].blank?
#q = Bucket.search(params[:q])
#buckets = #q.result.paginate(:page => params[:page])
else
#buckets = Bucket.find(:all, :limit => 5).paginate(:page => params[:page])
end
end
I understand the last part isn't that great: what I'm trying to do is if I'm just accessing the bucket index page (not by searching), i display the 5 most recently created buckets. When I search for something in the header form, I access the index page but only show the buckets that hit the search. (would a better way to handle it to have a search page separate from my index page?)
I found this issue which is pretty much identical, but I still don't see how I handle #q if every page is going to have the form on it--surely I don't have to alter every controller's every action?
Sorry in advance for any frustration my noobishness my cause you!
As others have said, you need to utilize the ApplicationController's before_filter. Though ernie himself seems not to recommend this, the implementation is simple.
First, use the advanced Ransack options to set your path for your search thusly
#config/routes.rb
resources :buckets do
collection do
match 'search' => 'buckets#search', via: [:get, :post], as: :search
end
end
Second, update your BucketsController to include the following custom action:
#controllers/buckets_controller.rb
def search
index
render :index
end
Nothing yet out of the ordinary. If you currently try to search you will get the error from your original question. Your definition of the variable q is correctly implemented, but you will have to move it to the ApplicationController like so:
#controllers/application_controller.rb
before_filter :set_global_search_variable
def set_global_search_variable
#q = Bucket.search(params[:q])
end
Finally, update your search form to pass in the correct search options
#layouts/_header.html.erb
<% search_form_for #q, url: search_buckets_path, html: { method: :post } do |f| %>
<%= f.label :name_cont %>
<%= f.text_field :name_cont %>
<%= f.submit %>
<% end %>
No, you do not need to edit all your controllers.
You can use ApplicationController for all your "common" controller needs. Read up on it in the guides http://guides.rubyonrails.org/action_controller_overview.html and the API docs http://api.rubyonrails.org/classes/ActionController/Base.html
The key here is, when you generated your new rails app, you'll notice it created the file .../app/controllers/action_controller.rb and that class derives from ActionController::Base. Then, if you again use the rails generator to create a controller for your app, you'll notice your new controller class derives from ApplicationController (not ::Base). That means that the application_controller.rb is the parent controller class for your app. That means everything in it is available to all your app controllers. It's easy to abuse, so be judicious.
Looks like this is not possible. This is a comment from Ernie the gem author.
You'd have to handle the Ransack-required stuff in a before_filter or
(ick) in the view partial itself. If you're putting a search field on
every single part of the site, I'd recommend you strongly consider
whether ransack is the right tool for the job, as well. You might want
some sort of inverted index search setup like sphinx, solr, etc.
https://github.com/ernie/ransack/issues/3

Resources