500 internal server error in rails with ajax - ruby-on-rails

I am trying to make a text box that displays a list of sorted users that sorts per every typed letter. From there the person can add the user as a collaborator. The result should be kind of like facebook's search feature when you are searching to add new friends. When I press a key I see a new 500 internal server error in the network section of the browsers console. Here is a snippet of the response:
<h1>
NoMethodError
in CollaborationsController#collaboration_search
</h1>
</header>
<div id="container">
<h2>undefined method `[]' for nil:NilClass</h2>
So I think the ajax is getting fired to the server but there is something wrong with the controller. Here is my code for the view, views/collaborations/_new.html.erb:
<%= form_for [wiki, collaboration] do |f|%>
<div class = "col-md-8">
<div class = "form-group">
<%= f.label :user_name %>
<%= f.text_field :user_name, class: 'form-control', placeholder: "Enter name" %>
</div>
<div class = "form-group">
<%= f.submit class: 'btn btn-success' %>
</div>
</div>
<%= #users_by_name.to_a %>
</div>
</div>
</div>
<%end%>
where the form above is a partial. The ajax is written in javascripts/collaborations.js:
$(document).ready(function()
{
// alert(1);
$('#collaboration_user_name').on('keyup', function() {
// text = $(this).val();
// alert(text);
$.ajax({ url: "/collaborations",
beforeSend: function( xhr ) {
xhr.overrideMimeType( "text/plain; charset=x-user-defined" );
}
}).done(function( data ) {
if( console && console.log ) {
console.log( "Sample of data:", data.slice( 0, 100 ) );
//alert()
}
});
});
});
Here is the collaboration#search_collaboration action within the collaborations controller:
def collaboration_search
name_search = params[:collaboration][:user_name].to_s
#users_by_name = User.where('name Like ?', "%#{params[:collaboration][:user_name]}%")
render json: #users_by_name.map do |user|
{ name: user.name, id: user.id}
end
end
And just for testing purposes I kept my collaborations/search_collaboration.js.erb very simple:
alert('hello');
however if someone can point me in the right direction for how to list the names of the users returned from the collaboration_search action that would be much appreciated!

The error seems to suggest that you're trying to index into something as a hash, when it is, in fact, nil:
undefined method `[]' for nil:NilClass
The [] refers to hash indexing -- such as params[:collaboration]. My immediate guess would be that you're not serving the params to this controller action in the format expected, so that params[:collaboration] is nil, and you're trying to index into that params[:collaboration][:user_name], provoking said error.
This jives with your current jQuery code, which doesn't send the data at all (where are you sending text as a parameter, either in the querystring or as a jQuery.ajax() param?), not to mention in that specific format.
You could either do something like this:
$.ajax({ url: "/collaborations?collaboration=#{text}",
#..etc
Or you could use the ajax function's data method to give it a parameter as a hash instead of just throwing it in the URL. The docs for that function should give you more information.
I'd strongly recommend the latter, as you expect nested hashes in your controller [:collaboration][:user_name], which is not easily supported in a querystring parameter.
To see what the parameters are coming in as, I suggest throwing something like this in your Ruby controller:
puts "PARAMS: #{params.inspect}"
That should go above anything causing an error. It will print out the params in your server log (the terminal tab where you typed rails server or rails s), so that you can see what the parameters are, and whether this hypothesis is accurate, and how to fix the problem.
As a final note, I don't think you're actually hitting your .js.erb file at all. Your action just returns a response to the jQuery ajax function. That response is in your function called on done(), and the response data is, in your current code, referred to as data. I'd alert that data once you've gotten past this error, to see how your controller is serializing things. And then, without that js.erb file, you can simply update the DOM with the results from the jQuery.
(Final note, I can't think of an occasion where you'd need to test for if console && console.log, and I'm not sure that test won't throw an error. I might be wrong, though.)

The UX Jargon for what you what you are trying to build is autocomplete dropdown or autocomplete combobox. It is actually a fairly complicated UI element that I wouldn't both programming from scratch. You should use a library like JQuery. JQuery is built into core Rails so I should just be a matter of including the right library. Here Is a sample of the element from JQuery.
http://jquery-ui.googlecode.com/svn/tags/1.8.7/demos/autocomplete/combobox.html
You can look at the source code using the browser development tools
Here is JQuery Autocomplete docs
http://jqueryui.com/autocomplete/
You can look at the code in you
Here is another implementation
http://www.jqwidgets.com/jquery-widgets-demo/demos/jqxcombobox/index.htm

Related

Rails clear flash notice after JSON response

I am using Angular to send JSON request to the controller, in my controller I flash notice like this:
flash[:notice] = "Toon has been tagged"
After I want to use my rabl template to return JSON response and also include my flash notice content like this:
object #toon
attributes :id, :uuid, :get_tag_string
if flash
node(:flash) do |f|
flash.each do |k, v|
{ :msg => v, :name => k }
end
end
end
attributes :errors
My angular code handles the response and display the flash notice contents correctly. But here comes the problem, when the page refreshed the flash message is displayed again because of following code in my layout view:
<% flash.each do |key, value| %>
<div class="row-fluid">
<div class="span8 offset1"><%= content_tag(:div, value, class: "alert alert-#{key} center")%></div>
</div>
<% end %>
I could remove this or do an after_filter in my controller to call flash.clear
IS THERE A BETTER WAY TO DO THIS?
THANKS!!
I too am using angularjs with rails. The way I am handling error messages from the server (rails) is to use angular route changing events. Since you are dealing with flash messages from the server, it's really the same concept.
In my angular app where I display errors (in your case flash messages) I use an ng-show with a variable, e.g.,
<div ng-show="showMessages" class="alert">
{{myMessages}} // obviously here you may have an ng-repeat or similar
</div>
In my main angular controller I am setting $scope.showMessages (either true or false). At this point it's the same issue. In my controller I use the following callback to see when the route has changed. When it's changed I can set $scope.showMessages to false.
$scope.$on('$routeChangeStart', function (scope, next, current) {
$scope.showMessages = false;
}
I also use this routeChangeStart event to deal with times where I want the message to come out on the next page- by adding another var to control the "show this on the next page only".
I personally wouldn't go back to the server to clear the flash messages - that seems "expensive" whereas you wouldn't be forced to make that extra round trip.
Solve with flash.now in my controller :)
Thanks for your answer Arthur Frankel, liked your way to hand the messages

Dynamically insert params to link_to in Rails

In my homepage, I have an input box that user can type in a search query. Then I have a link_to which will make a get request to a different page (search page) with the search query. By design, I can't use Rails form_for.
How can I insert my query dynamically to "link_to" after detecting a change in my input box?
Here is a mock:
%input{:type => "text", :id => "my_input"}
= link_to "Search", posts_path(query: "my_query_here")
:javascript
$(function(){
$("#my_input").change(function() {
... do something here ...
});
});
Thank you.
You can't. Your javascript can't hack into your server-side code. However, it can hack the result of your server-side code, which is HTML.
To make sure the query for your posts link matches properly, you should add a specific ID to your <%= link_to %>:
<%= link_to "Search", posts_path, :id => "search_link" %>
Then your javascript should be like:
$("#my_input").change(function() {
$("#search_link").attr("href","/posts?q=" + encodeURIComponent( $(this).val() ) );
});
Thanks to user #beck03076 for suggesting that you could simply execute a location change on click rather than updating the link every time the input changes:
$("#link").click(function() {
$(this).attr("href", "/posts?q=" + encodeURIComponent($("#my_input").val()));
});
Depending on what exactly you want to do, this may not exactly match your expectation. For example, if you have some other code that inspects the link URL to update something else on the page, this second method won't work. If, on the other hand, all you want is to execute a search on click, this will be much more efficient.

checking if subject exist through jquery in rails 2.3

How can I do this in ruby on rails with jquery
The Code:
Model
Subject
View
<%= text_field_tag :subject_1 %>
<%= text_field_tag :subject_2 %>
<%= text_field_tag :subject_3 %>
Senario:
User typed the subject code on the textfield(subject_1) and if the user goes to the next text field(subject_2) beside the first textfield(subject_1) there will be a reload icon then show the corresponding subject details(subject name, subject code, subject schedule) base on the typed suject code. And if the subject is does not exist it will show a message "Subject does not exist.".
The idea is that when a blur event occurs in the subject1 text_field an AJAX call is made to the server that tries to find a subject record with the id/description/attribute given by the `text_field´ and returns success or error. The code would be something like this:
$('subject_1').blur(function() {
var field_value = $(this).val();
$.post("/subjects/validate_subject", field_value, function(data) {
success: function() {
// Here you populate the subject_2 text_field with the data from the server.
},
error: function() {
// Here you populate some error content in your view.
}
});
});
Remember to add the validate_subject to your routes.rb.
This is just the beginning of the answer to your problem. I recommend you to read about Rails and Ajax interaction.
Here is a great guide for this subject. http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-in-rails-3/

How to transfer a javascript value into a symbol used in Ruby on Rails

I am currently using Rails 2.0.2 with Ruby 1.8.7. My Prototoype.js version is 1.7(if required). I am basically trying to integrate the calendar_date_select plugin in my app.
The link/tutorial I am referring is: http://ianli.com/site/HowTo/UseCalendarDateSelectRailsPlugin
I am trying to save the date I receive through the date select plugin and store in a rails symbol :publishing_date.
I am selecting the date using the calendar_date_select plugin. The selected date gets uploaded into the text field, but I am not sure how to transfer that returned value onto my publishing_date attribute(:publishing_date symbol) of my books table.
On manually entering a date I am able to see it reflected in the DB. I am getting stuck when I am trying to save it through the plugin.
<%= f.text_field :publishing_date %>
On clicking on the create button I get a null value for the date selected via the calendar_date_select plugin. I am able to properly insert values for name of book and author.
My code for a new book looks like this:
<%= javascript_include_tag :defaults %>
<script src='/javascripts/calendar_date_select/calendar_date_select.js' type='text/javascript'></script>
<h1>New book</h1>
<%= error_messages_for :book %>
<% form_for(#book) do |f| %>
<p>
<b>Title</b><br />
<%= f.text_field :title %>
</p>
<p>
<b>Author</b><br />
<%= f.text_field :author %>
</p>
<p>
<b>Publishing Date</b><br />
<%=calendar_date_select_tag f.text_field :publishing_date %> <!--This way of save/assigning doesn't work -->
</p>
<br />
<br />
<br />
<br />
<p>
<%= f.submit "Create" %>
</p>
<% end %>
<%= link_to 'Back', books_path %>
Also once I save it perfectly, could you also please tell me how would I be able to display this date it in my index.html.erb
My current index.html.erb looks like this:
<h1>Listing books</h1>
<table>
<tr>
<th>Title</th>
<th>Author</th>
<th>Publishing Date</th>
</tr>
<% for book in #books %>
<tr>
<td><%=h book.title %></td>
<td><%=h book.author %></td>
<td><%= book.publishing_date %></td> <!-- Will this work? -->
<td><%= link_to 'Show', book %></td>
<td><%= link_to 'Edit', edit_book_path(book) %></td>
<td><%= link_to 'Destroy', book, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
<%= will_paginate #books %>
<br />
<%= link_to 'New book', new_book_path %>
An interesting excerpt from the aforementioned tutorial link is given below:
The value of the selected date can be accessed by getting the value of the text field named calendar.
Using the Prototype Javascript Library, you can do the following to get the value.
$F('calendar')
The roadblock I am facing is how to call the $F('publishing_date') in my new.html.erb file using the rails <%=> tag and then assign that to my :publishing_date symbol which will eventually be use to update the publishing_date attribute in my books table.
Thanks for your support.
Here's how to make your plugin do what you want (with javascript, like the tutorial says)
Summary:
Very complicated, not actually rails code. Requires knowledge of javascript, and use of this knowledge to write your own custom form, rather than using pre-generated Rails forms. This might not be what you're looking for, but it looks like what the plugin actually expects. Probably complicated to debug (would need to look at html source code, what routes are getting hit in the logs, etc)
Process:
Your plugin lets you do something like:
<%= calendar_date_select_tag "calendar", Date.today,
:embedded => true,
:year_range => 3.years.ago..0.years.ago %>
(according to the tutorial you linked to).
That is rails code. All any rails erb code does is give you a quick, simple way to generate real html... A link to, for example,
<%= link_to 'Edit', edit_video_path(#video) %>
produces html code that looks like this:
Edit
Which is what your browser actually renders. So far so good?
All rails does is take your erb file, and line by line convert it to html, which a web page can display. What this means for you, is that by the time your plugin is actually running (which is in the browser), there is NO rails code left. So you can't GIVE any javascript variables back up to your rails code UNLESS you pass it in through a route.
How rails normally handles forms, is it makes the proper html tags, and html itself handles controlling the form. Even though you set rails variables in the .erb file, those variables don't actually help data go to your rails app. Instead, when you use your form, you should see (in your logs), something like:
Started POST "/users/sign_in" for 127.0.0.1 at 2011-02-03 14:22:42 -0500
Processing by Devise::SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"NeqeuxOpBfGVJ0qq5V4emR23vc744KkgJQDFyPluaok=", "user"=>{"email"=>"don#a.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"}
In your controller (sign_in in the above case, looks like maybe create for yours?), you could access these posted parameters by saying params[:user][:email], or whatever NO MATTER HOW YOU PASSED THEM IN.
That is, yes, in your form you say things like :title, and :publishing date, but those just set the params you pass in to rails, not the actual symbol in your rails controller. You could just as easily use a command line tool (like curl) to pass the same things in, without a rails-generated webpage.
WHICH, is basically how the javascript solution works.
The tutorial says you can do things like:
<%= calendar_date_select_tag "calendar", Date.today,
:embedded => true,
:year_range => 3.years.ago..0.years.ago,
:onchange => "changeLocation(new Date($F(this)))" # <- ADD THIS LINE
%>
And then write a javascript function (NOT rails) like:
<script type="text/javascript">
function changeLocation(date) {
year = date.getFullYear();
month = date.getMonth() + 1;
day = date.getDate();
if (month < 10) {
month = "0" + month;
}
if (day < 10) {
day = "0" + day;
}
location.href = 'http://google.com/search?q=' + year + '-' + month + '-' + day;
}
</script>
The above script takes whatever date you chose on your calendar, and sends you to a google page with that date, as shown in the line:
location.href = 'http://google.com/search?q=' + year + '-' + month + '-' + day;
This is ACTUALLY really close to what we want to do. The difference is we want it to set the location to your create book route, and POST (not GET like location does) the book's parameters to that route. Once we do that, rails will handle it just as if it was a form it had created itself.
Are you familiar with restful routes at all? (and more importantly, are you using them?) location.href (as in the example) does a GET, while we need a POST to hit the create route with the right information.
I'm not too familiar with how standard javascript does things, but I use a library called "JQuery" for most of my POSTs (which you can include at the top of your erb file like:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
Jquery lets me change the code to look like:
<script type="text/javascript">
function changeLocation(date) {
year = date.getFullYear();
month = date.getMonth() + 1;
day = date.getDate();
if (month < 10) {
month = "0" + month;
}
if (day < 10) {
day = "0" + day;
}
var pdate = year + "/" month + "/" day
$.post("/videos", {publishing_date: pdate}) //this is going to your create route, with the parameters in brackets
}
</script>
Keep in mind this is by no means the only way to do javascript posts, it's just how I do them. Also, this assumes you want your publishing date in yy/mm/dd format like the tutorial (if you don't, create pdate differently).
So, that last should let you give publishing_date to your Rails controller action responsible for creating books. Tada! You can access it through params[:publishing_date] if you want. If you want it to look EXACTLY like rails, you'd probably have to nest it something like:
{book: {publishing_date: pdate}}
So that it looks just like something that came from a form to rails.
If you want to get the rest of your form params in there, you'll probably have to not use rails auto-creation tools, and instead build the rest of your form with javascript as well. There are some pretty good tutorials out there, but essentially, when you do that post, you want to change it to looke something like:
$.post("/videos", {book:{publishing_date: pdate, title: book_name}})
or whatever, and have the var book_name be set in the same method by using something like:
var book_name = document.form_name.field_name.value
Where form_name is the name of the form (easily found out by viewing the source of the file) and field_name is the name of the field (same deal).
For some of my rails code it's generating something that looks like:
<form action="/videos" enctype="multipart/form-data" method="post">
<p>
<label for="video_name">Name</label><br />
<input id="video_name" name="video[name]" size="30" type="text" />
</p>
Which actually doesn't have a name for the form (there's probably some rails way to set this), but the name of the field would be "video[name]" (not sure how javascript would like the brackets...but only one way to find out. If javascript DOES have a problem, you can always write the form html by hand, and make all the tag names something javascript can deal with. You wouldn't need a submit button, because the javascript does the submitting for you.
As far as "How to display", you are correct that
book.publishing_date
will work just fine, IF it gets set. You say you can set it just fine with a text field, right (i.e. your migrations are correct)? Doing that, then looking at your index page should confirm this.
Also, from my experience, javascript vars can't be passed to rails (though rails vars can be passed to javascript). So, you would never be able to get $F('publishing_date') into your erb file. By the time any javascript vars are set, it's not a Ruby program anymore, it's just a web page... There MUST be a default way for your plugin to handle things, and I'm a little surprised it's not working out of the box... Hrrm...wait...
I just actually glanced over the tutorial you linked to, and I THINK I see your problem:
Your plugin is not ACTUALLY a form helper (that works with "form_for).
If it WAS a form helper (and would set your form variable like you want), you'd call it with:
<% f.calendar_select_tag %>
Which would make it be a parameter passed into your form. In this case, it seems like it's just generating a calendar for you, which you can then program your own javascript to handle (like "function changeLocation(date)" in the tutorial). It has nothing at ALL to do with forms.
If you want this interface to actually work with a form, you'll have to make the form in html/javascript and NOT with the ruby helper tags. (which is more complicated).
You'd need to have a post, which contains "$F('publishing_date')" in the parameters, as well as any other javascript variables you'd want to set, and hit your create route manually, through javascript, with those post variables.... Not exactly fun.
Edit:
It's possible it MIGHT work with something like:
<%= form_tag( { :action => 'upload' }, :multipart => true ) %>
<br />
<%= text_field "Title", "title"%>
<%=calendar_date_select_tag :publishing_date %>
<%= submit_tag( "Submit" ) %>
<%= end_form_tag %>
or whatever (a different way to do tags, as opposed to the "form_for" you were using)
http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html
Either way, at the very least, the way you were calling it:
<%=calendar_date_select_tag f.text_field :publishing_date %> <!--This way of save/assigning doesn't work -->
is completely wrong, since you include "f.text_field" in there, which might be a typo? How can it be a select tag AND a text field? Who knows, maybe just getting rid of that will help (though it's still not associated with a form unless you do <% form_tag%>

How to set-up jquery-ui autocomplete in Rails

I need some help on how to implement a jquery-ui autocomplete in my Rails app.
I want to add autocompletion to a text field where the user can enter in a customer name. As there can be hundreds of customers, I will need to pull the suggested auto-completion values 'remotely', as in, from a table (at least this is what I understand).
The main point I am failing to understand is how to provide the suggested values to the autocompletion textbox. I have read the jquery-ui docs, but I seem to be a bit dense on this matter.
So what I am really after is an example of how I can get this to work in a Rails app, not necessarily a full description of how the javascript is built (that's what the jquery-ui team has done for me =) ).
For example, how do I prepare the data for the autocompletion, and how do I attach the autocompletion functionality to a textbox.
Well I never got an answer to my question above so I ended up having to figure it out for myself. I thought I should post the solution I came up with in case there are any other guys out there who are wondering the same thing.
First thing you should know is that this is my first experience with javascript, and I am just getting the hang of Rails. So by all means, feel free to edit, comment anywhere you feel I have gone wrong with this. Right or wrong at least I know that it functions the way I wanted it to.
I think the best way to show this is by example. So the following is how I got the autocomplete widget to work in my app. You can go ahead and put the following code in your app even if you don't understand what is happening, then we can go over how each part is working by example. After this you should have a grasp on how to modify it for your use or refractor it.
**INCLUDE JQUERY UI IN YOUR RAILS APP.**
Download a copy of the [jQuery UI][ui] and place jquery-ui-1.8.2.custom.min.js inside your /public/javascript directory. Also make sure you have a copy of jQuery itself and that this is also in the same folder.
Include the jQuery UI file and the jQuery file in your application.html.erb file like this.(you can name the files as you please as long as they match)
<%= javascript_include_tag 'jquery.min', 'jquery-ui-1.8.2.custom.min.js' %>
In your download of jQuery UI, you will have a folder that contains all of your CSS data. The name will vary based on the theme you chose, for example I chose the theme 'cupertino'. Place the entire folder containing your CSS data into '/public/stylesheets/'. Then include the CSS file in your application.html.erb like this.
<%= stylesheet_link_tag 'cupertino/jquery-ui-1.8.2.custom' %>
**EXAMPLE AUTOCOMPLETE JAVASCRIPT**
Now take the following chunk of code and place it in one of your 'new' views. You can use this in any view, but realize that I have literally taken it from an existing view belonging to a controller called 'links_controller', and it is pulling data from a 'people_controller'. Hopefully you know enough about Rails to work out what you need to change so this works for you.
-- Begin big chunk of code --
<script type="text/javascript">
$(function() {
// Below is the name of the textfield that will be autocomplete
$('#select_origin').autocomplete({
// This shows the min length of charcters that must be typed before the autocomplete looks for a match.
minLength: 2,
// This is the source of the auocomplete suggestions. In this case a list of names from the people controller, in JSON format.
source: '<%= people_path(:json) %>',
// This updates the textfield when you move the updown the suggestions list, with your keyboard. In our case it will reflect the same value that you see in the suggestions which is the person.given_name.
focus: function(event, ui) {
$('#select_origin').val(ui.item.person.given_name);
return false;
},
// Once a value in the drop down list is selected, do the following:
select: function(event, ui) {
// place the person.given_name value into the textfield called 'select_origin'...
$('#select_origin').val(ui.item.person.given_name);
// and place the person.id into the hidden textfield called 'link_origin_id'.
$('#link_origin_id').val(ui.item.person.id);
return false;
}
})
// The below code is straight from the jQuery example. It formats what data is displayed in the dropdown box, and can be customized.
.data( "autocomplete" )._renderItem = function( ul, item ) {
return $( "<li></li>" )
.data( "item.autocomplete", item )
// For now which just want to show the person.given_name in the list.
.append( "<a>" + item.person.given_name + "</a>" )
.appendTo( ul );
};
});
</script>
<h1>New link</h1>
<% form_for(#link) do |f| %>
<%= f.error_messages %>
<!-- Place the following text fields in your form, the names are not important. What is important is that they match the names in your javascript above -->
<p>
Select which person you want to link:<br />
<!-- This is the textfield that will autocomplete. What is displayed here is for the user to see but the data will not go anywhere -->
<input id="select_origin"/>
<!-- This is the hidden textfield that will be given the Persons ID based on who is selected. This value will be sent as a parameter -->
<input id="link_origin_id" name="link[origin_id]" type="hidden"/>
</p>
<!-- end of notes -->
<p>
<%= f.label :rcvd_id %><br />
<%= f.text_field :rcvd_id %>
</p>
<p>
<%= f.label :link_type %><br />
<%= f.text_field :link_type %>
</p>
<p>
<%= f.label :summary %><br />
<%= f.text_area :summary %>
</p>
<p>
<%= f.label :active %><br />
<%= f.check_box :active %>
</p>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>
-- End Big Chunk of Code --
Okay now to connect the dots.
**PROVIDE DATA FOR AUTOCOMPLETE TO USE AS SUGGESTIONS**
Lets start by connecting up some data that the autocomplete textfield can display in the drop down suggestions. The format we will be using is JSON, but don't worry if you are not familiar with it ... neither am I =). It is good enough to know that it is a way to format text so that other parts of yours/other applications can use it.
The data the textfield will need for the autocomplete is specified in the 'source:' option. Because we want to send a list of peoples names and their ID to the autocomplete we will put the following as the source.
source: '<%= people_path(:json) %>'
The rails helper above will translate to a string "/people.json". You do not need to create a page at "/people.json". What you do need to do is tell your people_controller what to do when it receives a request for /people with the .json format. Put the following into your people_controller:
def index
# I will explain this part in a moment.
if params[:term]
#people = Person.find(:all,:conditions => ['given_name LIKE ?', "#{params[:term]}%"])
else
#people = Person.all
end
respond_to do |format|
format.html # index.html.erb
# Here is where you can specify how to handle the request for "/people.json"
format.json { render :json => #people.to_json }
end
end
Now we have all the people in #people being sent to the autocomplete textfield. This brings up the very next point.
**FILTER DATA USED FOR AUTOCOMPLETE SUGGESTION, BASED ON INPUT**
How does the autocomplete textfield know how to filter the results based on what you type?
The autocomplete widget assigned to the textfield will send whatever you type into the textfield as a parameter to your source:. The parameter being sent is "term". So if you were to type "Joe" into the textfield, we would be doing the following:
/people.json?term=joe
That is why we have the following in the controller:
# If the autocomplete is used, it will send a parameter 'term', so we catch that here
if params[:term]
# Then we limit the number of records assigned to #people, by using the term value as a filter.
#people = Person.find(:all,:conditions => ['given_name LIKE ?', "#{params[:term]}%"])
# In my example, I still need to access all records when I first render the page, so for normal use I assign all. This has nothing to do with the autocomplete, just showing you how I used it in my situation.
else
#people = Person.all
end
Now that we have limited the number of records assigned to #people based on what is typed into the autocomplete textfield, we can now turn that into JSON format for the autocomplete suggestions.
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #people.to_json }
end
Now, just review the comments inside the "Big Chunk of Code" which should explain the rest of how this ties together.
At the end you should have a textfield on your page that acts as the autocomplete and a hidden field that will send the ID in a parameter to your controller.
**CUSTOMIZE YOUR OWN AUTOCOMPLETE**
Once you understand the above and you want to modify it for your use, you should know that the format JSON returned from your controller looks like this:
[{"person":{"id":1,"given_name":"joe","middle_name":"smith","family_name":"jones","nationality":"australian"}}]
The way to access the different values from the JSON string in your javascript in this case would be:
ui.item.person.name_of_some_attribute_such_as_given_name
Pretty, simple. A lot like accessing an ActiveRecord attribute in Rails.
One last note. I spent a lot of time looking for a different way to supply the hidden value, as I thought this function should have been built into the jquery widget. However, this is not the case. It is clearly shown in the official jQuery example that the way to send a different value then selected as a parameter, is to use a hidden field.
Dale
[ui]:http://jqueryui.com/download
jQuery 1.9/1.10 removed the key autocomplete and added uiAutocomplete
.data("uiAutocomplete") instead of .data("autocomplete")
After modifying to above,it worked for me.
Dale's Answer is quite the tutorial. One thing to note is that using your first query, the datasource will only return matches beginning with the string you type. If you want search anywhere in the word, you need to change:
#people = Person.find(:all,:conditions =>
['given_name LIKE ?', "#{params[:term]}%"])
to
#people = Person.find(:all,:conditions =>
['given_name LIKE ?', "%#{params[:term]}%"])
(added an extra % to the query)
I basically followed Dale's advice below but my controller and js files were slightly diff- his version was giving me issues for some reason (maybe bc of jquery updates)
Context: I'm trying to autocomplete names of DJs typed in by users - also a newb
DJs Controller
class DjsController < ApplicationController
def index
if params[:term]
#djs = Dj.is_dj.where('lower(name) LIKE ?', "%#{params[:term].downcase}%")
respond_to do |format|
format.html
format.json { render :json => #djs.map(&:name) }
end
end
end
end
html.erb file
<script type="text/javascript">
$(function() {
$('#select_origin').autocomplete({
source: '<%= djs_path(:json) %>'
})
$('.submit-comment').click(function(){
var dj_name = $('#select_origin').val();
$('#link_origin_id').val(dj_name);
})
})
</script>
This is a great help.
In addition to it in case if you need to fetch url of image of user, it might not be possible with to_json. For that add the following code in model.
def avatar_url
avatar.url(:thumb)
end
And then in controller instead of to_json use as_json
respond_to do |format|
format.json {render :json => #users.as_json(:only => [:id,:name,:username], :methods => [:avatar_url]) }
end
It's important to note that if your 'source' is relatively small, for example 50 elements, the implementation should be different (and a lot simpler). It is mentioned in the fourth paragraph of the official doc:
https://api.jqueryui.com/autocomplete/
When using local data all you need to do is obtain the data and pass it to the autocomplete method, and it will do the filtering for you. You don't need to go back and forth to the server every time a term es entered.
function filterByTags(tags) {
$("#stories-filter").autocomplete({
source: tags,
autoFocus: true
});
}
$("#stories-filter").click(function() {
$.ajax({
dataType: 'json',
method: 'GET',
url: 'tags/index',
data: $(this).data('project-id'),
success: function (response) {
if(response.success) {
var tags = response.data.tags;
filterByTags(tags);
}
},
error: function (response) {
if(response.status === 422) {
var $errors = 'There are no tags in this project',
$errorsContainer = $('.error-container');
$errorsContainer.append($errors);
$errorsContainer.show();
}
}
});
});
Since this is old, but google still comes here, a small note about the main answer, which is essentially good, but some things have changed:
see answer about jquery having changed .data("uiAutocomplete") to .data("autocomplete")
Also i would recommend a separate route on the resource collection that just handles json
use rabl to create smaller json (or pluck for larger models)
ilike , not like, for case insensitive
the % in front, so the search is not just start_with.
valiable traversal in the methods, like item.person.name are just item.name (so drop the .person)
use coffee (in haml)
use a limit, and where as in: Person.where('given_name ilike ?', "%#{params[:term]}%").limit(20)

Resources