I am using Ransack to add a simple search form on my homepage. I would like the results of the search to show on a different page, instead of on the homepage.
The HomeController has an index action with the #search variable set as follows
def index
#search = User.search(params[:q])
#users = #search.result
end
The view contains
<%= search_form_for #search do |f| %>
<fieldset>
<legend>User</legend>
<ul>
<li>
<%= f.label :first_name_or_last_name_cont %>
<%= f.text_field :first_name_or_last_name_cont %>
</li>
<li>
<%= f.label :email_cont %>
<%= f.text_field :email_cont %>
</li>
</ul>
</fieldset>
<fieldset>
<legend>User's Posts</legend>
<ul>
<li>
<%= f.label :posts_title_cont %>
<%= f.text_field :posts_title_cont %>
</li>
</ul>
</fieldset>
<%= f.submit %>
<% end %>
<%= render 'results' %>
How can I set up the controller so that I can use <%= render 'results' %> in a different view for a different action, say a search action? How can I do this so that when I submit the search form I am directed to a new page for the search action which displays the search results?
Great question! To answer your question, you can create a private method with a redirect_to a different page (that has <%=render 'results' %>) IF search params are passed in your HomeController.
class HomeController < ApplicationController
before_action :search
def index
#search = User.search(params[:q])
#users = #search.result
end
private
def search
if params[:q]
search_params = CGI::escapeHTML(params[:q])
redirect_to (url --> see below how to get the url)
end
end
end
However, if you want to start building out your app, you want your search results to display on that dedicated page, no matter where you are at in the app. I am pasting in a full answer from a small rails app. The code is only slightly different (form_tag instead of search_form_for), but I know it works, so hopefully it will help you.
Below, is a nav bar partial that is displayed across the app and then the relevant code for the home page and the ListingController index action. If search params are passed, then index.html.erb renders the #listings partial (_listing.html.erb) and nothing below the <% else %> tag on the home page.
_navigation.html.erb
<%= form_tag search_path, :method => :get do %>
<div class="form-group">
<%= text_field_tag :search, params[:search], class: "form-control", placeholder: "Search" %>
</div>
<%= submit_tag "Submit", :name => nil, :class => "btn btn-primary" %>
<% end %>
index.html.erb
<% if params[:search] %>
<h2>Search Results</h2>
<%= render #listings %>
<% else %>
...what usually shows up on my home page with no search results.
<% end %>
listings_controller
def index
#listings = Listing.search(params[:search])
end
routes.rb
get 'search' => "listings#search"
This works great. However, if I am in a different view/controller, like the one showing all the categories, and try to search, then it basically searches the current page. So, I added the following to the categories controller:
categories_controller
before_action :search
......
private
def search
if params[:search]
search_params = CGI::escapeHTML(params[:search])
redirect_to ("/listings?utf8=%E2%9C%93&search=#{search_params}")
end
end
BUT, for your specific app, to get the search to redirect to the home page and display the search results, first do a search on your home page and see what is generated in the url. Let's say I typed 'cheese' (/listings?utf8=%E2%9C%93&search=cheese). Notice the %E2%9C%93...you may not see this b/c this normally displays as a check in the url on your browser (http://unicode-search.net/unicode-namesearch.pl?term=mark)...so just paste it into text wrangler or stackoverflow text area to get the 'full url' like above. Then at the end of the url, just replace what you typed into the search box with #{search_params}.
This passes whatever was typed into the search box to your dedicated search results page (in my case index.html.erb)!
Here is some documentation on CGI escapeHTML (for security reasons): http://ruby-doc.org/stdlib-2.0/libdoc/cgi/rdoc/CGI.html#method-c-escapeHTML
Related
My question
With Ransack, when submit is clicked, is there a way to call a method before displaying the results on another page.
Summary
I have a page called manualPull that contains a single search_field:
<%= search_form_for #q do |f| %>
<div class="field">
<%= f.label :Username_cont, "Lookup" %>
<%= f.search_field :Username_cont %>
</div>
<div class="actions"><%= f.submit "Pull & Search"%></div>
<% end %>
Basically what I want to happen is when a user clicks on the submit button, we will send a call to the controller of another page (sessions_controller#manuallookupsession) to pull data from our database then show the results on that other page.
What I tried
I tried adding url: 'sessions_controller#manuallookupsession' to search_form_for :
<%= search_form_for #q do |f|, url: 'sessions_controller#search' %>
<div class="field">
<%= f.label :Username_cont, "Lookup" %>
<%= f.search_field :Username_cont %>
</div>
<div class="actions"><%= f.submit "Pull & Search"%></div>
<% end %>
I also added the following line to the sessions_controller before_action :index, only: [:search]
That almost worked in the sense that it would show the search results in the new page but it would not run the manuallookupsession method in the sessions_controller. The other weird behavior is that the manuallookupsession method would run every time I refresh the manualPull page but not when I clicked submit.
Update1:
session_controller
Here is the code for my session_controller:
class PppoeSessionsController < ApplicationController
before_action :index, only: [:search]
def index
#q = Session.ransack(params[:q])
#session = #q.result.order(:username).page params[:page]
#sessions_to_export = #q.result.order(:username).all
respond_to do |format|
format.html
format.csv { render text: #sessions_to_export.to_csv }
format.xlsx
end
end
end
def search
puts("TEST")
#username = params[ 'username' ]
#sessionsearch = Session.new
#sessiondetails = Session.new
if #username
#sessiondetails = #sessionsearch.pull_user(#username)
respond_with(#pppoe_session)
end
end
According your given informations, your before_action syntax it's a bit weird, can you replace it by this one:
before_action :search, only: [:index], if: -> { params[:username] }
In this way you should also remove your if statement inside your search method within the session_controller.
Here is what worked for me finally:
In my search_form_for I added a hidden field called search as follows:
<%= search_form_for #q, url: 'sessions_controller' do |f| %>
<div class="field">
<%= f.label :username_eq, "Lookup" %>
<%= f.search_field :username_eq %>
<%= hidden_field_tag "search", true %>
</div>
<div class="actions"><%= f.submit "Refresh & Search" %></div>
<% end %>
And in my sessions_controller I added the following check to my index class:
if params[:search] == "true" && params[:commit] == "Refresh & Search"
search #This is a call to a method
end
Furthermore in my search class I was able to retrieve the entered username from the URL (since it was a get request and not a post request) with the following code (you need to require 'cgi' at the start of the class):
url = request.original_fullpath.split("/").last
parameter_hash = CGI.parse(URI.parse(url).query)
#username = parameter_hash["q[username_eq]"][0].to_s
Thanks to #morissetcl for leading me to the correct answer in the comments of your last answer.
I wish there was a way to give you credits for it.
I have a Product (imovel) controller where the users can create his own Products (imovels). I am using devise for the authentication and the CRUD (create, Update, Delete) needs login. So for the clients be able to see the products and doesn't need a user, I created the Welcome controller where so it is the root.
In the Index of the Products I use Ransack to do the research in the table and works just fine. (very happy about it).
On the welcome controller I try to do the same thing, but when I submit the search the page gets redirect to the imovels#index.
Controller:
class WelcomeController < ApplicationController
def index
#q = Imovel.ransack(params[:q])
#imovel = #q.result(distinct: true)
end
end
View:
<div class="container text-center">
<%= search_form_for #q do |f| %>
# Search if the name field contains...
<%= f.label :descricao_cont %>
<%= f.search_field :descricao_cont %>
<%= f.submit "Pesquisar", class: "btn btn-primary" %>
<% end %>
</div>
Another thing that can be important in the index (imovels#index) there is a for in a tr and the information is filtered there:
Imovels Index
<tbody>
<% #imovels.each do |imovel| %>
<tr>
<td><%= imovel.id %></td>
<td><%= imovel.descricao %></td>
<% end %>
And in the welcome controller where I need the search, I used Divs:
Welcome Index
<% #imovels.each do |imovel| %>
<div class="card">
<div class="containerImovel">
<h4><b><%= imovel.descricao %></b></h4>
<p><%= imovel.cidade %> - <%= imovel.bairro.nome %> </p>
</div>
</div>
<% end %>
How can I do the search on the divs of welcome controller? Ransack is the better option for it? It is possible to search in the has_many :through association?
Add a path for it in your routes.rb
resources :imovel do
collection do
match 'search' => 'welcome#search', via: [:get, :post], as: :search
end
end
and then add a new controller action to WelcomeController
def search
index
render :index
end
and afterwards modify the search form like so
<%= search_form_for #q, url: search_imovel_path, html: { method: :post } do |f| %>
Be sure to recheck the naming/variables as I'm not completely familiar with your app
I have been trying to implement the Ransack search gem into a project I am currently working on. I am pretty sure that I have it set up correctly. I want to be able to search profiles and have placed my code in the profiles controller like so:
def index
#q = Profile.search(params[:q])
#profile = #q.result(distinct: true)
#profiles = Profile.all
end
And the profile index.html.erb file like so:
<%= search_form_for #q do |f| %>
<div class="field">
<%= f.label :first_name_cont, "Name Contains" %>
<%= f.search_field :first_name_cont %>
</div>
<div class="actions"><%= f.submit "Search" %></div>
<% end %>
It does at the least appear to be attempting to search database correctly but just wont render any results on screen. It might be something obvious I am just not seeing. Any help is greatly appreciated.
Try a set up like this in your controller and view:
#profile controller
def index
#search = Profile.search(params[:q])
#profiles = #search.result(distinct: true)
end
#profile index
<%= search_form_for #search do |f| %>
<%= f.label :first_name_cont, "name in profile" %><br>
<%= f.submit "Search", class:"btn btn-info btn-block" %>
<% end %>
<% #profiles.each do |profile| %>
<%= profile.name %>
<% end %>
Is the problem when you try to access #profile or just is it with knowing how to display results? If the latter, right now they are being stored in #profile so you need to loop through them and choose what you want to show from each profile instance.
From when I've used this gem it seems it defaults to the index page of the given class (so in your case, the profile index page). So you can either:
Just let the results list below the search form you shared above.
Move the search bar to something like a homepages controller so when a search is made it'll go to the profile index page and only show the results.
Now I can search only from videos page, How to add search from any page ot the site?
When I want to search from another controller search doesn't redirect to index
my controllers/videos_controller.rb
def index
#videos = Video.text_search(params[:query]).page(params[:page]).per(12)
end
my views/shared/_menu.html.erb
<%= form_tag videos_path, method: :get do %>
<%= search_field_tag :query, params[:query] %>
<% end %>
You can add that partial to any view page on the site (page_name.html.erb file). It will submit to the controller via the routes file.
Anywhere on the site you can add the following to a view:
<%= render "shared/menu" %>
I have two different controllers (scholarships_controller, scholarships_browse_controller) that look at the scholarship model. I want my Ransack search function to show the search results on the current page. So, for example, if I am on /scholarships_browse and I use the search functionality, I want it to use the scholarships_browse_controller and show the results on /scholarships_browse.
Currently, if I search on /scholarships_browse it uses the scholarships_controller and redirects to /scholarships to show the results (instead of /scholarships_browse).
Code for ScholarshipsBrowseController and ScholarshipsController
def index
#search = Scholarship.search(params[:q])
#scholarships = #search.result.page(params[:page]).per(3) #allows 3 scholarships on a page at a time
#search.build_condition
respond_to do |format|
format.html # index.html.erb
format.json { render json: #scholarships }
end
end
Code for scholarships browse index.html.erb:
<%= search_form_for #search do |f| %>
<%= f.condition_fields do |c| %>
<div class="field">
<%= c.attribute_fields do |a| %>
<%= a.attribute_select %>
<% end %>
<%= c.predicate_select compounds: false, only: [:cont, :eq, :gt, :lt] %>
<%= c.value_fields do |v| %>
<%= v.text_field :value %>
<% end %>
</div>
<% end %>
<div class="actions"><%= f.submit "Search" %></div>
<% end %>
So, I guess specifically I'm asking how do I make sure I am using the ScholarshipsBrowseController index instead of ScholarshipsController index when I am on /scholarships_browse ?
On your view:
<%= search_form_for #search, url: RAILS_ROUTEHERE do |f| %>
...
<%- end %>
search_form_for its an extension for form_for, so you can use the :url parameter to tell the form what should be the action of it (you can check the page source code when you render it on browser, you can check the tag <form action=""> to make sure it points to the right route.