ruby on rails implement search with auto complete - ruby-on-rails

I've implemented a search box that searches the "Illnesses" table and the "symptoms" table in my DB.
Now I want to add auto-complete to the search box.
I've created a new controller called "auto_complete_controller" which returns the auto complete data.
I'm just not sure how to combine the search functionality and the auto complete functionality: I want the "index" action in my search controller to return the search results, and the "index" action in my auto_complete controller to return the auto_complete data.
Please guide me how to fix my html syntax and what to write in the js.coffee file.
I'm using rails 3.x with the jquery UI for auto-complete, I prefer a server side solution, and this is my current code:
main_page/index.html.erb:
<p>
<b>Syptoms / Illnesses</b>
<%= form_tag search_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %> <br/>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
</p>
auto_complete_controller.rb:
class AutoCompleteController < ApplicationController
def index
#results = Illness.order(:name).where("name like ?", "%#{params[:term]}%") + Symptom.order(:name).where("name like ?", "%#{params[:term]}%")
render json: #results.map(&:name)
end
end
search_controller.rb:
class SearchController < ApplicationController
def index
#results = Illness.search(params[:search]) + Symptom.search(params[:search])
respond_to do |format|
format.html # index.html.erb
format.json { render json: #results }
end
end
end
Thanks, Li

I have had the same problem and had to create this gem for it: https://github.com/rayasocialmedia/rails_autocomplete

Here's how to do dynamic typeahead in Twitter-Bootstrap; I'm sure it's something similar for jQuery:
https://gist.github.com/1848558
Essentially, by listening to to non-navigational keystrokes, it triggers an AJAX partial text search to your controller. This return data then populates the JS framework's typeahead/autocomplete data to be displayed. This means that you really only need the one SearchController.

Try rails3-jquery-autocomplete. I am using it and had the same requirements as you, and they work fine together. Let me know if you need further help.

Related

Rails - Render active partial on same page?

So i just attach a screenshot to make it more obvious what im trying to do:
Is there a way to load a partial dynamically based on which button was pressed?
For example: If Customers is pressed, load the customer partial on the right side. If products, the products partial and so on.
I saw somewhere in some literature some examples where they did that, but can't find it anymore.
Thanks in advance everyone!
Greetings!
I think you can do this in very easier way...
Suppose your button is loaded on index page :-
#index.html.erb
.....
#Your index page code
.....
<%= link_to “customer path”, customer_path, class: "css-class", remote: true %> ## create button with remote true for ajax call
<%= link_to “product path”, product_path, class: "css-class", remote: true %> ## create button with remote true for ajax call
<div id = "customer-section"> </div> #div to load partials
<div id = "product-section"> </div> #div to load partials
In your controller:
#controller.rb
def customer
#customer code here
respond_to do |format|
format.js {}
end
end
def product
#product code here
respond_to do |format|
format.js {}
end
end
Create js file :-
# customer.js.erb
$("#customer-section").html("<%=j render "customer")%>");
# product.js.erb
$("#product-section").html("<%=j render "product")%>");
Create partial html file to render :-
# _customer.html.erb
<h1>This is customer partial</h1>
# _product.html.erb
<div>This is product partial</div>
This way you can achieve your above requirement. For more you can refer this article https://m.patrikonrails.com/how-to-make-ajax-calls-the-rails-way-20174715d176
Hope this will help you. :)

How to filter by params and user input in Rails

