Sunspot model assocation - ruby-on-rails

I have two models, an School model and Price model. Every school has a price. I would like to return in the search result school with its prices. I am using rails and sunspot.
School-controller:
class SchoolsController < ApplicationController
def index
#query = params[:search]
#search = School.search do
fulltext params[:search]
paginate :page => params[:page], :per_page => 7
end
#results = #search.results
end
end
School-model:
class School < ActiveRecord::Base
has_many :prices
# sunspot search
searchable do
text :name, :locality
end
end
Index - view
<% for result in #results %>
<tr>
# School name, from the school-model
<td><h3><%= link_to result.name, result %></h3></td>
# School price, from the price-model
<td><h3><%= result.prices.min %> kr</h3></td>
</tr>
<% end %>
How do I return for every school its prices, with sunspot?

Maybe you can do eager loading with :include:
#search = School.search(:include => :prices) do # or :include => :price, depends on the relation
fulltext params[:search]
paginate :page => params[:page], :per_page => 7
end
Additionnal:
If a School can only have one Price, you should replace has_many :prices with has_one :price in your School model. After doing this, you could access to the price you want by doing this: result.price.min (take a look at number_to_currency, you could be interested in this Helper)

Related

How can I link to the ID of a user's profile?

I have two controllers- a ProfilesController and a UsersController. I have a page full of blog posts, and I want each to have a link to the profile of the user who created them. I've been having a wee problem with this lately, and I want to start fresh, but don't know where to begin. How can I go about this?
Post controller:
def index
#shit = Static.all.order('id DESC')
if params[:search]
#posts = Post.search(params[:search]).order("created_at DESC").paginate(page: params[:page], per_page: 5)
else
#posts = Post.all.order('created_at DESC').paginate(page: params[:page], per_page: 5)
end
end
Profiles model:
class Profile < ApplicationRecord
belongs_to :user
end
Users model:
class User < ApplicationRecord
has_secure_password
validates :username, uniqueness: true
has_many :posts, foreign_key: :author
has_many :comments, foreign_key: :author
has_one :profile, foreign_key: :user
after_create :build_profile
def build_profile
Profile.create(user: self) # Associations must be defined correctly for this syntax, avoids using ID's directly.
end
end
BTW not using Devise
Use joins
def index
#shit = Static.all.order('id DESC')
scope =
if params[:search]
Post.search(params[:search])
else
Post.all
end
#posts =
scope.
joins(:users).
joins(:profiles).
order("created_at DESC").
paginate(page: params[:page], per_page: 5)
end
In single #post object you should have relation to owner (user). In your view for each post use route for user_path but provide it with #post.user
Example in view
<% #posts.each do |post| %>
<%= link_to user_path(post.user) %>
//Rest of post content
<% end %>

ruby on rails - Ordering two models

I have two models image.rb and story.rb
I am trying to order them together.
stories_controller.rb looks like this:
def index
#stories = Story.all.order(:cached_votes_total => :desc)
#images = Image.all.order(:cached_votes_total => :desc)
#combined = (#stories + #images).sort_by {|record| record.created_at}
end
private
def story_params
params.require(:story).permit(:title, :content, :category)
end
images_controller.rb looks like this:
private
def image_params
params.require(:image).permit(:title, :image, :image_file_name, :category)
end
In my index.html.erb im tryign to order them both but i run into undefined method errors because they have different parameters.
<% #combined.each do |s| %>
...
<% end %>
is there a way to fix this?
This is an wrong approach, combining two models is not recommended, you should use model association for this.. For example
# Image Model
class Image < ActiveRecord::Base
belongs_to :story
end
# Image Model
class Story < ActiveRecord::Base
has_one :image
end
In the controller..
def index
#stories = Story.find(:all, :include => :image).order(:cached_votes_total => :desc)
end
and finally in the view
<% #stories.each do |story| %>
# here you can access story and story.image
...
<% end %>

Tire - sort by number of related object

I have something like this in my model:
class User < ActiveRecord::Model
has_many :followers, :through => :as_followed_followings, :class_name => "User", :foreign_key => "follower_id", :uniq => true
...
def self.search(params)
tire.search(load: true, page: params[:page], per_page: params[:per]) do
end
end
end
I would like the return an array of users ordered by the count of followers that user has.
So what is the correct way to define mappings and indexes to search through nested object with count property ?
Thanks for reading.
I have solved this problem by creating another field on users table and index that value instead of performing nested search in runtime.
This may not be the best solution but I have deadline. Any better solution is welcome :)
Trying with ...
AsFollowedFollowing.count(:group => :follower_id, :order => "count_all DESC")
This is Ordered Hash that contains user_id => count
If you want to loop this hash, try following
# in controller
#counts = AsFollowedFollowing.count(:group => :follower_id, :order => "count_all DESC")
#users = User.where(:id => #counts.map{|k,_| k})
#in view
<% #counts.each do |k, v| %>
<% user = #users.find{|u| u.id == k} %>
<div><%= user.name %> | <%= v %></div>
<% end %>

How can I fetch only the confirmed users when using devise and Sunspot?

