Thinking Sphinx searching search across all models - ruby-on-rails-3

i've implemented search for induvidual models and it works.
Now i have my home page which has a form that has fields from several models of my application but searching one field at a time doesn't yield any result on the home page although i can see the query....(searching for tv_show name)
Parameters: {"utf8"=>"✓", "name"=>"count", "broadcast_date_from"=>"", "broadcast_date_to"=>"", "gender"=>"", "organization_id"=>"", "position_id"=>"", "alignment"=>"", "commit"=>"Generate"}
Sphinx Query (1.0ms) SELECT * FROM `episode_core`, `organization_core`, `person_core`, `position_core`, `profession_core`, `segment_core`, `tv_show_core` WHERE MATCH('*count*') AND `sphinx_deleted` = 0 ORDER BY `last_name` ASC, first_name ASC LIMIT 0, 20
Sphinx Found 0 results
Rendered home/index.html.erb within layouts/home (3.0ms)
Completed 200 OK in 13ms (Views: 12.9ms | ActiveRecord: 0.0ms)
when search the model tv_show i have a result.
Parameters: {"utf8"=>"✓", "name"=>"count", "channel"=>"", "starting_time"=>"", "ending_time"=>"", "commit"=>"Search"}
Sphinx Query (0.9ms) SELECT * FROM `tv_show_core` WHERE MATCH('*count*') AND `sphinx_deleted` = 0 ORDER BY `tv_name` ASC LIMIT 0, 20
Sphinx Found 2 results
TvShow Load (0.5ms) SELECT "tv_shows".* FROM "tv_shows" WHERE "tv_shows"."id" IN (9, 4)
Rendered tv_shows/index.html.erb within layouts/application (7.5ms)
Rendered tv_shows/_search.html.erb (0.9ms)
Completed 200 OK in 68ms (Views: 66.7ms | ActiveRecord: 0.5ms)
So why is there a difference?
global search no result
#results = ThinkingSphinx.search.search "#{params[:name]} ",
:star => /[\w#:]+/u,
:order => 'last_name ASC, first_name ASC',
:page => params[:page],
:per_page => 20
model search return results
#tv_shows = TvShow.search "#{params[:name]} #{params[:channel]} ",
:star => /[\w#:]+/u,
:order => 'tv_name ASC',
:page => params[:page],
:per_page => 20
UPDATE
ok removing the :order => 'last_name ASC, first_name ASC', get me somewhere.
Have another question
how do you make it query a specific model depending on the field used in the form?
Parameters: {"utf8"=>"✓", "name"=>"count", "broadcast_date_from"=>"", "broadcast_date_to"=>"", "gender"=>"", "organization_id"=>"", "position_id"=>"", "alignment"=>"", "commit"=>"Generate"}
Profession Load (0.9ms) SELECT "professions".* FROM "professions" ORDER BY name
Organization Load (2.5ms) SELECT "organizations".* FROM "organizations" ORDER BY name
Position Load (2.0ms) SELECT "positions".* FROM "positions" ORDER BY name
Sphinx Query (1.7ms) SELECT * FROM `episode_core`, `episode_delta`, `organization_core`, `organization_delta`, `person_core`, `person_delta`, `position_core`, `position_delta`, `profession_core`, `profession_delta`, `segment_core`, `segment_delta`, `tv_show_core`, `tv_show_delta` WHERE MATCH('*count*') AND `sphinx_deleted` = 0 LIMIT 0, 20
Sphinx Found 4 results
Organization Load (0.5ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" IN (109)
Position Load (0.4ms) SELECT "positions".* FROM "positions" WHERE "positions"."id" IN (164)
TvShow Load (0.4ms) SELECT "tv_shows".* FROM "tv_shows" WHERE "tv_shows"."id" IN (4, 9)
Here i am just using the tv_show field which refer to the TvShow model.
Adding a conditon is not helping....:condition => {:tv_name => params[:name]}
any insight appreciated.
Response(just in case)
Needed to add in the global search view :
<% for result in #results %>
<% if result.class.name == "Organization" %>
<%= render :partial => "organizations/result", :locals => { :result => result } %>
<% elsif result.class.name == "Position" %>
<%= render :partial => "positions/result", :locals => { :result => result } %>
<% elsif result.class.name == "TvShow" %>
<%= render :partial => "tv_shows/result", :locals => { :result => result } %>
<% end %>
<% end %>
and create partial ( _result.html.erb ) for each model in view folder to print the different fields (The partials are optional).

Related

Why isn't my search method working in Ruby on Rails?

In my Ruby on Rails application, I have a cinema system and am trying to return the screen a showing is in when a user searches for the showing.
To display the search drop down I am using this code in my _application.html.erb:
<%= render( :partial => '/screen_lookup', :locals => {:showings => #showings = Showing.all, :my_path => '/screens/display_screens_by_showing' })%>
Which renders the search from the _screen_lookup.html.erb:
<%= form_tag my_path, :method=>'post', :multipart => true do %>
<%= select_tag ('showings_id'),
options_from_collection_for_select(#showings, :id, :showing_times, 0 ),
:prompt => "Showings" %>
<%= submit_tag 'Search' %>
<% end %>
And uses the display_screens_by_showing in the screens_controller:
def display_screens_by_showing
#screens = Screen.showing_search(params[:showing_id])
if #screens.empty?
# assign a warning message to the flash hash to be displayed in
# the div "feedback-top"
flash.now[:alert] = "There are no films of that genre."
# return all products, in alphabetical order
#screens = Screen.all
end
render :action => "index"
end
And this searches using the method in the screen.rb model:
def self.showing_search(showing_id)
screen = Showing.where("id = ?", showing_id).screen_id
self.where("id = ?", screen)
end
Now, the problem I am having is that because a showing belongs_to a screen, and a screen has_many showings, I need to be able to search for the showing, and store that showing's screen_id in a variable to search for the screen that showing is in with, which I have tried doing in the model:
screen = Showing.where("id = ?", showing_id).screen_id
self.where("id = ?", screen)
But the error I am getting is:
NoMethodError in ScreensController#display_screens_by_showing
undefined method `screen_id' for #<ActiveRecord::Relation []>
These are the model relationships:
showing.rb:
class Showing < ActiveRecord::Base
belongs_to :screen
end
screen.rb:
class Screen < ActiveRecord::Base
has_many :showings
end
What code will get my search working?
The problem is that where doesn't return a record, it returns a relation that can be enumerated or chained, instead you want to use find or find_by to return a single record, which is kind equivalent to where + first
screen = Showing.find(showing_id).screen_id
which is sort of like doing
screen = Showing.where(id: showing_id).first.screen_id
If you want to pass a hash you can use find_by which will be like this
screen = Showing.find_by(id: showing_id).screen_id
PS:
I'm not sure what you're doing exactly, but i think those two lines can be merged into a single query ( not sure what it should be returning, but I'm assuming a screen )
def self.showing_search(showing_id)
Showing.find(showing_id).screen
end

Rails WillPaginate::Collection not paginating Array

An existing array vparray is being generated, then sorted by a non-db column rate. It then needs to be paginated :
#vps = vparray.sort_by{|e| e.rate}
#vps = WillPaginate::Collection.create(1, 10, #vps.length) do |pager|
pager.replace #vps
end
The view;
<%= will_paginate #vps, :previous_label => "prev ", :next_label => " next" -%>
renders fine, the number of pages pans out and the page is apparently the first. However, upon: <% #vps.each do |product| %>, the entire sorted array is being rendered.
Apparently, the array can only be populated with values of current page. However
#vps = vparray.sort_by{|e| e.rate}
#vps = #vps.paginate(:page => params[:page], :per_page => 10)
#vps = WillPaginate::Collection.create(1, 10, #vps.length) do |pager|
pager.replace #vps
end
is incorrect. The paginate command actually reduces the found set to the same number as per_page and therefore == only 1 page!
So I'm assuming that line should not be there. The view should be calling the proper page of results
<% #vps.each do |product| %>
something better than
<% #vps.page(params[:page]).each do |product| %>
that generates undefined methodpage for WillPaginate::Collection`
context:
ruby 1.9.3,
rails 3.2.17,
will_paginate 3.0.5
Went and re-read the collection.rb and array.rb libraries.
With controller stating:
require "will_paginate/array"
#vgps = vgp.sort_by{|e| e.rate}
#vgps = #vgps.paginate(:page => params[:page], :per_page => 30)
This is all that is necessary for a sorted array.

Rails SQLException syntax errors (Model.where('date > ? AND date < ?, min, max)

I'm trying to look up the 'events' that fall between two datetimes.
if (params[:timeMin].present? and params[:timeMax].present?)
#events = Event.where('date > ? AND date < ?', params[:timeMin], params[:timeMax])
I keep getting a similar error and I can't figure out how to fix it.
SQLite3::SQLException: near ",": syntax error: SELECT "events".* FROM "events" WHERE (date > '---
- (1i)
- ''2014''
','---
- (2i)
- ''1''
','---
- (3i)
- ''8''
','---
- (4i)
- ''14''
','---
- (5i)
- ''36''
' AND date < '---
- (1i)
- ''2014''
','---
- (2i)
- ''1''
','---
- (3i)
- ''13''
','---
- (4i)
- ''14''
','---
- (5i)
- ''36''
') ORDER BY events.created_at DESC
This is the line causing the issue in the view
<% #events.each do |event| %>
Thanks
Requested info
index.html.erb
<%= form_tag events_path, :method => :get do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= datetime_select :timeMin, params[:timeMin] %>
<%= datetime_select :timeMax, params[:timeMax] %>
<%= submit_tag "Search Near", :name => nil %>
</p>
<% end %>
Using solution from #CDub
log when make request with dates that should return 2 (all) events -> none are returned (empty list)
Started GET "/events?utf8=%E2%9C%93&search=&timeMin%5B%281i%29%5D=2014&timeMin%5B%282i%29%5D=1&timeMin%5B%283i%29%5D=7&timeMin%5B%284i%29%5D=15&timeMin%5B%285i%29%5D=13&timeMax%5B%281i%29%5D=2014&timeMax%5B%282i%29%5D=1&timeMax%5B%283i%29%5D=13&timeMax%5B%284i%29%5D=15&timeMax%5B%285i%29%5D=13" for 127.0.0.1 at 2014-01-13 18:13:45 -0800
Processing by EventsController#index as HTML
Parameters: {"utf8"=>"✓", "search"=>"", "timeMin"=>{"(1i)"=>"2014", "(2i)"=>"1", "(3i)"=>"7", "(4i)"=>"15", "(5i)"=>"13"}, "timeMax"=>{"(1i)"=>"2014", "(2i)"=>"1", "(3i)"=>"13", "(4i)"=>"15", "(5i)"=>"13"}}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'BVjMjs3hJ1HV6udJzEg4-g' LIMIT 1
Event Load (0.1ms) SELECT "events".* FROM "events" WHERE (date > '2014-1-7 15:13:' AND date < '2014-1-13 15:13:') ORDER BY events.created_at DESC
Rendered events/index.html.erb within layouts/application (9.1ms)
Rendered layouts/_shim.html.erb (0.0ms)
Rendered layouts/_header.html.erb (1.1ms)
Rendered layouts/_footer.html.erb (0.2ms)
Completed 200 OK in 53ms (Views: 52.1ms | ActiveRecord: 0.3ms)
You're returning a datetime_select hash which will need to be parsed into a string. One way of doing so is to do the following:
min_hash = params[:timeMin]
max_hash = params[:timeMax]
min_time_string = "#{min_hash['(1i)']}-#{min_hash['(2i)']}-#{min_hash['(3i)']} #{min_hash['(4i)']}:#{min_hash['(5i)']}:#{min_hash['(6i)']}"
max_time_string = "#{max_hash['(1i)']}-#{max_hash['(2i)']}-#{max_hash['(3i)']} #{max_hash['(4i)']}:#{max_hash['(5i)']}:#{max_hash['(6i)']}"
After this parsing, this should work:
#events = Event.where('date > ? AND date < ?', min_time_string, max_time_string)

Why is my log showing a partial rendered twice Rails

I want to show an easier example of the same thing:
Started GET "/greetings/new" for 127.0.0.1 at 2011-09-29 15:30:46 +0700
Processing by GreetingsController#new as JS
Board Load (0.6ms) SELECT "boards".* FROM "boards" WHERE "boards"."id" = 12 LIMIT 1
User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Upload Load (0.2ms) SELECT "uploads".* FROM "uploads" WHERE ("uploads".uploadable_id = 1 AND "uploads".uploadable_type = 'User') LIMIT 1
Rendered greetings/_greeting_form.html.erb (108.9ms)
Rendered greetings/_greeting_form.html.erb (4.1ms)
Rendered greetings/new.js.erb (116.9ms)
Completed 200 OK in 302ms (Views: 126.5ms | ActiveRecord: 1.7ms)
The log shows that the _greeting_form.html.erb is being rendered twice. The partial is rendered with an Ajax call to the controller.
Controller:
def new
#greeting = Greeting.new
#user = current_user || User.new
respond_to do |format|
format.js {render :action => 'new'}
end
end
new.js.erb
if($('#boxGreeting').length == 0){
$('#buttons').after($(" <%=escape_javascript(render 'greeting_form', :user => #user, :greeting => #greeting) %>").fadeIn('fast'));
}
else
{
$('#boxGreeting').replaceWith("<%=escape_javascript(render 'greeting_form', :user =>#user, :greeting => #greeting)%>");
}
You are calling render 'greeting_form' twice in your new.js.erb. If you look into the output .js file in your browser you will see that the partial appears twice.
The browser will later evaluate your javascript if-clause and use either the first or the second of the pre-rendered "greeting_form" partials.
You can avoid parsing it twice by assigning the render result to a variable and then use this variable within the if or else part:
var greeting_form = " <%=escape_javascript(render 'greeting_form', :user => #user, :greeting => #greeting) %>";
if($('#boxGreeting').length == 0) {
$('#buttons').after($(greeting_form).fadeIn('fast'));
}
else {
$('#boxGreeting').replaceWith(greeting_form);
}

Group and count in Rails

I have this bit of code and I get an empty object.
#results = PollRoles.find(
:all,
:select => 'option_id, count(*) count',
:group => 'option_id',
:conditions => ["poll_id = ?", #poll.id])
Is this the correct way of writing the query? I want a collection of records that have an option id and the number of times that option id is found in the PollRoles model.
EDIT: This is how I''m iterating through the results:
<% #results.each do |result| %>
<% #option = Option.find_by_id(result.option_id) %>
<%= #option.question %> <%= result.count %>
<% end %>
What do you get with this:
PollRoles.find(:all,:conditions=>["poll_id = ?",#poll.id]).collect{|p| p.option_id}
You want to use this function to do things like this
PollRoles.count(:all, :group => 'option_id') should return a hash mapping every option_id with the number of records that matched it.