How to index translations of one item in Sunspot - ruby-on-rails

I am using Sunspot/Solr to index my Rails website. I index City name by doing the following:
class City < ActiveRecord::Base
searchable do
text :name
...
end
...
Now I am internationalizing the whole site, using the Globalize3 gem. It saves translations in another table, and get these translations out using the normal accessors.
From the example here (http://osdir.com/ml/rails-oceania/2011-11/msg00047.html) they have:
searchable do
# sorting
string(:job_title) { title }
# keyword / fulltext searching
I18n.available_locales.each do |locale|
text(("title_" + locale.to_s).to_sym, :default_boost => 2)
{ eval("title_" + locale.to_s) }
end
end
So essentially for each locale there is an indexing column in Sunspot, like title_en and title_fr. I am wondering if there is a better approach? (too many columns sounds bad to me)
One alternative I am thinking is to concatenate translations of one item as a single string and put it in another text index column.
Also I was thinking if there is something similar to integer :ids, :multiple => true for texts?
So what's a better way to index multiple translations of the same item name?

I implemented single column language index:
LANGUAGES = {
'en' => 'English',
'fr' => 'Français'
}
#inside city model
text :name_alt do
LANGUAGES.keys.reject{|l| l=='en'}.map do |locale|
read_attribute(:name, locale:locale)
end
end
This uses Rails I18n module and Globalize3. 'read_attribute' is part of Globalize3.
This avoids creating columns per language.
I am not sure whether this is better or the multi column approach.

Related

Find all items where match (or like) a text in a Model within Mongoid in Rails 4

I´m working in a project with Rails 4 and Mongodb as back-end helped by the wonderful gem 'Mongoid' and I want to find all items of my model 'Item' matching a search term using 'sql-like' too.
My model looks like:
class Item
include Mongoid::Document
field :name, :type => String
field :importe, :type => BigDecimal
field :tipo, :type => String
end
Trying to do this in the controller but doesn´t works correctly:
Item.where(name: Regexp.new(".*"+params[:keywords]+".*"))
(where "params[keywords]" is the searchterm) because doesn´t returns anything when there are items with this name value.
How do I make this query?
In ruby rails, we need to use this:
condition = /#{params[:keywords]}/i
Item.where(:name => condition)
Item.where({:name => "/#{params[:keywords]}/i"})

Search integers with Sunspot

I managed to get Sunspot working in my rails setup. My rails setup renders graphs (Chartwell) with input from my database (integers), example: "design: 80, art: 20, code: 40".
Is there a way that I can search for "design" and get all elements with design > 70 (integer, for instance) as output?
You're not giving code, so I'll improvise.
Since you have everything working, I assume you already have defined your design field indexed in searchable definition in your model.
After you've done that, you will have a .search block for Sunspot (or Model) in your active code (most probably in a controller).
So, let's suppose your model name is Graph.
design = params[:design] # guessing, again.
Graph.search do
with(:design).greater_than(design)
# .... other conditions
end
This should work for you.
UPDATE:
Assuming that you have a design:integer column in your db
In your event.rb:
searchable do
text :name, :location, :date_search
integer :design
end
in your events_controller.rb:
#search = Event.search do
fulltext params[:search]
with(:design).greater_than(params[:design].to_i)
end
Note: You should pass :design as a parameter with your search form

How make better Rails I18n (sorting and search by translation)

Now I have model Territory - id, territory_title_locale_key in my database
And I have en.yml and ru.yml files with translations. In future, i want to add more locales. Now I show value - I18n.t("translate_path.#{territory.territory_title_locale_key}")
But I can't fast search territories by title's value and order them by title.
I see variant:
Change database to Territory - id, title, en, ru, es, ... and always type Territory.where(my_condition).select("#{I18n.locale} as title") (for each new locale I must add column to database).
Or Create additional table Translations with polymorph references, translations and locale_ids.
How to make it better?
Take a look at the globalize gem, it does what you're looking for.
https://github.com/globalize/globalize
Example:
class Post < ActiveRecord::Base
translates :title, :text
end
I18n.locale = :en
post.title # => Globalize rocks!
I18n.locale = :he
post.title # => גלובאלייז2 שולט!

Querying embedded objects in Mongoid/rails 3 ("Lower than", Min operators and sorting)

I am using rails 3 with mongoid.
I have a collection of Stocks with an embedded collection of Prices :
class Stock
include Mongoid::Document
field :name, :type => String
field :code, :type => Integer
embeds_many :prices
class Price
include Mongoid::Document
field :date, :type => DateTime
field :value, :type => Float
embedded_in :stock, :inverse_of => :prices
I would like to get the stocks whose the minimum price since a given date is lower than a given price p, and then be able to sort the prices for each stock.
But it looks like Mongodb does not allow to do it.
Because this will not work:
#stocks = Stock.Where(:prices.value.lt => p)
Also, it seems that mongoDB can not sort embedded objects.
So, is there an alternative in order to accomplish this task ?
Maybe i should put everything in one collection so that i could easily run the following query:
#stocks = Stock.Where(:prices.lt => p)
But i really want to get results grouped by stock names after my query (distinct stocks with an array of ordered prices for example). I have heard about map/reduce with the group function but i am not sure how to use it correctly with Mongoid.
http://www.mongodb.org/display/DOCS/Aggregation
The equivalent in SQL would be something like this:
SELECT name, code, min(price) from Stock WHERE price<p GROUP BY name, code
Thanks for your help.
MongoDB / Mongoid do allow you to do this. Your example will work, the syntax is just incorrect.
#stocks = Stock.Where(:prices.value.lt => p) #does not work
#stocks = Stock.where('prices.value' => {'$lt' => p}) #this should work
And, it's still chainable so you can order by name as well:
#stocks = Stock.where('prices.value' => {'$lt' => p}).asc(:name)
Hope this helps.
I've had a similar problem... here's what I suggest:
scope :price_min, lambda { |price_min| price_min.nil? ? {} : where("price.value" => { '$lte' => price_min.to_f }) }
Place this scope in the parent model. This will enable you to make queries like:
Stock.price_min(1000).count
Note that my scope only works when you actually insert some data there. This is very handy if you're building complex queries with Mongoid.
Good luck!
Very best,
Ruy
MongoDB does allow querying of embedded documents, http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanEmbeddedObject
What you're missing is a scope on the Price model, something like this:
scope :greater_than, lambda {|value| { :where => {:value.gt => value} } }
This will let you pass in any value you want and return a Mongoid collection of prices with the value greater than what you passed in. It'll be an unsorted collection, so you'll have to sort it in Ruby.
prices.sort {|a,b| a.value <=> b.value}.each {|price| puts price.value}
Mongoid does have a map_reduce method to which you pass two string variables containing the Javascript functions to execute map/reduce, and this would probably be the best way of doing what you need, but the code above will work for now.

Query on Mongoid Hash Field

I want to query on a Hash field for a Mongoid Class. I'm not sure how I can do this with conditions?
Here is an example:
class Person
include Mongoid::Document
field :things, :type => Hash
end
So, let's say that I have this:
p = Person.new
p.things = {}
p.things[:tv] = "Samsung"
I want to query for the first person with a tv that is a Samsung...
People.first(:conditions => ?????
Thanks in advance.
Person.where('things.tv' => 'Samsung').first
This is where Mongoid and MongoDB really shine. Mongoid's Criteria methods (Person.where, Person.any_of, Person.excludes, etc.) will give you much more flexibility than the ActiveRecord-style finders (passing a :conditions hash to Person.find, Person.first, etc.)
Mongoid's site has some great documentation on how to use Criteria:
http://mongoid.org/en/mongoid/docs/querying.html

Resources