Solved
I want to have my :price and :purchase_date fields to be ordered together in my search index. So it will give the most present date and then the lowest price of the following date. How is this done?
I think there is a bug when doing:
order_by :purchase_date, :desc
order_by :price,:asc
compared to:
order_by(:purchase_date, :desc)
order_by(:price,:asc)
My finished code is like this:
class SearchController < ApplicationController
def index
#search = UserPrice.search do
fulltext params[:search]
paginate(:per_page => 5, :page => params[:page])
facet :business_retail_store_id, :business_online_store_id
order_by(:purchase_date, :desc)
order_by(:price,:asc)
end
#user_prices = #search.results
end
end
UserPrice.order(:by => [:price,:purchase_date])
UserPrice.order("price DESC, purchase_date DESC")
See:
http://guides.rubyonrails.org/active_record_querying.html
http://m.onkey.org/active-record-query-interface
Here's an example from the Sunspot site:
Post.search do
fulltext 'best pizza'
with :blog_id, 1
with(:published_at).less_than Time.now
order_by :price, :desc # descending order , check Documentation link below
order_by :published_at, :desc # descending order , check Documentation link below
paginate :page => 2, :per_page => 15
facet :category_ids, :author_id
end
The Sunspot documentation says:
order_by(field_name, direction = nil) Specify the order that results should be returned in. This method can be called multiple times; precedence will be in the order given.
See:
http://outoftime.github.com/sunspot/
http://outoftime.github.com/sunspot/docs/index.html
Related
I have a search implemented with the gem sunspot_solr. I would like to add links in the search results to be able to filter the search by alphabetical order and other parameters.
my controller is
class SearchController < SuperSiteController
def index
#sunspot_search = Sunspot.search User, Post do |query|
query.keywords #search_query
query.paginate(:page => params[:page], :per_page => 30)
end
#posts = #sunspot_search.results
end
I wish I could filter for older, recent, and alphabetical order within your search has already been completed. I did not find anything in the documentation about this.
Has anyone worked with this type of search before, and if so, do you know the best practice for doing this?
I think you aim to order results based on a property (data field) of documents.
For example, to sort the results of Post model by created_at, you have to add this field to the index definition in app/models/post.rb as below:
class Post < ActiveRecord::Base
searchable do
...
time :created_at
...
end
end
And then in you SearchController sort the result as below:
class SearchController < SuperSiteController
def index
Post.search do
fulltext #search_query
paginate(:page => params[:page], :per_page => 30)
order_by :created_at, :desc #:desc for descending, :asc for ascending
end
#posts = #sunspot_search.results
end
In order to order results alphabetically you just have to add the field to you index definition as what mentioned above with text function instead of time and use order_by in SearchController.
Consider the following code snippet from ransack
#search = Post.search(params[:q])
#search.sorts = 'name asc' if #search.sorts.empty?
#posts = #search.result.paginate(
:page => params[:page],
:per_page => 20
)
In my case, the "name asc" is actually a related field in another model.
I am trying to figure out how to sort based on that, while keeping the ransack feature in place.
search.sorts = 'comment_name asc' if #search.sorts.empty? should do it. Substitute comment with the other model name.
I have a column called cached_votes_up in Communities table.
Now I'd like to fetch the records ordered by its number.
#search = Community.search do
fulltext params[:search]
with(:genre_id, params[:genre])
order_by :cached_votes_up, :desc
paginate :page => params[:page], :per_page => 5
end
#communities = #search.results
But this returns the following error:
No field configured for Community with name 'cached_votes_up'
You need to index the cached_votes_up attribute of your object. Add these lines in your Community model:
searchable do
integer :cached_votes_up
end
Using RoR 2.3.8.
Here's my controller code:
class CitiesController < ApplicationController
def show
#city = City.find(params[:id])
#shops = Shop.search #city.name, {
:conditions => {:country => #city.country && (:city => #city.name || :state => #city.state)},
:page => params[:page],
:per_page => 100
}
end
end
The :conditions => {:country => #city.country && (:city => #city.name || :state => #city.state)} obviously doesn't work because I am just trying to explain what I wanna achieve.
:city and :state will be columns from Spots table, not Cities table. I want results to return either one of them fulfills the condition. But have no clue how to do it.
Thanks.
Tass has got it right - with your TS search call, it should look something like this:
def show
#city = City.find(params[:id])
#shops = Shop.search "#{#city.name} #country #{#city.country} (#city #{#city.name} | #state #{#city.state})",
:match_mode => :extended,
:page => params[:page],
:per_page => 100
}
end
You'll note I've set the match mode - Thinking Sphinx will do this automatically if you're using the :conditions argument - but when constructing the query manually, you need to set it yourself.
Place your raw search to Sphinx - you should find the correct method in the TS docu. A reference for raw search. You probably want something like
"#city_country #{#city.country} (#city_name #{#city.name} | #city_state #{#city.state})"
(I'm not sure how TS names the indexes. Check that.)
I am using running a simple find all and paginating with willpaginate, but I'd also like to have the query sorted by the user. The first solution that came to mind was just use a params[:sort]
http://localhost:3000/posts/?sort=created_at+DESC
#posts = Post.paginate :page => params[:page], :order => params[:sort]
But the problem with his approach is that the query is defaulting as sorting by ID and I want it to be created_at.
Is this a safe approach to sorting and is there a way to default to created_at?
I’d use a named scope for providing the default order (available since Rails 2.1).
You’d add the scope in your Post model:
named_scope :ordered, lambda {|*args| {:order => (args.first || 'created_at DESC')} }
Then you can call:
#posts = Post.ordered.paginate :page => params[:page]
The example above will use the default order from the named_scope (created_at DESC), but you can also provide a different one:
#posts = Post.ordered('title ASC').paginate :page => params[:page]
You could use that with Romulo’s suggestion:
sort_params = { "by_date" => "created_at", "by_name" => "name" }
#posts = Post.ordered(sort_params[params[:sort]]).paginate :page => params[:page]
If params[:sort] isn’t found in sort_params and returns nil then named_scope will fall back to using the default order.
Railscasts has some great info on named_scopes.
In general, the way to supply default values for Hash and Hash-like objects is to use fetch:
params.fetch(:sort){ :created_at }
A lot of people just use || though:
params[:sort] || :created_at
I prefer fetch myself as being more explicit, plus it doesn't break when false is a legitimate value.
The Ruby idiom to set a default would be:
#posts = Post.paginate :page => params[:page], :order => params[:sort] || "created_at"
But the approach isn't safe. The paginate method will not bother with a parameter like "created_at; DROP DATABASE mydatabase;". Instead, you could use a dictionary of valid sort parameters (untested):
sort_params = { "by_date" => "created_at", "by_name" => "name" }
#posts = Post.paginate :page => params[:page], :order => sort_params[params[:sort] || "by_date"]
So that the URI becomes:
http://localhost:3000/posts/?sort=by_date
I prefer this idiom:
#posts = Post.paginate :page=>page, :order=>order
...
def page
params[:page] || 1
end
def order
params[:order] || 'created_at ASC'
end