Mapping search results in rails when working with Association - ruby-on-rails-3

I have a two models as:
Product { has_may variants}
Variant {belongs to product}
I used Sunspot search, and in result I retrieved selected variants, now I want this result as my search result contains the each Product who's one or more variant is retrieved by the search.
code sample of search is as follows:
#search = Sunspot.search(Spree::Variant) do
keywords params[:keywords]
with :is_active, true
with :deleted_at,nil
if params[:ah].present? && params[:al].present?
(Date.parse(params[:al])..Date.parse(params[:ah])).each do |d|
with :f2r_available_on, d.to_time
end
end
end
#products = #search.results

Let me first clarify: in your code above, #search.results is an array of variant records returned from your search, and you want to get all products associated with one or more of these variants?
If so, then this should do that:
#products = Product.where(:id => #search.results.map(&:product_id))

Related

search for django-objects tagged with all tags in a set

In my django-project have a search function where you can specify tags, like "apple, banana" and by that query for objects of a certain model, tagged with taggit. When I do:
tag_set = Tag.objects.filter(Q(name__in=tag_list))
query_set = Model.objects.filter(Q(tags__in=tag_set))
this gives me objects tagged with either "apple" OR "banana". But I want the AND operator... I tried:
query_set = Model.objects.filter(reduce(operator.and_, (Q(tags__in=x) for x in tag_set)))
but then I get 'Tag' object is not iterable.
Any help?
You can work with:
queryset = Model.objects.all()
for tag in tag_list:
queryset = queryset.filter(tags__name=tag)
This will make a JOIN for each tag, and thus eventually the queryset will only contain Model items that have all the necessary tags.
Another approach is counting the number of matched tags, so:
from django.db.models import Count
tag_set = set(tag_list)
Model.objects.filter(tag__name__in=tag_set).alias(
ntags=Count('tags')
).filter(ntags=len(tag_set))

using .where with .find

