Thinking Sphinx showing excerpts of a many-to-many (or one-to-many) association - thinking-sphinx

I have:
define_index do
.
.
indexes tags.name, :as => tags
end
How do I show the excerpts for tags? Doing search_obj.excerpts.tags does not seem to work.

The excerpts method just calls back to the original object - so you'll need a method on it that returns all the tag data. Something like the following in the model:
def tag_names
tags.collect(&:name).join(' ')
end
And then excerpts calls for that should be:
search_obj.excerpts.tag_names

Related

Rails database query - is it possible to give a column an alias?

I've got to produce a json feed for an old mobile phone app and some of the labels need to be different from my database column names.
I think the most efficient way of doing this would be to do a create an alias at the database level. So I'm doing things like
Site.where( mobile_visible: true ).select("non_clashing_id AS clientID")
which produces the SQL
SELECT non_clashing_id AS clientID FROM `sites` WHERE `sites`.`mobile_visible` = 1 ORDER BY site_name
If I run this query in MYSQL workbench it produces a column with the heading ClientID as I expect, with the required values.
But if I show the object in a rails view I get {"clientID":null},{"clientID":null},{"clientID":null}
What am I doing wrong? Is there a better way of doing this?
This shows how to access the variable
sites = Site.where( mobile_visible: true ).select("non_clashing_id AS clientID")
sites.each do |site|
puts site.clientID
end
I think by default, activerecord loads column definitions from the database. And, it should load value into existing columns only.
Site.columns
I guess you could add one more item to that array. Or you could use the normal query without alias column name, then add alias_attribute like MurifoX did and overwrite as_json method:
class Site < ActiveRecord::Base
alias_attribute :client_id, :non_clashing_id
def as_json(options={})
options[:methods] = [:client_id]
options[:only] = [:client_id]
super
end
end
Try putting this in your model in addition to the database alias:
class model < ActiveRecord::Base
alias_attribute :non_clashing_id, :client_id
...
end

How to search for multiple strings in a database table column?

