Defining indexes for associated models with Thinking Sphinx - ruby-on-rails

What is the proper way of defining indexes on associated models with following configuration?
I have model Locality with lat and lng attributes and associated models Profile and User
class User < ActiveRecord::Base
has_one :user_profile
define_index do
# This doesn't work :(
has "RADIANS(user_profiles.localities.lat)", :as => :lat, :type => :float
has "RADIANS(user_profiles.localities.lng)", :as => :lng, :type => :float
end
end
end
class UserProfile < ActiveRecord::Base
belongs_to :user
belongs_to :locality
end
class Locality < ActiveRecord::Base
has_many :user_profiles
end
I need to define indexes for User model so I can perform geo-searches on it.
Thank you for the answers!

The problem is twofold:
Thinking Sphinx doesn't know that you want to join the user_profile and locality associations.
SQL snippets should be just that - standard SQL - so you can't chain associations within them.
The following should do the trick:
define_index do
# force the join on the associations
join user_profile.locality
# normal SQL:
has "RADIANS(localities.lat)", :as => :lat, :type => :float
has "RADIANS(localities.lng)", :as => :lng, :type => :float
end
Claudio's point of using singular references within the SQL is not correct - within SQL, you want table names. But you do want the correct association references in the join call (hence they're singular there).
Cheers

Don't really know the exact solution but:
You have a typo:
has_one :user_profile
define_index do
# This doesn't work :(
has "RADIANS(user_profiles.localities.lat)", :as => :lat, :type => :float
You are using "user_profiles" for the attribute, it should not be plural, try changing it to: "user_profile".
I repeat, I don't know if you can navigate through associations for this case, but if you can, this should be a typo.
You can read here for more information: http://freelancing-god.github.com/ts/en/geosearching.html

Related

Thinking Sphinx Rails Multiple Association

