Ransack Ruby On Rails Result Wont Render - ruby-on-rails

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.

Related

Run method in Controller on another page before showing results with Ransack

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.

How do I initiate my each loop only after I have click my submit button in Rails?

I have a Rails app that searches through a DB and returns items. At the moment in my view it automatically returns the default search results ("") without me needing to hit my submit_tag. How do I go about only making this action happen once I have hit the submit_tag? Any help would be greatly appreciated!
Here is my view:
<%= form_tag(new_design_path, method: :get) do %>
<%= label_tag(:q, "Search all designs:") %>
<%= text_field_tag(:q) %>
<%= submit_tag("Search") %>
<% end %><br>
<!-- Button to return one random design -->
<%= form_tag(new_design_path, method: :get) do %>
<%= label_tag(:q, "Inspire me! Click here for a random design:") %>
<%= submit_tag("Random Design") %>
<% end %>
<h2>Search results:</h2>
<% #random.each do |design| %>
<h3><%= design['name'] %></h3>
<h5><%= image_tag design['thumbnail_url'] %></h5>
<% end %>
<% #search.each do |design| %>
<div class="design">
<h3 class="design_name"><%= design['name'] %></h3>
<h5><%= image_tag design['thumbnail_url'] %></h5>
<%= button_to 'Save to Favourites',
designs_path(
design: design.slice('name', 'thumbnail_url')
),method: :post %>
</div>
<% end %>
And my controller:
class DesignsController < ApplicationController
def index
#designs = Design.all.order("created_at DESC")
end
def new
# returns an array of hashes
#search = SpoonflowerApi.new.find(params[:q])['results']
#random = SpoonflowerApi.new.random(rand(1..740579), 1)['results']
end
def create
#design = Design.new(design_params)
#design.save
if #design.save
flash[:notice] = 'Design has been added to favourites!'
else
flash[:notice] = 'Design already in Favourites!'
end
redirect_to new_design_path
end
def destroy
#design = Design.find(params[:id])
#design.destroy
flash[:notice] = 'Design removed from favourites!'
redirect_to designs_path
end
private
def design_params
params.require(:design).permit(:name, :thumbnail_url)
end
end
new is used to populate the initial form, so if you don't want anything for those fields you should just set both #search and #random to an empty array in new. You don't show any code for your model, so it's not really clear what Api is.
show should be called once you submit the form
def new
#search = []
#random = []
end
then move the logic to provide the search results or random record into the show method
def show
# not sure what you want to do here
# since it seems like you have 2 buttons you need logic to provide data
# based on the button
# maybe something like this
if params[:q].nil?
#search = []
#random = Api.new.random(rand(1..740579), 1)['results']
else
#search = Api.new.find(params[:q])['results']
#random = []
end
end
If I understood you correctly, your view showing some search results before you click the search button.
Since you directly send the params[:q] to SpoonflowerApi, I am guessing that it returns some default value and your view draw it.
Simply update your controller to:
def new
#search=[]
#search = SpoonflowerApi.new.find(params[:q])['results'] unless params[:q].nil?
#random = SpoonflowerApi.new.random(rand(1..740579), 1)['results']
end

Show Ransack search results on different page

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

RoR Ransack Searching issue

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.

checkboxtag in forms

Im looking for the following thing: an array of all users (only 6 in this case) with a checkbox in front of their name, resulting in a list of selectable players for the game.
Current code:
<%= form_for #game, url: games_path, :method => "post" do |f| %>
<%= f.label :name %>
<%= f.text_field :name, :value => "#{current_user.name}\'s Game" %>
<%= f.fields_for :participants do |ff| %>
<%= ff.label :user_id %>
<%= ff.text_field :user_id %>
<%= ff.check_box :user_id %>
<% end %>
<%= f.submit "Create Game", class: "btn btn-primary" %>
<% end %>
I'm now having 3.times { #game.participants.build } in my controller which effectively gives me 3 textfields in which i can fill in the participant id in order to make a record in the table participants (which is linked to games).
I've been looking around for 1.5h now and i cant seem to find a proper answer. What i need is a syntax that gives me a list of all current users (say #users) with a checkbox attached to it. When I click the checkbox it should add its id to the parameters and i should be able to create a new game with the linked participant id's. However I'm getting some problems with the ID's attached to the check_box which always seems to be 1. I've read some stuff about checkboxes being a pain with hashes, but I have no other solution atm.
I tried:
<% #users.each do |i| %>
<%= check_box_tag "alternate_numbers[#{i}]" %> <%= i.name %><br />
<% end %>
But i see no way to get that fixed up part of the form itself.
GamesController code (edit):
def new
#users = User.paginate(page: params[:page])
#games = current_user.games
#game = Game.new
3.times { #game.participants.build }
end
def create
#game = Game.new(params[:game])
#newround = #game.rounds.new
#newround.storyFragment = "New story!"
if #game.save && #newround.save
flash[:success] = "Created!"
redirect_to game_path(#game.id)
else
redirect_to root_url
end
end
It's very vague to describe since im not exactly sure how to accomplish this.
In short: the check_box should contain the value of the user_id in the loop. I'm now filling in a manual ID with the text_field helper but i'd like to have the checkbox linked to the username that is right next to it in the view.
Any guidelines/solutions/tips?
Thx
Okay, so you're making a form for a new Game. You now have to feed that new Game, along with some Participants to your view.
def new
#game = Game.new
#participants = User.all # or the users you want
end
Now use those in your view. You were on the right track. Depending on how your create action works:
<% #participants.each do |p| %>
<%= check_box_tag "participants[#{p.id}]" %> <%= p.name %>
<% end %>
I think what you were missing was the documentation for check_box_tag. The input attribute name is the argument.
You also seem to have a lot of logic in your controllers. Remember to keep the logic in the models, and only use the controllers to give the right objects to your views, and taking them for saving, for example. As the saying goes, "fat model, skinny controller".

Resources