I'm fetching all the users by this now.
However, I want to exclude non-confirmed users.
Their confirmed_at attribute is nil.
How can I?
#search = User.search do
fulltext params[:search]
paginate :page => params[:page], :per_page => 10
end
#users = #search.results
First add a scope to your User model:
scope :confirmed, where("confirmed_at IS NOT NULL")
Then you have just to add the scope before the search
#search = User.confirmed.search do
fulltext params[:search]
paginate :page => params[:page], :per_page => 10
end
EDIT:
Indeed, after a test, the solution above don't seem to work. The scope seems to be ignored. There's another solution:
In your User model you probably have a method like this:
searchable do
text :lastname, :firstname
...
end
You have to add a condition to searchable:
searchable if: proc { |user| user.confirmed? } do
text :lastname, :firstname
...
end
EDIT 2:
There is another way if sometimes you want confirmed users and sometimes all users, but you need to modify you model too.
In you User model:
searchable do
text :lastname, :firstname
boolean :confirmed do
confirmed_at != nil
end
...
end
Then in your controller
#search = User.search do
fulltext params[:search]
with(:confirmed, true) # true if you want confirmed users, false for unconfirmed and if you want all users you don't write this line
paginate :page => params[:page], :per_page => 10
end
I hope this help
I use User.where.not(confirmed_at: nil). You can create a scope in your model to make it easier:
class User < ApplicationRecord
scope :confirmed, -> { where.not(confirmed_at: nil) }
end
and then you can use User.confirmed

Is passing multiple params to thinking_sphinx search method absolutely impossible?

I have a page that when visted brings up the most recently active users. Above the users are some filtering options such as filtering by one or a combination of:
location
gender
sexual preference
age range
country
I'm using a form_tag helper for my form. My issue is passing each of these parameters to my controller:
class BrowsersController < ApplicationController
def index
#default_image = "/assets/default_avatar.jpg"
#users = Profile.search params[:search], :page => params[:page], :per_page => 26
end
end
If I was searching with one field with the param "Search" I would be fine but I have multiple fields, select menu's on my form. How am I suppose to pass that info to my controller in order to filter the search results?
I'm sure I'm not the first to use search filtering in ruby on rails
<%= form_tag browsers_path, :method => 'get' do %>
<p>
Location: <%= text_field_tag :location %><br />
Gender: <%= select_tag :gender,
options_for_select([["Select", nil],
["Male", 1],
["Female", 2]]) %>
<br />
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
<br />
Kind regards
update
#users = Profile.search 'HERE IS WHERE THE POWER LIES', :page => params[:page], :per_page => 20, :conditions_all => { :gender => params[:gender], :location => params[:location]}
I use :conditions_all to get my field params and in rails server logs I can see that they are being picked up.. now I just need to some how get them all seen by thinking sphinx
Update 2
i have has gender in the define_index block and indexes location because it seems i need at least 1 field.
this working to return genders:
#users = Profile.search params[:location], :page => params[:page], :per_page => 40, :with => { :gender => [params[:gender]]}
I've tried to check for both location and gender and it seems to work but I'll double check in console because it's returning 1 female in united kingdom out of 1000 and that could be wrong but I'll double check in console and edit this update appropriately.
I'm not quite sure where you got :conditions_all from - if you're dealing with fields, then :conditions is what you're after:
#users = Profile.search 'HERE IS WHERE THE POWER LIES',
:page => params[:page],
:per_page => 20,
:conditions => {:gender => params[:gender], :location => params[:location]}
But, it sounds like you've got gender as an attribute instead of a field - and so, you want to filter on it instead:
#users = Profile.search 'HERE IS WHERE THE POWER LIES',
:page => params[:page],
:per_page => 20,
:conditions => {:location => params[:location]},
:with => {:gender => params[:gender]}
As I said here, I will try to explain a bit of Thinking Sphinx and my suggested approach to solve your problem.
Let's say you have the following Profile model:
# == Schema Information
#
# Table name: access_number_campaigns
#
# id :integer
# latitude :float
# longitude :float
# created_at :datetime
# updated_at :datetime
class Profile < ActiveRecord::Base
GENDER = {1 => "Male", 2 => "Female"}
belongs_to :country
has_and_belongs_to_many :sexual_preferences
has_and_belongs_to_many :age_ranges
end
And you may have those models:
class SexualPreference < ActiveRecord::Base
has_and_belongs_to_many :profiles
end
class AgeRange < ActiveRecord::Base
has_and_belongs_to_many :profiles
end
class Country < ActiveRecord::Base
has_many :profiles
end
Then you may define your ThinkingSphinx index in the following schema:
# within model Profile
define_index
has "RADIANS(latitude)", :as => :latitude, :type => :float
has "RADIANS(longitude)", :as => :longitude, :type => :float
has sexual_preferences(:id), :as => :sexual_preference_ids
has age_ranges(:id), :as => :age_range_ids
has country_id, :type => :integer
has gender, :type => :integer
end
And you can create a class to build the following ThinkingSphinx query to handle all needed associations and attributes:
Profile.search "your keywords", :page => 1, :per_page => 10, :with => {"#geodist" => 0.0..NUMBER_OF_METERS, :with_all=>{:sexual_preference_ids=>["1", "2", "3"], :age_range_ids=>["1", "2", "3"], :country_id => ["123"], :gender => ["1"]} }
You can see above a Thinking Sphinx search query with :with and :with_all hashes included. There is also an important Sphinx's #geodist function called. I hope you have readable example and the best reference for Thinking Sphinx gem you can find here:
Thinking Sphinx reference
Section about indexing
Section about searchin
Section about geodist
I hope you enjoy reading my example and very clear Thinking Sphinx reference.

Resources