find_with_ferret , multiple model not working - ruby-on-rails

I have 2 models A and B.
class A < ActiveRecord::Base
has_one :b
acts_as_ferret :fields => [:title,:description]
In a_cotroller, i wrote:
#search=A.find_with_ferret(params[:st][:text_search],:limit => :all).paginate :per_page =>10, :page=>params[:page]
The above title and description search is properly working.
class B < ActiveRecord::Base
belongs_to :a
Now,I want to perform a text search by using 3 fields; title, description(part of A) and comment(part of B). Where I want to include the comment field to perform the ferret search.Then,what other changes needed.

The documentation of find_with_ferret indicates that you simply code :store_class_name => :true to enable search over multiple models. While this is true there is a little more to it. To search multiple do the following:
#search = A.find_with_ferret(
params[:st][:text_search],
:limit => :all,
:multi => [B]
).paginate :per_page =>10, :page=>params[:page]
Notice the multi option. This is an array of the additional indexes to search.
Now to get his to work you have to rebuild your indexes after adding :store_class_name => :true to the index definitions.
class A < ActiveRecord::Base
has_one :b
acts_as_ferret :store_class_name => :true, :fields => [:title, :description]
end
OR...
You can simply include Bs fields in the index definition:
class A < ActiveRecord::Base
has_one :b
acts_as_ferret :fields => [:title, :description],
:additional_fields => [:b_content, :b_title]
def b_content
b.content
end
def b_title
b.title
end
end
This makes everything simple, but doesn't allow to search the B model independently of A.

Related

Filtering a relation in Rails

I have this relation in my Product model:
has_many :features, :class_name => 'ProductFeature', :source => :product_feature, :include => :feature
So I can do Product.features
which works fine. But I want to be able to filter that by fields in the feature table, when and if necessary. For example in pseudo code:
find all product features where feature is comparable
compare is a bool field on the feature.
I have been trying for 2 hours solid and cannot figure it out (without writing a new query completely). I can't figure out how to access the feature table's fields from the Product.features relation, as it seems it can only filter on product_features fields.
This is what I have come up with so far:
def features_compare
features.feature.where(:compare => true)
end
But it just says feature is not a valid method, which I understand.
Edit
I have updated my model so the relationships are clearer:
product.rb:
class Product < ActiveRecord::Base
belongs_to :company
belongs_to :insurance_type
has_many :product_features
has_many :reviews
attr_accessible :description, :name, :company
end
product_feature.rb:
class ProductFeature < ActiveRecord::Base
belongs_to :product
belongs_to :feature
delegate :name, :to => :feature
attr_accessible :value
end
feature.rb
class Feature < ActiveRecord::Base
attr_accessible :name, :compare
end
I want to be able to query the product_features that belong to a product and feature where Feature.compare is true. Something like this:
product.rb
def features_compare
product_features.where(:compare => true)
end
This throws an error because compare in in the Feature model, not ProductFeature. I have tried the following in product_feature.rb:
delegate :compare, :to => :feature
but I didn't help.
I will adding a bounty to this in a few hours so please please help me!
find all product features where feature is comparable is just
ProductFeature.joins(:feature).where(:feature => {:compare => true})
You can make that a bit more reusable by introducing a scope:
#in product_feature.rb
scope :with_feature_like, lambda do |filter|
joins(:feature).where(:feature => filter)
end
#elsewhere
ProductFeature.with_feature_like(:compare => true)
#all the product features of a certain product with at comparable features
some_product.product_features.with_feature_like(:compare => true)
Finally, if you want all products with product features with comparable features, you want something like:
Product.joins(:product_features => :feature).where(:feature => {:compare => true})
which of course you can also turn into a scope on Product.
This seems like a has_many :through relationship. Try changing this:
has_many :features, :class_name => 'ProductFeature', :source => :product_feature, :include => :feature
to this:
has_many :product_features
has_many :features, :through => :product_features
As long as your ProductFeature model has this:
belongs_to :product
belongs_to :feature
And you have the appropriate columns on product_features (product_id, feature_id), then you should be able to access that product's features and all the attributes on both Product and ProductFeature.
See here:
http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association
EDIT: Here's how to filter by feature fields.
Product.joins(:features).where(:features => {:name => "Size"})
#product.each |p| { p.features.where(:comparable => true) } is probably your best bet here, but I'm open to being enlightened.

Sort has_many relation in rails 3

