In a model,
I have defined indexes on some columns and have defined some attributes.
On some external application conditions, I don't want to sphinx to search in some columns values.
In the question name, do you mean attributes or fields? I'm guessing fields, as attributes are only used for filters...
So, to search on just specific fields, you can make a query like the following:
Model.search "#(title, body, user) foo bar", :match_mode => :extended
Put all the fields you want to search on within the parentheses, and you should be good to go.
Related
One table, one column ('headline' in an RSS feed reader). On the front end, I want a text area in which I can enter a comma-separated list of search terms, some multi-word, like for 'politics':
rajoy, pp, "popular party", "socialist party", etc
This could either be stored as part of a separate search model or as a keyword column on the 'category' or 'story' models, so they can be edited and improved with different terms from the front end, as a story develops.
In the RSS reader, have a series of links, one for each story or category, that, on being clicked return the headlines that contain one (or more) of the search terms from the stored list.
In a later version, it would be good to find headlines containing several of the terms in the list, but let's start simple.
Have been doing lots of reading about postgres, rails, different types of searches and queries, but can't seem to find what I want, which I understand is basically "search 'headlines' column against this list of search terms".
Sounds like it might be an array thing that's more to do with controllers in Rails than postgres, or cycling through a giant OR query with some multi-word terms, but I'm not sure.
Does anyone have any better pointers about how to start?
Users
If this will be user specific, I would start with a User model that is responsible for persisting each unique set of search terms. Think logon or session.
Assuming you use the Category method mentioned before, and assuming there's a column called name. Each search term would be stored as a separate instance in the database. Think tags.
headlines that contain one (or more) of the search terms from the stored list
Categories
Since each Category has many terms, and all the queries are going to be OR queries, a model that joins the User and Category, storing a search term would be appropriate.
I'm also assuming you have a Story model that contains the actual stories, although this may not be persisted in the database. I'm predicting your story model has a heading and a body.
Terminal Console
rails generage model SearchTerm query:string user:references category:references && rake db:migrate
Models
On your existing User and Category models you would add:
# app/models/user.rb
has_many :search_terms
has_many categories, through: :search_terms
# app/models/category.rb
has_many :search_terms
has_many :stories
Rails Console
This will automatically make it possible for you to do this:
#user = User.last # this is in the console, just to demonstrate
#category = Category.find_by_name("politics")
#user.search_terms.create {query: "rajoy", category: #category}
#user.search_terms.create {query: "pp", category: #category}
#user.search_terms.where(category_id: #category.id).pluck(:query)
-> ['rajoy', 'pp']
Controllers
What you will want to do with your controller (probably the Category controller) is to parse your text field and update the search terms in the database. If you want to require commas and spaces to separate fields, you could do:
#user.search_terms.where(category: #category).delete_all
params[:search_term][:query].split(", ").map{|x| x.gsub("\"", "")}.each do |term|
#user.search_terms.create({category: #category, query: term})
end
Front End
Personally though, I'd make the front end a bit less complicated to use, like either just require commas, no quotes, or just require spaces and quotes.
Search
For the grand finale, for the Stories to be displayed that have search terms in their heading:
Story.where(#user.search_terms.where(category: #category).pluck(:query).map { |term| "heading like '%#{term}%'" }.join(" OR "))
I would recommend using pg_search gem rather than trying to maintain complicated queries like this.
Note: I'm sure there are errors in this, since I wasn't able to actually create the entire app to answer your questions. I hope this helps you get started with what you actually need to do. I encourage you as you work through this to post questions that have some code.
References
Rails guides: choosing habtm or has many through
gem 'pg_search'
Stack Overflow: Search a database based on query
In the past:
A model User has a string filed first_name. If I write filter :first_name in ActiveAdmin model it would display a drop-down besides the input field with the options Contains, Equals, Starts with, Ends with. So for examle if I choose Contains and write ik, it would find, for example Mike.
Now:
If I use a custom filter I just get a large input, spanning across two columns, which only does exact search. I define my filter like so:
Create a scope in the model.
Whitelist it with ransackable_scopes.
Add it to the admin model like so: filter :my_filter, as: :string.
How do I get the functionality to seach for substrings?
To search for substrings you must use the Ransack Search Predicate Syntax i.e. if you want search a substring on field first_name you must configure this way:
filter :first_name_cont, as: :string, label: "Name"
You can find more information here
I hope it helps.
Where is the best place to define, and how should I store select/radio options for rails (and where to put translations)?
Right now I am defining a Hash within the model and storing the integer keys in the record. I've also placed the translations as 'attributes' within the model translations as it seems to group them together well. ie
PHYSICAL_CONDITIONS = {
1 => "activerecord.attributes.building.condition_excellent",
2 => "activerecord.attributes.building.condition_good",
3 => "activerecord.attributes.building.condition_average_for_age",
4 => "activerecord.attributes.building.condition_fair",
5 => "activerecord.attributes.building.condition_poor"
}.freeze
Is there a better way to do this? I have dozens of fields with options and do not want to create separate tables for each either.
My solution is:
use varchar to store the answer ie 'excellent', 'good' from above. This is actual meaningful data I can see in raw form vs numeric values.
in my model have the options array. The order is maintained and if I re-order them numbers don't matter:
PHYSICAL_CONDITIONS = [
:excellent,
:good
]
under the active record model translation have an options group for each set of options. In the above case I call it :physical_condition_options.
have each translation as a subset of that ie excellent: "Excellent"
If I ever need to convert this to allow multiple selections (checkbox) on the model (happened a number of times), I just remove this subset and make it part of the model. Migration is simpler instead of having to translate numeric values.
have a helper translate those options when passing it to a field
localized_options(Building::PHYSICAL_CONDITIONS,
"activerecord.attributes.building.physical_condition_options.")
This seemed to be the best way to store the data and allow it to be easily translated.
I have a Rails app on Heroku that I'm looking to increase the user-friendlyness of the search for. To do this, I'd like to allow them to text search across multiple fields on multiple models through associations. The input from the user could be a mix of text from any of these fields (and often might span multiple fields) in no particular order.
Example: if you had a car database and wanted to allow the user to search "Honda Fit 2011", where "Honda" came from the manufacturer table, "Fit" came from the model table, and "2011" came from the model_year table.
I'm thinking that I need to build a single field on the root record that contains the unique list of words from each of these fields, and then tokenize the user's input. But that would cause me to use an IN clause, which I'm not sure could benefit from full-text search plugins like pg_search.
So, my question is what's a good way to active a search like this in Rails?
I would take a look at Sunspot_rails. It uses Solr as it's search engine, but allows you index content in all sorts of fruity ways. For instance, I have models indexed with their associations pretty simply:
searchable do
text :description
text :category do
category.present? ? category.name : ''
end
end
You can then search with:
TYPES = [Asset,Product]
Sunspot.search(*TYPES) do |q|
q.fulltext search_str
end
I'm using Rails with the Tire gem (for ElasticSearch) and I need to search across multiple models. Something like:
# title is a field in all models
Tire.search :tasks, :projects, :posts, { :title => "word" }
I know I can search models one by one and then handle these results, but that should be unecessary considering ElasticSearch(Lucene) is document oriented.
Any thoughts?
Thanks,
One possibility is to see them not as distinct models. A compound model could be that every document can be an item belonging to one or many differnt submodels identified by a string constant which can be multivalued.
If you want to retrieve only results from one of those submodels you could add a fixed part to the query which identifies the set of documents belonging to this submodel.
The only caveeat is that you need to have a primary key which is unique(which is not that bad because you can use something like an implicit document key).