Hi, Ryan!
I always liked all your episodes! I'm buildind a Rails programming team at my company and I'm showing some of your episodes a day. Congratulations for the great work! :D
Best regards,
Felipe Giotto.
hi ryan,
sweetness once again...
but unfortunately it's not working in the IE because of the window.pageYOffset and the innerHeight. both returns undefined in IE. that's why i need to implement a browser switch in scrollDistanceFromBottom(). anyway. nice.
bless chris
Is there a way to modify what is displayed in the <li> that is produced? For instance, if I was autocompleting a Name field, searching by lastname only, so I'm doing something like this:
<%= auto_complete_result @user, :lastname %>
Is there a way to display both the firstname and lastname in the <li> that is produced?
I've tried having my format.js respond by calling a partial which contains both the firstname and lastname, and it displays properly when I trigger the autocomplelte, but then when I submit the form, both the firstname and lastname get injected into my :lastname field
@Jeff, sphinx has some "fuzzy" matching for phrases, where there need to be a certain number of words a given distance a part. See the "extended" match mode for this behavior.
But I don't think this is what you're looking for. If you want fuzzy searching on a given word, where similar words are also found, then I don't think Sphinx supports this.
You may want to look into Xapian. It has some powerful features regarding this. Including stemming which can find variations of a given word (run, runs, running, etc.). it also supports spelling correction to find terms which are similar to a given word.
Dude, Ryan Bates. You are the man. That was AWESOME. I learned so much in that action-packed video. Thanks so much for the free Rails University courses. You are the man! I hope Obama nominates you for the position of vice-president, so that the entire nation will learn how to bitch-slap rails code like you!!
@eddie, I would say that it is possible, the parameter passed to the active record observer methods (after_save and after_destroy) is the record which can be tested to check what it is, check out the api documentation, it has an example using two models: http://api.rubyonrails.com/classes/ActionController/Caching/Sweeping.html
Thanks for the podcast Ryan, I've been looking into the various search technologies for a while. As far as I can tell, one advantage to Ferret is it supports a "fuzzy" string match for search parameters. Any suggestions on how to handle this with Sphinx?
some ActiveRecord caveat to care about regarding UTC conversions:
>> time_str = "2008-07-30T09:44:28+02:00"
>> time = Time.parse time_str
if used then like this:
>> XXX.find_all_by_YYY('yyy', :conditions => ["created_at >= ?", time_str])
you see this query in the log:
SELECT * FROM "XXX" WHERE (created_at >= '2008-07-30T09:44:28+02:00')
same happens with:
>> XXX.find_all_by_YYY('yyy', :conditions => ["created_at >= ?", time])
in the mean time, USE this:
>> XXX.find_all_by_YYY('yyy', :conditions => ["created_at >= ?", time.utc])
then you get this perfectly in the log:
SELECT * FROM "messages" WHERE (created_at >= '2008-07-30 07:44:28')
Well done, I really learnt a lot from this cast and so from others. You have made it very simple to me to understand it without reading a single line on thinking sphinx. Thank you, waiting more interesting topics from you
@Michael, it's best to set up a "cron" job to trigger the rake index task. If you aren't able to do this then you may be able to get your Rails app to spawn a background process to redo the index at a regular interval. I'm not exactly sure how that would work though.
First of all... thanks for the amazing episode again! Thanks for you r help with all the episodes you are making.
I have one thing what i dont understand. How can you manage this on a webhost server you dont maintain yourself? You have to restart it with ssh every time somebody wrote an article or smt else?
Awesome! Looks sweet. I was searching around on Rails Forums for solutions after just sort of winging it, and came across the following thread: http://railsforum.com/viewtopic.php?id=14905.
It looks like the attribute-fu plugin tidies things up similarly. When I get a chance I'll play around with both methods and see what I can see.
I should mention though that I've got an even more complicated situation - the kind of fields that I use for each subtasks depending on what kind of subtask you are dealing with. So imagine that either the task or the subtask has a select which when selected renders the appropriate fields for that selection. I'm gonna take this as it comes, but it's down the road for me so I'm keeping an eye on it.
Brandon: I think it's a performance concern more than anything, since now your pages controller might start handling a bunch of requests that otherwise would have been handled more efficiently higher up the chain. It's also possible you don't want your page editors to be able to carve out chunks of your root URLspace.
Swist: Ryan uses a helper method to create titles without duplication. There's probably some way to make nifty-generators create the helper method, but all it is is:
def title(title)
content_for(:title) { title }
end
and a yield(:title) in the appropriate spot in the site layout.
Because it's a partial, the id and name attributes are duplicated, so the autocomplete only works on the first instance of the partial, not to mention it's invalid XHTML to have dupe id's.
Just one question, how would you manage a more complicated search form.
Let's say that the user can say if he wants to search only by title, author or comments.
Is there an easy way to filter the indexes to use ?
I just converted a large application from Ferret to Sphinx last week, and ran into a whole bunch of problems. I wrote a long <a href="http://blog.lrdesign.com/2008/07/fixing-problems-with-sphinx-search/">blog post</a> about the trials and tribulations I went through to get it working, including the fixes.
Though we were using ultrasphinx instead of thinking_sphinx, some of the struggles will be relevant to everyone using sphinx, for example the fact that foxy fixtures generates IDs that are often too large for sphinx's indexing strategy.
@MikeInAZ, thanks for pointing that out. I normally use auto-completion for rake tasks as you may have noticed in this episode. If anyone's interested in that, see my dotfiles:
I'm having some trouble with the edit using this method.
For example:
When I go to the edit, and i have several countries associated to it's continents, it keeps the value selected (for example China for the Asian continent). When I change the continent in the parent select it replaces all the select but not the prompted edit value (in this case China).
The question is, how can I replace that first value in the edit view?
Outstanding job, Ryan. I think this is your best Railscast yet! Great job showing simultaneously how simple it is to use Thinking Sphinx and how much power you can leverage by drilling down into it. I'll be watching this one again. :)
i'm trying.... i tried to get it to work with text_field_tag, because in Ryan's example in this episode, it was used with the object-related text_field. i've put off using auto_complete for now. i need to finish other priorities for a project first before i go back to this... should i go back to this.
@Steven, there isn't a User model in this app. We have a UserSession model, but that's not based on Active Record so you can't build associations through it.
Alright, so I got it to work using options_from_from_collection_for_select to get the options and then feeding them into a select_tag method. It works, but a) it seems like there is a prettier way to do it and b) I'm not sure how to specify a prompt. I've tried putting :prompt => "Select a such and Such" both at the end of the select_tag call and the options_ from_col.. call, and neither works. If anyone has solutions to these minor queries, answers would be welcome and appreciated.
this is a problem when you are trying to make each field autocomplete with scriptaculous because it needs a unique id for each input, and this is ignoring the fact they should be unique anyway.
Thanks for tutorial. I recently wrote <a href="http://emmanueloga.wordpress.com/2008/07/26/liquid-coolness/">a blog post</a> about liquid internals, I hope you guys may find it useful.
I was able to successfully implement this with the 3-part complex forms application. Vysogot's solution worked, but I had to make a couple of further modifications. Here is the code from my _task partial
<label for="task_state_id">State or Province:</label>
<%= task_form.collection_select :state_id, State.find(:all), :id, :name, :prompt => "Select a State" %>
</p>
...
Here's what I changed:
-I had to call :country_id (not :country) in the collection_select
-I put the collection_selects in the the same <p> element so that the call to .next() works properly.
-I put the :onchange call in {} brackets
-'model' in the def of collectionSelected() should have been 'state'
I think that that's it for the complex forms application. I'm still not sure how to get this to work with my application, since as I mentioned I can't use collection_select, as what will effectively be the person in my application has a state, but a country only through a state. I'll keep working on it, but if anyone knows what to use instead of a collection_select I would appreciate a comment on it.
Oh, and thanks to Ryan and everyone else who helps everyone out here - Awesome!
@klickverbot, I generated the models from fixtures, which if you don't specify an id, generates one based on the name of the fixture record. That's what you're seeing there.
@Felipe, heh, I record the show in very tiny segments (usually less than a minute each) and edit it all together. Recording a full screencast in one go is very difficult and usually ends up being more work than editing.
Hi, Ryan!
I always liked all your episodes! I'm buildind a Rails programming team at my company and I'm showing some of your episodes a day. Congratulations for the great work! :D
Best regards,
Felipe Giotto.
hi ryan,
sweetness once again...
but unfortunately it's not working in the IE because of the window.pageYOffset and the innerHeight. both returns undefined in IE. that's why i need to implement a browser switch in scrollDistanceFromBottom(). anyway. nice.
bless chris
Hey thanks for the video Ryan. Awesome little tutorial. I had previously installed Selenium inside my Rails projects by following the writeup here:
http://siannopollo.blogspot.com/2007/02/selenium-and-ruby-they-actually-work.html
Works very well, but not quite as flexible and versatile as this method. Thanks
Is there anybody lucky with installing sphinx on a Windows computer?
if i use the install link here above it says that vendor/plugin/sphinx is removed again. And after that it wont start sphinx
Is there a way to modify what is displayed in the <li> that is produced? For instance, if I was autocompleting a Name field, searching by lastname only, so I'm doing something like this:
<%= auto_complete_result @user, :lastname %>
Is there a way to display both the firstname and lastname in the <li> that is produced?
I've tried having my format.js respond by calling a partial which contains both the firstname and lastname, and it displays properly when I trigger the autocomplelte, but then when I submit the form, both the firstname and lastname get injected into my :lastname field
@Jeff, sphinx has some "fuzzy" matching for phrases, where there need to be a certain number of words a given distance a part. See the "extended" match mode for this behavior.
But I don't think this is what you're looking for. If you want fuzzy searching on a given word, where similar words are also found, then I don't think Sphinx supports this.
You may want to look into Xapian. It has some powerful features regarding this. Including stemming which can find variations of a given word (run, runs, running, etc.). it also supports spelling correction to find terms which are similar to a given word.
Dude, Ryan Bates. You are the man. That was AWESOME. I learned so much in that action-packed video. Thanks so much for the free Rails University courses. You are the man! I hope Obama nominates you for the position of vice-president, so that the entire nation will learn how to bitch-slap rails code like you!!
@eddie, I would say that it is possible, the parameter passed to the active record observer methods (after_save and after_destroy) is the record which can be tested to check what it is, check out the api documentation, it has an example using two models: http://api.rubyonrails.com/classes/ActionController/Caching/Sweeping.html
Thanks for the podcast Ryan, I've been looking into the various search technologies for a while. As far as I can tell, one advantage to Ferret is it supports a "fuzzy" string match for search parameters. Any suggestions on how to handle this with Sphinx?
some ActiveRecord caveat to care about regarding UTC conversions:
>> time_str = "2008-07-30T09:44:28+02:00"
>> time = Time.parse time_str
if used then like this:
>> XXX.find_all_by_YYY('yyy', :conditions => ["created_at >= ?", time_str])
you see this query in the log:
SELECT * FROM "XXX" WHERE (created_at >= '2008-07-30T09:44:28+02:00')
same happens with:
>> XXX.find_all_by_YYY('yyy', :conditions => ["created_at >= ?", time])
in the mean time, USE this:
>> XXX.find_all_by_YYY('yyy', :conditions => ["created_at >= ?", time.utc])
then you get this perfectly in the log:
SELECT * FROM "messages" WHERE (created_at >= '2008-07-30 07:44:28')
Well done, I really learnt a lot from this cast and so from others. You have made it very simple to me to understand it without reading a single line on thinking sphinx. Thank you, waiting more interesting topics from you
@ bijou and Peter
Just throwing in my chips to let you know I'm also trying to get text_field_with_auto_complete to work sensibly with fields_for.
However, unlike the Complex Forms 1-3 Railscasts, I'm not injecting fields_for with virtual attributes.
I'll post here if I can come up with a solution that isn't too embarrassing.
@Michael, it's best to set up a "cron" job to trigger the rake index task. If you aren't able to do this then you may be able to get your Rails app to spawn a background process to redo the index at a regular interval. I'm not exactly sure how that would work though.
First of all... thanks for the amazing episode again! Thanks for you r help with all the episodes you are making.
I have one thing what i dont understand. How can you manage this on a webhost server you dont maintain yourself? You have to restart it with ssh every time somebody wrote an article or smt else?
@Ryan, I'd agree with Rafel's idea.
Maybe the comment form could also be moved up (and made collapsable to save space?). This might encourage users to post (even) more comments :)
@glennpow (et al.):
Awesome! Looks sweet. I was searching around on Rails Forums for solutions after just sort of winging it, and came across the following thread: http://railsforum.com/viewtopic.php?id=14905.
It looks like the attribute-fu plugin tidies things up similarly. When I get a chance I'll play around with both methods and see what I can see.
I should mention though that I've got an even more complicated situation - the kind of fields that I use for each subtasks depending on what kind of subtask you are dealing with. So imagine that either the task or the subtask has a select which when selected renders the appropriate fields for that selection. I'm gonna take this as it comes, but it's down the road for me so I'm keeping an eye on it.
@Rafael, thanks for the suggestion. Most blogs do the earlier comments first, so I think it's best to follow that convention. But I'll consider it.
@Xavier, are you referring to delta indexing? See the bottom of the Thinking Sphinx Usage page for more info on that.
http://ts.freelancing-gods.com/usage.html
My English listening is really weak :-), can you please write somewhere what provides instant indexing?
Hey, just a suggestion, what about put the last comment in the top of the page. So, we can read from the more recent to the oldest. =P
Brandon: I think it's a performance concern more than anything, since now your pages controller might start handling a bunch of requests that otherwise would have been handled more efficiently higher up the chain. It's also possible you don't want your page editors to be able to carve out chunks of your root URLspace.
Swist: Ryan uses a helper method to create titles without duplication. There's probably some way to make nifty-generators create the helper method, but all it is is:
def title(title)
content_for(:title) { title }
end
and a yield(:title) in the appropriate spot in the site layout.
How about a episode showing how to use you dotfiles...looks nice on this episode :P
Anyone know how to use text_field_with_auto_complete in place of f.text_field in the partial?
Using Ryan's example:
<%= text_field_with_auto_complete :task_attributes, :name, :object => task %>
Because it's a partial, the id and name attributes are duplicated, so the autocomplete only works on the first instance of the partial, not to mention it's invalid XHTML to have dupe id's.
Thanks,
Mark
@Evan, preview button is coming very soon. :)
@jblanche, you can use the :conditions hash to search by specific fields. I think that will do what you need.
@Swami: I just read this post (http://freelancing-gods.com/posts/thinking_sphinx_reborn)
Multi-model searching is (obviously) supported:
ThinkingSphinx::Search.search "help"
Haven't tried it though. Hope it helps!
Outstanding screencast !
Just one question, how would you manage a more complicated search form.
Let's say that the user can say if he wants to search only by title, author or comments.
Is there an easy way to filter the indexes to use ?
Whoops, sorry about that, didn't realize your comments don't allow links. (suggestion: a preview button)
Here's the bare URL I mentioned in my previous comment:
http://blog.lrdesign.com/2008/07/fixing-problems-with-sphinx-search/
Thanks for the 'cast, Ryan.
I just converted a large application from Ferret to Sphinx last week, and ran into a whole bunch of problems. I wrote a long <a href="http://blog.lrdesign.com/2008/07/fixing-problems-with-sphinx-search/">blog post</a> about the trials and tribulations I went through to get it working, including the fixes.
Though we were using ultrasphinx instead of thinking_sphinx, some of the struggles will be relevant to everyone using sphinx, for example the fact that foxy fixtures generates IDs that are often too large for sphinx's indexing strategy.
@MikeInAZ, thanks for pointing that out. I normally use auto-completion for rake tasks as you may have noticed in this episode. If anyone's interested in that, see my dotfiles:
http://github.com/ryanb/dotfiles
I'm having some trouble with the edit using this method.
For example:
When I go to the edit, and i have several countries associated to it's continents, it keeps the value selected (for example China for the Asian continent). When I change the continent in the parent select it replaces all the select but not the prompted edit value (in this case China).
The question is, how can I replace that first value in the edit view?
nice screencast! thanks!
Thanks for the screencast Ryan, I just implemented TS last week.
Also, instead of thinking_sphinx:index command, you can just type ts:in
ts:start
ts:stop
@Swami, I haven't tried Ferret, so I can't comment too much about that. I have heard it has some stability issues, but that's all I know.
As for searching across multiple models, I believe it's possible with "ThinkingSphinx::Search.search", but I haven't tried it.
@andrej, I don't think Sphinx gives an easy way to highlight the search terms. However you could use the "highlight" helper method Rails provides.
Crazy timing! Just implemented Thinking Sphinx into a major project in place of Solr.
Thanks for the great screen casts. Keep them coming!
Is it possible to do result highlighting with Sphinx to show the search terms?
Long time fan here. Thanks for the continued outstanding quality of your railscasts.
Ferret used to be the de-facto choice. Any reasons not to use Ferret? Why having chosen Sphinx over other solutions?
Is it possible to perform searches across several models?
Outstanding job, Ryan. I think this is your best Railscast yet! Great job showing simultaneously how simple it is to use Thinking Sphinx and how much power you can leverage by drilling down into it. I'll be watching this one again. :)
@Lance - you're welcome!
@Peter
i'm trying.... i tried to get it to work with text_field_tag, because in Ryan's example in this episode, it was used with the object-related text_field. i've put off using auto_complete for now. i need to finish other priorities for a project first before i go back to this... should i go back to this.
@Steven, there isn't a User model in this app. We have a UserSession model, but that's not based on Active Record so you can't build associations through it.
Awesome screen cast, thanks!
I'm curious: why didn't you create/edit/update the comments through the user model association:
@user.comments.build
@user.comments.find(params[:id])
Seems like this might have simplified some of the logic in you UserSession model.
Alright, so I got it to work using options_from_from_collection_for_select to get the options and then feeding them into a select_tag method. It works, but a) it seems like there is a prettier way to do it and b) I'm not sure how to specify a prompt. I've tried putting :prompt => "Select a such and Such" both at the end of the select_tag call and the options_ from_col.. call, and neither works. If anyone has solutions to these minor queries, answers would be welcome and appreciated.
Thanks again!
Shawn, the movie is not damaged, but the url is wrong.
You can get the movie at:
http://media.railscasts.com/videos/001_caching_with_instance_variable.mov
The html it generates is not valid I don't think. Each text field has the same id... ie
<input id="project[task_attributes]__name" name="project[task_attributes][][name]" size="30" type="text" />
this is a problem when you are trying to make each field autocomplete with scriptaculous because it needs a unique id for each input, and this is ignoring the fact they should be unique anyway.
Thanks for tutorial. I recently wrote <a href="http://emmanueloga.wordpress.com/2008/07/26/liquid-coolness/">a blog post</a> about liquid internals, I hope you guys may find it useful.
Greets!
I was able to successfully implement this with the 3-part complex forms application. Vysogot's solution worked, but I had to make a couple of further modifications. Here is the code from my _task partial
...
<label for="task_country_id">Country:</label>
<%= task_form.collection_select :country_id, Country.find(:all), :id, :name, {:prompt => "Select a Country"}, {:onchange => "collectionSelected(this);"} %>
<label for="task_state_id">State or Province:</label>
<%= task_form.collection_select :state_id, State.find(:all), :id, :name, :prompt => "Select a State" %>
</p>
...
Here's what I changed:
-I had to call :country_id (not :country) in the collection_select
-I put the collection_selects in the the same <p> element so that the call to .next() works properly.
-I put the :onchange call in {} brackets
-'model' in the def of collectionSelected() should have been 'state'
I think that that's it for the complex forms application. I'm still not sure how to get this to work with my application, since as I mentioned I can't use collection_select, as what will effectively be the person in my application has a state, but a country only through a state. I'll keep working on it, but if anyone knows what to use instead of a collection_select I would appreciate a comment on it.
Oh, and thanks to Ryan and everyone else who helps everyone out here - Awesome!
@bijou
I'm also trying to incorporate auto-complete with a similar setup to the one introduced in Complex Forms 1-3.
Anyone have any tips?
I would recommend putting the line
params[:product][:category_ids] ||= []
in a before filter. So..
# Top of the controller...
before_filter :initialize_check_boxes, :only => [:create, :update]
# Bottom of the controller as a protected method
def initialize_check_boxes
params[:product][:category_ids] ||= []
end
In relation to the edit form not remembering the child. I got around it by added another onload observer to set the value.
<script>
document.observe('dom:loaded', function() {
$('person_state_id').value = <%= @person.state_id %>;
});
</script>
Not the most elegant, but it works! Good Luck!
Excellent screencast Ryan
@klickverbot, I generated the models from fixtures, which if you don't specify an id, generates one based on the name of the fixture record. That's what you're seeing there.
@Felipe, heh, I record the show in very tiny segments (usually less than a minute each) and edit it all together. Recording a full screencast in one go is very difficult and usually ends up being more work than editing.
(forget the heads and tails.... I just found it... before the "-" the information is encoded in BASE64... should be easier to parse at that point)