my model is
class Job < ActiveRecord::Base
belongs_to :client
end
class Client < ActiveRecord::Base
has_many :jobs
end
in controller i want get client with sorted jobs.
If i do (without ordering)
#client = Client.find(params[:id], :include => {:jobs => :status})
It is all ok. But if i add ordering:
#client = Client.find(params[:id], :include => {:jobs => :status}, :order => 'job.level DESC')
// :order is dynamicly set (not in this example) - i know about :order in has_many.
the result is only 3 rows (for every job.level one). I logged the sql query and executed it and result is ok, but in app i have only these 3 rows.
What is the right way to sort jobs? Thank you
You could try specifying the order directly in the model instead of the controller
class Job < ActiveRecord::Base
belongs_to :client, :order => 'level DESC'
end
OR
class Client < ActiveRecord::Base
has_many :jobs, :order => 'level DESC'
end
Also, what data type is the level in the Jobs model? If you could post your logs for the sql queries that would be helpful as well. Also, have you tried
:order => 'jobs.level'
instead of the singular job.level used in the code you posted?
This is not what i originally wanted, but it works, so this is answer
#jobs = #client.jobs.find(:all, :order => sort_column + " " + sort_direction)

acts_as_api rails query for non related field

I've two tables which are related say A and B. A has has_many to B and B belongs_to A. However I've a field in A stored say A.account_number. And A is totally unrelated to table C which is accounts table. D has account details like addresses and other details. C has has_many relation to D and D belongs_to C. Now using acts_as_api in A and B . I wrote a big query which almost fetches every field I need except for the account and acoount details. How do I get this details using acts_as_api. I tried using calling scopes sub resource method. but it did not work. Any ideas. Please share. I'm new to rails. Here is my code.
Let's Say
A-> item_people
B-> item_people_roles
C-> people_accounts
D-> people_account_details
Class ItemPeople
class ItemPeople < ActiveRecord::Base
has_many:item_people_roles, class_name => "ItemPeopleRole", :dependent => :destroy
accepts_nested_attributes_for :item_people_roles, :allow_destroy => true, :reject_if => :all_blank
acts_as_api
api_accessible :bill_rewriting do |bill|
bill.add :account_number
bill.add :item_people_roles
end
end
Class ItemPeopleRoles
class ItemPeopleRole < ActiveRecord::Base
attr_accessor :messages
belongs_to :item_people, :class_name => "ItemPeople"
acts_as_api
api_accessible :bill_rewriting do |bill|
bill.add :item_people_id, :as => :shipper_id, :if => lambda{|u|u.role_type_code=="SHIPPER"}
bill.add :item_people_id, :as => :consignee_id, :if => lambda{|u|u.role_type_code=="CONSIGNEE"}
bill.add :item_people_id, :as => :ship_to_id, :if => lambda{|u|u.role_type_code=="SHIPTO"}
end
end
Class C People
class People < ActiveRecord::Base
# This model has account number
# account type fields
end
Class D People_Details
class PeopleDetails < ActiveRecord::Base
# This model has address1, address2, name1, name2
end
Now according to people's role there in the itempeopleroles, I need to get people and people details fields in acts_as_api of ItemPeople. Hope I'm clear now
The best way to accomplish this is via a template Proc/lambda
api_accessible :public do |template|
template.add lambda { |record,options|
# look at options, and use those to build your custom data
return [the correct data]
}, :as => :a_magic_field
end
Then in your controller, get a results set, "annotate" it, and then render it.
raw_results = Model.where(... some where conditions ....)
results = raw_results.as_api_response(:public, ... [some other options to appear in your lambda])
And finally render it:
respond_to do |format|
format.json {render :json => results, :callback => params[:callback]}
format.xml {render :xml => results}
end
With this, you can write any code you want inside your lambda to navigate your data structures, regardless of how it is laid out. How it will perform is another question....
(I can't add comments yet).
If A has A.account_number and C is the table of accounts, why don't you have associations between A and C (and maybe even A and D as well as C and D)?
My "answer" is to add those associations and then just use the proper :include syntax. I don't really see what acts_as_api is providing.

Search by record id with ultrasphinx

I'm trying to search by record id with ultrasphinx on Rails 2.3.8
In my model i tried the following:
class Offer < ActiveRecord::Base
is_indexed :fields => [{:field => 'id', :as => 'offer_id'}]
end
and
class Offer < ActiveRecord::Base
is_indexed :fields => ['id']
end
And I search with
Ultrasphinx::Search.new(:query => "1691")
It doesn't return any results, while searching for other indexed fields does.
Wow. a blast from the past.
Whilst I shifted to ThinkingSphinx after starting off with UltraSphinx, are you sure that you shouldn't be using
class Offer > ActiveRecord::Base
is_indexed :fields => ['id']
end
maybe try that for now and then figure out how to do the AS after.

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