I am using Rails 3.2.2 and MySQL. I am searching by user name (for instances, John, Anthony, Mark) a database table column this way:
# User controller
User.search_by_name(params[:search]).order(:name)
# User model
def self.search_by_name(search)
if search
where('users.name LIKE ?', "%#{search}%")
else
scoped
end
end
However, since a name can be composed from two or more strings (for instances, John Henry or Henry John, Anthony Maria or Maria Anthony, Mark Alfred or Alfred Mark), I would like to search users also when in the params[:search] are provided more than one name. I tried to use
def self.search_by_name(search)
if search
search.split(' ').each do |string|
where('users.name LIKE ?', "%#{string}%")
end
else
scoped
end
end
but I get the following error (for instance, given I am searching for John Henry):
NoMethodError (undefined method `order' for ["John", "Henry"]:Array).
How can I properly search for multiple names?
I totally think you should do one of the following,
Mysql full text search:
http://devzone.zend.com/26/using-mysql-full-text-searching/
SphinxSearch:
http://www.ibm.com/developerworks/library/os-php-sphinxsearch/
I recommend sphinxsearch since I use it with various cool features
built in with it.
Support for sphinx is amazing too!
Using the squeel gem.
def self.search_by_name(search)
if search
where(name.like_any search.split)
else
scoped
end
end
Note that this will NOT order by matching level. For that you need a search-engine implementation, like gems for sphinx, solr, xapian
also note that your original use of each is incorrent since you meant to 'OR' the conditions. If you do not mind to issue as many db queries as search terms you could even fake the match level ordering.
def self.search_by_name(search)
if search
results = search.split.map do |string|
where('users.name LIKE ?', "%#{string}%").all
end.flatten
ids = results.map(&:id)
# desc order by count of matches
ordered_results = results.uniq.order { |result| -ids.count(result.id) }
else
scoped.all
end
end
This is not an Arel relation that can be further scoped but a plain array though.
Note the 'all' call, so do not even attempt this on a big db.
Also note that this will not order 'a b' above 'b a' if search is 'a b' etc.
So I'm kinda just having fun.

Cannot get information in mysql result with rails

I'm using Rails with ActiveAdmin gem. And I want to select some information from mysql database.
sql = ActiveRecord::Base.connection();
s="SELECT word FROM dics WHERE word LIKE 'tung%'";
ten = sql.execute(s);
But when I printed out "ten" to screen, it showed that:
#<Mysql2::Result:0x4936260>
How can I get the information of records?
I suggest that you don't use ActiveRecord::Base.connection directly. Sticking with ARel syntax should work for most cases, and your example doesn't seem like an edge case.
As stated in the comments above, try the following:
dics = Dic.select(:word).where(["word LIKE ?", "tung%"]).all
In order to pluck some special field of object, not objects themselves, use pluck instead of all:
# instead of .pluck(:word) use real field identifier
dics = Dic.where(["word LIKE ?", "tung%"]).pluck(:word)

Thinking Sphinx "no field found in schema" error

I am pretty new to Sphinx.
Trying to find user with name "bob" and company_id "14".
Controller:
#users = User.search 'bob', :conditions => { :company_id => '14'}
Model:
define_index do
indexes :name
indexes :company_id
end
Error:
index user_core: query error: no field 'company_id' found in schema
I have the 'company_id' in table & I re-indexed everything several times.
When I am just searching for the 'name' everything works properly.
Just as another helpful hint: turns out I had to change the way I called Model.search(), since my field was listed as an attribute (i.e. using has), I needed to call the search method with :with instead of :conditions (for fields).
Attributes should be declared as:
has company_id
So, in you case:
Model:
define_index do
indexes :name
has :company_id
end
And one more helpful hint, if you happen to be an idiot like me:
If you are getting this error and you are correctly using attributes and fields, it may be that you forgot to restart your dev server after adding a new field to the index.

Multiple word searching with Ruby, and MySQL

I'm trying to accomplish a multiple word searching in a quotes database using Ruby, ActiveRecord, and MySQL. The way I did is shown bellow, and it is working, but I would like to know if there a better way to do.
# receives a string, splits it in a array of words, create the 'conditions'
# query, and send it to ActiveRecord
def search
query = params[:query].strip.split if params[:query]
like = "quote LIKE "
conditions = ""
query.each do |word|
conditions += (like + "'%#{word}%'")
conditions += " AND " unless query.last == word
end
#quotes = Quote.all(:conditions => conditions)
end
I would like to know if there is better way to compose this 'conditions' string. I also tried it using string interpolation, e.g., using the * operator, but ended up needing more string processing. Thanks in advance
First, I strongly encourage you to move Model's logic into Models. Instead of creating the search logic into the Controller, create a #search method into your Quote mode.
class Quote
def self.search(query)
...
end
end
and your controller becomes
# receives a string, splits it in a array of words, create the 'conditions'
# query, and send it to ActiveRecord
def search
#quotes = Quote.search(params[:query])
end
Now, back to the original problem. Your existing search logic does a very bad mistake: it directly interpolates value opening your code to SQL injection. Assuming you use Rails 3 you can take advantage of the new #where syntax.
class Quote
def self.search(query)
words = query.to_s.strip.split
words.inject(scoped) do |combined_scope, word|
combined_scope.where("quote LIKE ?", "%#{word}%")
end
end
end
It's a little bit of advanced topic. I you want to understand what the combined_scope + inject does, I recommend you to read the article The Skinny on Scopes.
MySQL fulltext search not working, so best way to do this:
class Quote
def self.search_by_quote(query)
words = query.to_s.strip.split
words.map! { |word| "quote LIKE '%#{word}%'" }
sql = words.join(" AND ")
self.where(sql)
end
end
The better way to do it would be to implement full text searching. You can do this in MySQL but I would highly recommend Solr. There are many resources online for implementing Solr within rails but I would recommend Sunspot as an entrance point.
Create a FULLTEXT index in MySQL. With that, you can leave string processing to MySQL.
Example : http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html