I am wondering how I can use where cause with the ActiveRecord find method.
Here is the code I am using:
Supplier.joins(:products).find(params[:id]).where('suppliers.permalink = ? AND variants.master = ?', params[:id], TRUE)
which gives me:
undefined method `where' for #<Supplier:0x007fe49b4eb330>
Supplier.joins(:products).find(params[:id]).where('suppliers.permalink = ? AND variants.master = ?', params[:id], TRUE)
What you're doing here is finding the first record with the id contained in params[:id], then trying to run a where statement on that single record. where only works when run against the model itself.
The confusing part here is that you are using params[:id] both for the primary key (find searches the id field) but then also comparing it to the permalink column in the where clause.
To explain the usage of both methods:
find will search for result(s) from the table, matching the argument you provide it to the id field. You can pass in multiple id's and this method is mostly used to select a row that you know exists, by id. Most commonly it is used with a single id and returns a single instance.
where is used to find all results from the table that match the clause and return a collection of records. You can then refine these results or select one, for example by using .first:
Supplier.joins(:products).where('suppliers.permalink = ? AND variants.master = ?', params[:permalink], true).first
(Note that you're using joins(:products) but then querying variants table. Is this incorrect?)
Supplier.joins(:products).where('suppliers.permalink = ? AND variants.master = ?', params[:id], TRUE).find(params[:id])

Rails Active Record Search - Name includes a word

Im trying to pull all records from a Project model that includes in the project_name the word 'Fox'. I can do an active record search and return specific project_names, like 'Brown Fox':
#projects = Project.where("project_name like ?", "Brown Fox")
But if I want to return all the names that INCLUDE 'Fox', this does not work unless the complete project name is 'Fox':
#projects = Project.where("project_name like ?", "Fox")
How do I do a search that returns all the objects with the word 'Fox' in the name?
Try using:
variable = "Fox"
Project.where("project_name like ?", "%#{variable}%")
You can use the SQL % operator:
#projects = Project.where("project_name like ?", "%Fox%")
Note that if you want your query to return results ignoring the word case, you can use PostgreSQL ilike instead of like.
Did you try ransack ?
With ransack you can do something like
#projects = Project.search(:project_name_cont => "Fox")
If you think it is too much for what you need. you can use the % operator as MurifoX said
Here's a version that will allow you to handle any number of input words and to search for all of them within a name. I was looking for this answer and didn't find the more complicated case, so here it is:
def self.search(pattern)
if pattern.blank? # blank? covers both nil and empty string
all
else
search_functions = []
search_terms = pattern.split(' ').map{|word| "%#{word.downcase}%"}
search_terms.length.times do |i|
search_functions << 'LOWER(project_name) LIKE ?'
end
like_patterns = search_functions.join(' and ')
where("#{like_patterns}", *search_terms)
end
end

Get just one database column in rails 3

How is it possible to get the data of just one column in a database table, e.g. title? I'd like to have an array of strings at the end for bootstrap typeahead.
There's a special method just for that: pluck
Post.pluck :title
If your database model is called "Post" and the column is "title" then
Post.select(:title).all.map(&:title)
Will give you an array of all the titles.
This should work:
def get_titles
Yourcolumn.all.each do |i|
#titles += i.title
end
return #titles
end

Advanced search on multiple associations in Rails

Im trying to build advanced search finder for my Candidate model.
Lets imagine it has couple fields + multiple associations like has_many: languages & has_many: skills. Now I'm building query like this:
query = Candidate.select("*")
if position_name
query = query.where('position_name LIKE ? OR position_name IS NULL',"%#{position_name}%")
end
if salary
query = query.where('salary <= ? OR salary IS NULL',salary)
end
and so on...
Now I want to add more advanced conditions like to find users who only have such skills like PHP and Java (so return only those users who have both skills)
This works but only when I insert OR
query = query.joins(:skills)
query = query.where('`skills`.`name` = ? OR `skills`.`name` = ?',"Java","PHP")
Additionally I'd like the same also for languages (plus, language have language.name & language.level)
Can someone points me in which direction to look? And also how to build such condition where I can multiple skills or multiple languages?
Have a look at the various search gems like Ransack, Metawhere or Searchlogic
http://rubygems.org/gems/ransack
https://github.com/railsdog/searchlogic
Both Ransack and Searchlogic allow searching on associated models and you can use scopes to restrict the search parameters.
Example Search params for Searchlogic.
[search][admitted_gte]
[search][admitted_lte]
[search][aetiology_like_any][] VIRUS
[search][at_risk_gte]
[search][at_risk_lte]
[search][died_gte]
[search][died_lte]
[search][gezi_reference_like]
[search][id]
[search][incidents_location_encrypted_postcode_like]
[search][lab_confirmed_gte]
[search][lab_confirmed_lte]
[search][onset_first_after]
[search][onset_first_before]
[search][onset_last_after]
[search][onset_last_before]
[search][outbreak_type_equals_any][] FOODBORNE
[search][point_source_date_after]
[search][point_source_date_before]
[search][total_affected_gte]
[search][total_affected_lte]
[search][user_reference_like]
[search][year_equals_any][] 2010
search[order] descend_by_id
Outbreak_Controller.rb Index action returns the results of the Search query. From 17 Search params only a single searchlogic call is required #search = Outbreak.search(params[:search]). The params are whitelisted against a list of allowed search params - code not shown.
def index
#set the default index order to be descending Outbreak id
if !params[:search][:order]
params[:search][:order] = "descend_by_id"
end
if params[:search][:bacterial_agents_bacterium_name_like_any] != nil && !params[:search][:bacterial_agents_bacterium_name_like_any].empty?
params[:search][:bacterial_agents_category_like] = "CAUSATIVE"
end
if params[:search][:viral_agents_virus_name_like_any] != nil && !params[:search][:viral_agents_virus_name_like_any].empty?
params[:search][:viral_agents_category_like] = "CAUSATIVE"
end
if params[:search][:protozoal_agents_protozoa_name_like_any] != nil && !params[:search][:protozoal_agents_protozoa_name_like_any].empty?
params[:search][:protozoal_agents_category_like] = "CAUSATIVE"
end
if params[:search][:toxic_agents_toxin_name_like_any] != nil && !params[:search][:toxic_agents_toxin_name_like_any].empty?
params[:search][:toxic_agents_category_like] = "CAUSATIVE"
end
#Outbreak.search takes all of the given params and runs it against the Outbreak model and it's associated models
#search = Outbreak.search(params[:search])
end