I am trying to display only the rows that belong to certain states in my application. I can do it the long way in Javascript, but I would prefer to better understand Rails and queries in the controller. I want to take the users to another page and then show them only that the companies in that state. It would be great to not have to link them to another page. Does anyone know how to do this?
Here is what I have in my controller
def vendors
#vendors = Collective.where(sort: 'Vendor').all
#vendors = #vendors.where(params[:state])
end
My route
get '/vendors/:state', to: 'collectives#vendors'
Then I use the stereotypical method to print a table in a html.erb file.
<% #vendors.each do |company| %>
<tr>
<td><%= company.name %></td>
<td><%= company.state %></td>
etc...
Should your controller code change the where as follows:
def vendors
#vendors = Collective.where(sort: 'Vendor').all
#vendors = #vendors.where(state: params[:state])
end
or better:
def vendors
#vendors = Collective.where(sort: 'Vendor', state: params[:state])
end
Using sessions instead of url params.
This is more or less what you can do, sorry if it is not completly working for your case, just to give an idea.
# view collectives/index (or whatever you have)
<%= form_tag (controller: :collectives, action: :set_status_filter, method: :post) do %>
<%= select_tag(:session_status_filter, options_for_select(#your_list_of_options_for_the_filter)) %>
<%= submit_tag "Set filter" %>
<% end %>
# collectives controller
def index # or whatever, this is the page containing the form and the list to show
#vendors = Collective.where(sort: 'Vendor').all
if session[:session_status_filter] == # etcetera
then #vendors = #vendors.where(state: session[:session_status_filter]) # for example
else # another option just in case, etcetera
end
end
def set_status_filter # this action is called by the form
session[:session_status_filter] = params[:session_status_filter]
respond_to do |format|
format.html { redirect_to *** the view where the form is placed ***, notice: 'the filter is set to: ....' + session[:session_status_filter] } # after the session variable is set the redirects goes to index which uses the session to filter records
end
end
params[:session_status_filter] is passed by the form to collectives#set_status_filter. The value is used to set the session variables. After that the action collectives#set_status_filter redirects to the index, or whatever page you placed the form and the list to show.

Ruby on Rails - Show method for a parsed JSON result

I am building a seemingly simple website for a visitor to get a status update on a selected data piece. The data comes from an external API. The gist of it is this: the visitor sees a list of the data names, clicks one, and is redirected to a partial with status update, either True or False.
My index method works very well, and iterates through the data names perfectly. I believe my routing (using the friendly_id gem) should work fine. However, I cannot figure out how to properly set up the show method.
Here is my code thus far:
Controller:
class DataController < ApplicationController
include HTTParty
attr_accessor :name, :status
def index
#response = HTTParty.get("api_url").parsed_response
respond_to do |format|
format.json { render :json => JSON.parse(#result, :include => { :data => { :only => [:name, :status]}}) }
format.html { render "index.html.erb" }
end
end
def show
#response = HTTParty.get('api_url').parsed_response
respond_to do |format|
format.json { render :json => JSON.parse(#result, :include => { :data => { :only => [:name, :status]}}) }
format.html { render "show.html.erb" }
end
#name = #response.find(params[:name])
end
end
View:
<% #response.each do |data| %>
<ul>
<li>
<%= link_to data['name'].upcase, name_path(#name) %>
</li>
</ul>
<% end %>
Routes:
Rails.application.routes.draw do
root 'data#index'
get '/:name' => 'data#show', as: "name"
end
All of this together brings up the following error:
ActionController::UrlGenerationError in Data#index
Showing /app/views/layouts/_header.html.erb where line #11 raised:
No route matches {:action=>"show", :controller=>"data", :name=>nil} missing required keys: [:name]
What I am trying to accomplish is to be able to route each iterated link as 'root/{data name}', pulling {data name} from the JSON result as a parameter, and then rendering a show page with the status update information. Clearly, I have no idea how to actually capture the "name" key from the parsed JSON result as a param for the show method. I have tried creating a data_params method to contain it, but it did not work. I have tried implicitly calling the param on the find method in show (as above), to no avail. I have even tried calling a new api scrape in a params method and trying to parse the results into that, and nothing.
I'm guessing it is either some very simple mistake I'm not seeing (is my link_to actually pointing the right direction? are my api calls and JSON parsing done correctly [yes, I know I should create a separate method or helper for the api call, but that hasn't been working out for me so far--I keep breaking the app]? is this link actually supposed to call from the index method still?), or else something a bit more out of my depth.
Any ideas on where to go from here?
In this view:
<% #response.each do |data| %>
<ul>
<li>
<%= link_to data['name'].upcase, name_path(#name) %>
</li>
</ul>
<% end %>
You're using #name but you never actually assign a value to it in your index controller method. As a result - it gets passed to the name_path function with a value of nil. That throws an error because your route definition requires a name.
I think you want something like name_path(data['name']) or something along those lines.

rails different form attributes based on category

I have a rails app!
I'd like to create a form for a product model, where users can choose a product category first and then can fill the form out.
This would be easy, but I'd like to show them different attributes based on the chosen category. Something like if they choose book category, then they will have fields like title, author, published_at, but if they choose shoes category then they can fill out the size, color and type fields.
I saw afew tuts about dynamic forms, but as far as I understand it, I don't need that since the form fields will be predefined and users won't be able to add extra fields.
What is the good approach in this case? Should I create more different models like (shoes,books, etc.) or something else?
Should I create more different models
No, I don't think that's necessary.
What you'd be best doing is using ajax to populate the form on category change. This would require some configuration, but will make it the most efficient and secure:
#config/routes.rb
resources :products do
put :new, on: :new #-> url.com/products/new
end
#app/controllers/products_controller.rb
class ProductsController < ApplicationController
def new
if request.get?
#product = Product.new
#categories = Category.all
elsif request.put?
#category = params[:product][:category_id]
#attributes = ...
end
respond_to do |format|
format.js
format.html
end
end
end
#app/views/products/new.html.erb
<%= form_for #product do |f| %>
<%= f.collection_select :category_id, #categories, :id, :name, {}, { data: { remote: true, url: new_product_path, method: :put }} %>
<div class="attributes"></div>
<%= f.submit %>
<% end %>
#app/views/products/new.js.erb
$attributes = $(...); // need a way to create form elements from #attributes
$("form#new_product .attributes").html( $attributes );
Something important to note is that Rails select & check elements allow you to use the data-remote attribute to send an ajax call to your controller on change.
Not much documentation about it, playing around with the above code should get it to work.

Correct way to use Ajax with rails

I am trying to add ajax to a voting system but having difficulty targeting individual elements with jQuery. This is what i have so far:
Vote Link in index action
<%= link_to post_votes_path(post), :method => 'post', :remote => true do %>
<span class="score"><%= post.votes.size %></span>
<% end %>
Create action in Vote controller
def create
#post = Post.find(params[:post_id])
#vote = #post.votes.create
respond_to do |format|
format.html { redirect_to root_url }
format.js
end
end
jQuery in votes#create view (create.js.erb)
$('.score').html("I voted");
Trouble is when i click the link to vote it changes the html for all posts not just the post i tried voting on. Dont have much experience with jQuery so i cant help but think i am missing something obvious. Any ideas ?
all your spans have the .score class. that's the reason for all be changed.
This is a possible solution.
Change in your html:
<span class="score p_<%= post.id%>"><%= post.votes.size %></span>
And then change in your create.js.erb
$('.score.p_<%= #post.id %>').html("I voted");
I typically just use JQuery's $.post. I am using asp.net, but assume rails will work with that as well.
$.post("/someurltoyouraction", {myval:val},function(data){
// do stuff after post
});
This will produce an Ajax post request. You can define your post parameters in the {myval:val} object to match your requirements. It's essentially a key value definition based object {key:value}

Resources