I have the following models
class Product < ActiveRecord::Base
belongs_to :sub_category
end
class SubCategory < ActiveRecord::Base
belongs_to :category
has_many :products
end
class Category < ActiveRecord::Base
has_many :sub_categories , -> { where("activate = 1") }
end
I need to index my products table.I need to search using category name(which is in category table) and subcategory name(in subcategories table)
ThinkingSphinx::Index.define :product , :with => :active_record do
indexes description
indexes name
indexes merchant_name
indexes sub_category(:sub_category) , :as => :sub_category_name
indexes category(:name) , :as => :cat_name
has sub_category_id
end
The category(:name) is failing.The subcategory is working fine.
Could somebody please help.I tried sub_category.category(:name) but thats also failing
Error Message
ERROR: index 'link_core': sql_range_query: You have an error in your
SQL syntax; check the manual that corresponds to your MySQL server
version for the right syntax to use near 'AS cat_name, products.id AS
sphinx_internal_id, 'Product' AS `sphinx_internal_' at line 1
(DSN=mysql://root:***#localhost:3306/xxxx_dev_phase4)
name should be passed as a chained method, not as an argument
indexes sub_category.category.name , :as => "category_name"
Thanks to the owner Pat for helping me out
concerned github thread

Multiple belongs_to to the same table

I have two tables:
currencies and rates
currencies: id:int, code:string, name: string
rates: id:int, top_currency_id:int, bottom_currency_id:int, rate:float
And I have two active records for them:
class Rate < ActiveRecord::Base
attr_accessible :bottom_currency, :rate, :top_currency, :top_currency_id
belongs_to :top_currency, :class_name => 'Currency', :foreign_key => 'top_currency_id'
belongs_to :bottom_currency, :class_name => 'Currency', :foreign_key => 'bottom_currency_id'
end
class Currency < ActiveRecord::Base
attr_accessible :code, :name
has_many :rates
end
So the problem is:
When I'm tring to execute following code:
top_currency = Currency.find_by_id(1)
#test = Rate.where(:top_currency=>top_currency)
I getting following error:
Mysql2::Error: Unknown column 'rates.top_currency' in
'where clause': SELECT `rates`.* FROM `rates` WHERE `rates`.`top_currency` = 1
Why Rails's magic doesn't work?
Many thanks.
In your two belongs_to methods, change the foreign_key option to primary_key, leaving everything else as is.
belongs_to :top_currency, :class_name => 'Currency', :primary_key => 'top_currency_id'
# ...
By default, an associated object's primary key is id. However, your currency model has three primary keys, the expected id plus two extra keys: top_currency_id and bottom_currency_id. Active Record needs to know which key to look for. Tell it with the primary_key option.
The foreign_key option is needed when a foreign key is different than the association's name (belongs_to :name) plus "_id". Since your foreign key matches the association name plus "_id," you do not need to use the foreign_key option.
From what I see, your code should work in theory. But I do think you are being a bit redundant.
It should be enough to just do this:
class Rate < ActiveRecord::Base
belongs_to :top_currency, class_name: 'Currency'
belongs_to :bottom_currency, class_name: 'Currency'
end
Rails will infer that the foreign key for top_currency is top_currency_id, and bottom_currency_id for bottom_currency.
I don't think you can query on the relationship like that. To use your example:
top_currency = Currency.find_by_id(1)
#test = Rate.where(:top_currency=>top_currency)
You'd have to change it to this:
top_currency = Currency.find_by_id(1)
#test = Rate.where(:top_currency_id => top_currency.id)
But it might just be easier to do this:
top_currency = Currency.find_by_id(1)
#test = top_currency.rates

Thinking-Sphinx Grouping Error

I have have the meeting model which belongs to the project:
class Project < ActiveRecord::Base
has_many :meetings
end
class Meeting < ActiveRecord::Base
belongs_to :project
define_index do
join project
indexes agenda
indexes project.name. :as => :project_name
end
end
I attempt to search with grouping:
Meeting.search("stuff", :group_by => 'project_id', :group_function => :attr)
I get the following error:
group-by attribute 'project_id' not found
Any suggestions?
Many Thanks.
This is just a wild guess based on the examples in the ThinkingSphinx docs (http://freelancing-god.github.com/ts/en/searching.html#grouping), but perhaps you need to include the attribute to be grouped by in the indexing.
Try adding has project_id to your define_index.

Rails: Set creator of Entry

Currently, I can add the creator_id like this in my controller:
#entry = Entry.new(params[:entry].merge(:creator => current_user._id))
If this is my model:
class Entry
include Mongoid::Document
belongs_to :User
field :creator, :type => String
field :title, :type => String
field :content, :type => String
field :scorea, :type => Integer
field :scoreb, :type => Integer
field :scorec, :type => Integer
end
Is there a better way to do this?
Your model doesn't looks very good, do you really want to store the user_id in a string field?
I suggest you change your models to following:
class Entry
include Mongoid::Document
belongs_to :creator, :class_name => 'User', :inverse_of => :entries
# field definitions
end
class User
include Mongoid::Document
has_many :entries, :inverse_of => :creator
end
Once you change the models you can continue using what you are now or alternatively:
#entry = current_user.entries.build(params[:entry])
Update:
The method to initialize entry is not much different in the way I did it. It is just more towards the rails way of doing things. The main difference is that you were not using the associations. From your model definitions it is clear that you want a one-to-many association between user and entries and this is how you create such associations. Associations has a lot of goodies attached to them, like you can do following things:
user.entries << entry # add a entry to users, will automatically change entry.creator_id
entry.creator = user # sets creato_id = user_id
entry.creator # returns associated user. no need to do User.find(entry.creator_id)
user.entries # returns all entries for use <=> Entry.where(creator_id: user.id)
for more details go to http://mongoid.org/docs/relations.html
There are no better way to do. Or you can do it in 2 line :
#entry = Entry.new(params[:entry])
#entry.creator = current_user._id
this second case allow you to add creator field in attr_protected
You can do it in this manner
#entery = Entery.new(params[:entry])
#entery.creator = current_user
or
#entery.creator_id = current_user.id
hence you can assigned id of creator to this entery.

Dynamic fields with Thinking Sphinx

I'm building an application where I have products and categories. Category has_many properties and each property has a list of possible values. After a category is set to the product all properties show up in the form and the user can set that property to one of the properties possible values.
My question is:
Is it possible for Thinking Sphinx to filter the products through a property and property value ex:
:with => {:property_id => property_value}
If it's possible, what is the best way to implement this? If not is there any other library out there to solve this problem?
Thanks
/ Ola
One approach is to store the property_id as multi-value attribute.
class Product < ActivRecord::Base
has_one :category
has_many :properties, :through => :category
KVP = "###"
define_index do
has properties("CONCAT(`properties`.`key`, \"%s\", `properties`.`value`)" %
KVP, :as => :category_key_value
end
def search_with_properties keys, with_attr={}, p={}
wp = (with_attr||{}).dup
values = p.map{|k, v| "#{k}#{KVP}#{v}"} unless p.empty?
wp = wp.merge({:category_key_value => values}) unless values.empty?
search keys, :with => wp
end
end
class Category < ActivRecord::Base
belongs_to :product
has_many :properties
end
class Property < ActivRecord::Base
belongs_to :Category
#key E.g: region
#value E.g: South West
end
Now you can issue following search commands:
Product.search_with_properties("XYZ", nil, :region => "South West")
Try this:
Add the following to your define_index:
has properties(:id), :as => :property_ids
Then you can use :with / :without like:
:with => {:property_ids => property_value}
Does this answer your question:
https://github.com/freelancing-god/thinking-sphinx/issues/356

Resources