ActiveRecords search with two params - ruby-on-rails

I have a table named measurements and a model named measure.
I have a method one_day_measurements_index in the controller.
Here is the code:
def one_day_measurements_index
#record = Measurement.last
if #record.blank?
#scheduled_on = Date.today
else
#scheduled_on = params[:date] || #record.scheduled_on
end
if #record.blank?
flash[:danger] = "No Measurements Calculated."
redirect_to measurements_path
else
if #scheduled_on.blank?
#scheduled_on = params[:date] || Date.today
end
#page = params[:page] || 1
#per_page = params[:per_page] || WillPaginate.per_page
if params[:search]
#measurements = Measurement
.where("scheduled_on = '#{#scheduled_on}'")
.search(params[:search])
.paginate(:per_page => #per_page, :page => params[:page])
.order("get_inst_status(instrument_id), instrument_id")
else
#measurements = Measurement
.where("scheduled_on = '#{#scheduled_on}'")
.paginate(:per_page => #per_page, :page => params[:page])
.order("get_inst_status(instrument_id), instrument_id")
end
end
measurements_hash #measurements
end
I can use search entering a string, the search method in the model is:
private
def self.search(search)
where('
upper(reading_type) like upper(:search)
or upper(daily_sequence) like upper(:search)
or upper(reading_frequency) like upper(:search)
or upper(reading_period) like upper(:search)
or upper(reading_period) like upper(:search)
or upper(measured_by) like upper(:search)
or upper(measured_with) like upper(:search)
or upper(crew) like upper(:search)
or get_inst_id(instrument_id) like upper(:search)
or get_inst_group_id(instrument_id) like upper(:search)
or upper(get_inst_status(instrument_id)) like upper(:search)
', search: "%#{search}%")
end
In the one_day_measurements_index.html.erb I am using this search tag:
<%= form_tag one_day_measurements_index_path, :method => 'get', class: "search" do %>
<%= text_field_tag(:search, params[:search], options = {:placeholder => "Search", :class => "search_field"})%>
<% end %>
And the path in the routes.rb is:
match 'one_day_measurements_index', to: 'measurements#one_day_measurements_index', via: 'get'
Here is the problem.
The page rendered show on top of the rows the tag for search lets say by a string.
Below the listed rows I have a tag to select with date picker the date since I want to see only the records for that date.
Here it is:
<%= form_tag one_day_measurements_index_path, :method => 'get' do %>
<%= text_field_tag :date, params[:date], options = {:placeholder => "Date (yyyy-mm-dd)", :class => 'datetimepicker'} %>
<%= submit_tag "Show Measurements for Date", class: "btn btn-xs btn-primary"%>
<% end %>
So in a nutshell I have to search tags for a string lets say an instrument type and the date for which I want to see those records. Practically I want to see all the records for instruments of type MPBX on the date of '2015-02-25'. The entire table has records for two more dates after that, '2015-02-26' and '2015-02-27'.
When I am entering the date '2015-02-25' I can see only the records from that date, which is correct. But when I am entering after that in the other search tag the string MPBX, the rendered page shown is for the date of '2015-02-27', the last date recorded in the table. Also no rows are shown since MPBX existed only on the date of '2015-02-25'.
Don't know how to solve this. Any clues?

Okay,
based on your comments, I've first of all refactored your controller code into a bit more readable structure. I hope I've not broken your logic by doing this:
def one_day_measurements_index
unless Measurements.last
#scheduled_on = Date.Today
flash[:danger] = “No Measurements Calculated.”
render(action: "one_day_measurements_index") and return
end
#scheduled_on = params[:date] || #record.scheduled_on
#page = params[:page] || 1
#per_page = params[:per_page] || WillPaginate.per_page
# Now we actually search on date first.
#measurements = Measurement.where("scheduled_on = '#{#scheduled_on}'")
# if the search string is provided, we perform a narrower search on
# the records of the matching date.
if params[:search]
#measurements.where('
upper(reading_type) like upper(:search)
or upper(daily_sequence) like upper(:search)
or upper(reading_frequency) like upper(:search)
or upper(reading_period) like upper(:search)
or upper(reading_period) like upper(:search)
or upper(measured_by) like upper(:search)
or upper(measured_with) like upper(:search)
or upper(crew) like upper(:search)
or get_inst_id(instrument_id) like upper(:search)
or get_inst_group_id(instrument_id) like upper(:search)
or upper(get_inst_status(instrument_id)) like upper(:search)
', search: “%#{params[:search]}%”)
end
# We finish by paginating and ordering our result.
#measurements.paginate(:per_page => #per_page, :page => params[:page])
#measurements.order("get_inst_status(instrument_id), instrument_id")
end
If I made no mistakes, the code should do the following:
Takes the last Measurement in your table.
If not found, then we set the #scheduled_on and show the page.
If the date is provided, we set that as criteria + pagination values
then we actually search using our criteria
I think the problem lies in that you performed a redirect_to which does not store the variables you have defined, basically resetting your query every time.
Let me know how this turns out, and I can make edits based on your feedback.
EDIT
I'm not 100% sure if this approach will, since I do not know enough about your application. It could potentially be that this results in a not working page based on the information in your DB, but unfortunately I do not have enough info to catch all cases.

Related

Multi find search in ruby with date

I have created a multi find search, where I need to filter records by date / category / title. Searching by a category and/or title works, however, when date is typed it doesn't change anything (the results is the same like there was no date typed). I have no idea what else I could do to fix it, I am just a beginner in Ruby. Any idea?
Model:
def self.multi_find(cat_id, search, date_search)
search_condition = "%" + search + "%"
#date_condition = date_search
# test if cat_id is not blank
if not cat_id.blank?
# assign the value of cat_id to a ‘scope’ named :cat
scope :cat, -> { where('category_id = ?', cat_id) }
# using the ‘scope’ cat find where a search string is like a title or an author’s name
self.cat.where("title LIKE ? or event_date = ?", search_condition, date_search.to_date)
else
# find where a search string is like a title or an author’s name
self.where("title LIKE ? or event_date = ?", search_condition, date_search.to_date)
end
end
Controller:
def multi_find
# call an Event class method, using two parameters; a category unique identifier and a search string (author or title)
events = Event.multi_find(params[:cat_id], params[:search_string], params[:event_date_search])
# use Kaminari pagination ...
#events = Kaminari.paginate_array(events.order :title).page(params[:page]).per(6)
# if no products have been found
if #events.empty?
# display a notice
flash.now[:alert] = "No events found - so displaying all events"
# then display all products
#events = Event.order(:title).page(params[:page]).per(6)
end
# use the index view
render :action => "index"
end
The console outputs the SQL Query
Event Load (0.0ms) SELECT "events".* FROM "events" WHERE (category_id = '1') AND (title LIKE '%%' or event_date = '2018-02-14') ORDER BY "events"."title" ASC
View file:
<%= form_tag my_path, :method=>'post', :multipart => true do %>
<%= select_tag ('cat_id'),
options_from_collection_for_select(#categories, :id, :cat_name, 0 ),
:prompt => "Select a Category" %>
<div class="datepicker">
<% #event_date_format %>
<%= text_field_tag :event_date_search %>
</div>
<!-- Key word:-->
<%= text_field_tag :search_string %>
<%= submit_tag 'Search' %>
<% end %>
It's because you have an or in your sql statement. However you should also clean up your code a bit.
def self.multi_find(cat_id, search, date_search)
result = self.all
result = result.where(category_id: cat_id) if cat.id.present?
result = result.where('title LIKE ?', "%#{search}%") if search.present?
result = result.where(event_date: date_search) if date_search.present?
result
end

Search/ filter method for all attributes in my index table

I'm trying to write a row for my index table that filters my objects regarding a specific value of a specific column. What I have until now is this:
pimps_controller.rb:
def index
#pimps = Pimp.search(params[:search])
end
pimp.rb:
def self.search( search)
if search
where('title LIKE ?', "%#{search}%")
else
scoped
end
end
A part of view:
<%= text_field_tag :search, params[:search] %>
That filters after the objects title only so I tried to alter it to make it functional for different search fields that can filter after different attributes. I want to pass a second parameter value if someone fires the search function to make sure it triggers for the right attributes. That's what I've tried:
pimps_controller.rb
#pimps = Pimp.search(params[:search_column],params[:search])
pimp.rb:
def self.search(search_column, search)
if search
col = "%#{search_column}"
s = "%#{search}%"
where(col 'LIKE ?', s)
else
scoped
end
end
The view:
<%= text_field_tag :search, params[:search], params[:search_column => title] %>
But it's not working. I get an error message for passing the both parameters in one search field I guess. How would you do it?
Here's a simple tutorial on how to do it:
https://we.riseup.net/rails/simple-search-tutorial
In the model, you will have to add the fields with or condition to the query.
def self.search(search)
search_condition = "%" + search + "%"
find(:all, :conditions => ['title LIKE ? OR description LIKE ?', search_condition, search_condition])
end
If you want to define the field to search in the params you can use string interpolation with simple quotes:
%q(text contains "#{search.query}")
You need 2 text fields, one for the column, one for the value:
# view
<%= text_field_tag :search_value, params[:search_value] %>
<%= text_field_tag :search_column, params[:search_column] %>
# controller
#pimps = Pimp.search(params[:search_column], params[:search_value])
# Pimp model
def self.search(search_column, search_value)
if search_value.present? && search_column.present?
column = self.column_names.include?(search_column.to_s) ? search_column : 'title'
value = "%#{search_value}%"
where("#{self.table_name}.#{column} LIKE ?", value)
else
scoped
end
end
The problem about this method is that if you don't type the exact name of the column, it will search the value in the column title. I think you should use a select_tag, listing all searchable columns of the model:
# view
<%= select_tag :search_column, options_for_select(Pimp.column_names.map { |col| [col, col] }, params[:search_column]) %>
This view code will display a select tag with the available columns of the Pimp model. You can easily limit the searchable columns by defining a class method on Pimp:
# Pimp model
def searchable_columns
self.column_names - ['id', 'created_at', 'updated_at']
end
# view
<%= select_tag :search_column, options_for_select(Pimp.searchable_columns.map { |col| [col, col] }, params[:search_column]) %>

:search => :all return empty on rails 3

i have a link_to like this:
<%= link_to "All", cars_path(:search => :all) %>
When i click him i receive this url:
localhost:3000/cars?search=all
The issue is, i have 3 records in database and don't appears nothing with the search link.
My cars_controller.rb have on index:
#cars = Car.search(params[:search])
And in the car.rb model i have a method:
def self.search(search)
result = order('new DESC')
result = joins(:model => :brand).where('brands.title LIKE ? OR models.title LIKE ? OR status LIKE ?', "%#{search}%", "%#{search}%", "%#{search}%").order('new DESC') if search.present?
result
end
I have another methods, but i delimited to this and still not working.
Any suggestions are welcome, thank you!
In your query you are searching for an car that has 'all' in its title or brand name. Is that really what you want? And do you have any cars in your table with such name?
If you just write <%= link_to "All", cars_path %> search won't be present and you should get all cars.
When you are using same params multiply times in an query like this you can make it much shorter if you write it like this.
def self.search(search)
result = order('new DESC')
result = result.joins(:model => :brand).where('brands.title LIKE :search OR models.title LIKE :search OR status LIKE :search', search: "%#{search}%") if search.present?
result
end

How to I make a drop down beside a search box that searches the specific field selected in rails?

Okay so im new to this site but this is what I have:
Report.rb
def self.search(search)
if search
where('JOBLETTER_CD_NUMBER LIKE ? AND DATE LIKE? AND CUST LIKE ?', "%#{search}%")
else
scoped
end
end
end
index.html.erb
select_tag "search", options_for_select([ "Job Letter and CD #", "Date", "Cust", "Job", "Date shipped", "Date billed", "Billed by" ], params[:search])
form_tag reports_path, :method => 'get' do
text_field_tag :search, params[:search], :class=> "form-search", :align => "right"
<%= submit_tag "Search", :JOBLETTER_CD_NUMBER => nil, :class => "btn btn-success", :align => "right"
reports controller
def index
#report = Report.paginate(:per_page => 1, :page => params[:page])
#report = Report.search(params[:search]).paginate(:per_page => 1, :page => params[:page])
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #views }
end
end
The only field it will search is the Job Letter and CD # field I need it to allow me to search whatever is selected in the drop down box. Btw I am using bootstrap fro js and css functions.
Your query has 3 placeholders ? but passed only one argument "#{search}" - if you run it like that, what you really should be getting is an exceptions stating
ActiveRecord::PreparedStatementInvalid: wrong number of bind variables (1 for 3) ...
Also, your select_tag is outside the form, so it won't be passed to the controller at all. If you move it into the form, you'd have to rename (e.g. to column) it since the name search is already used by the text field. Then you could pass both the column and the search parameters to your search function to construct the query.
HOWEVER, this is not safe, since nothing prevents a user to pass in any other column by manipulating the post request, and since you can't use placeholders for column names, there's a danger of SQL injection as well.
There are many solutions out there to construct searches, no need to reinvent the wheel. Take a look at the ransack gem. Here's a recent Railscast on how to use it.

Searching in Ruby on Rails - How do I search on each word entered and not the exact string?

I have built a blog application w/ ruby on rails and I am trying to implement a search feature. The blog application allows for users to tag posts. The tags are created in their own table and belong_to :post. When a tag is created, so is a record in the tag table where the name of the tag is tag_name and associated by post_id. Tags are strings.
I am trying to allow a user to search for any word tag_name in any order. Here is what I mean. Lets say a particular post has a tag that is 'ruby code controller'. In my current search feature, that tag will be found if the user searches for 'ruby', 'ruby code', or 'ruby code controller'. It will not be found if the user types in 'ruby controller'.
Essentially what I am saying is that I would like each word entered in the search to be searched for, not necessarily the 'string' that is entered into the search.
I have been experimenting with providing multiple textfields to allow the user to type in multiple words, and also have been playing around with the code below, but can't seem to accomplish the above. I am new to ruby and rails so sorry if this is an obvious question and prior to installing a gem or plugin I thought I would check to see if there was a simple fix. Here is my code:
View: /views/tags/index.html.erb
<% form_tag tags_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search], :class => "textfield-search" %>
<%= submit_tag "Search", :name => nil, :class => "search-button" %>
</p>
<% end %>
TagsController
def index
#tags = Tag.search(params[:search]).paginate :page => params[:page], :per_page => 5
#tagsearch = Tag.search(params[:search])
#tag_counts = Tag.count(:group => :tag_name,
:order => 'count_all DESC', :limit => 100)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #tags }
end
end
Tag Model
class Tag < ActiveRecord::Base
belongs_to :post
validates_length_of :tag_name, :maximum=>42
validates_presence_of :tag_name
def self.search(search)
if search
find(:all, :order => "created_at DESC", :conditions => ['tag_name LIKE ?', "%#{search}%"])
else
find(:all, :order => "created_at DESC")
end
end
end
If I read your problem correctly, you want to return a row if the tag names for the row matches one of the words passed in the query string.
You can rewrite your search method as follows:
def self.search(search)
all :conditions => (search ? { :tag_name => search.split} : [])
end
If you need partial matching then do the following:
def self.search(str)
return [] if str.blank?
cond_text = str.split.map{|w| "tag_name LIKE ? "}.join(" OR ")
cond_values = str.split.map{|w| "%#{w}%"}
all(:conditions => (str ? [cond_text, *cond_values] : []))
end
Edit 1
If you want pass multiple search strings then:
def self.search(*args)
return [] if args.blank?
cond_text, cond_values = [], []
args.each do |str|
next if str.blank?
cond_text << "( %s )" % str.split.map{|w| "tag_name LIKE ? "}.join(" OR ")
cond_values.concat(str.split.map{|w| "%#{w}%"})
end
all :conditions => [cond_text.join(" AND "), *cond_values]
end
Now you can make calls such as:
Tag.search("Ruby On Rails")
Tag.search("Ruby On Rails", "Houston")
Tag.search("Ruby On Rails", "Houston", "TX")
Tag.search("Ruby On Rails", "Houston", "TX", "Blah")
Tag.search("Ruby On Rails", "Houston", "TX", "Blah", ....) # n parameters
Caveat:
The wild card LIKE searches are not very efficient(as they don't use the index). You should consider using Sphinx (via ThinkingSphinx) OR Solr(via SunSpot) if you have lot of data.
You can try to set up ferret, or if you are really bend on just using rails, try this:
# Break the search string into words
words = params[:search].blank? ? [] : params[:search].split(' ')
conditions = [[]] # Why this way? You'll know soon
words.each do |word|
conditions[0] << ["tag_name LIKE ?"]
conditions << "%#{word}%"
end
conditions[0] = conditions.first.join(" OR ") # Converts condition string to include " OR " easily ;-)
# Proceed to find using `:conditions => conditions` in your find
hope this helps =)
Sounds like you need a full text search. The best search integration right now is with Sphinx and the Thinking_Sphinx plugin. I have used it on several projects and it's super easy to setup.
You do need to install sphinx on your host so if you are using a shared host that could present some issues.
You could also use full text search in a MyISAM MySQL database, but performance on that is pretty poor.
Once you have your sphinx installed you just put what you want to index in your model and call model.search. The results will be a list of model objects. It supports will_paginate as well.
I'd suggest looking at Searchlogic if you don't want to use a separate fulltext search engine (Ferret, Sphinx, etc). It makes simple searches extremely easy, although you may not want to use it in a public facing area without lots of testing.
Also check out the Railscast on it: http://railscasts.com/episodes/176-searchlogic
1.You can do some coding in your controller post as such:-
<pre>
def show
#post = Post.find(params[:id])
#tag_counts = Tag.count(:group => :name, :order => 'updated_at DESC', :limit => 10)
respond_to do |format|
format.html # show.html.erb
format.json { render json: #post }
end
end
</pre>
2.Now make some changes in your view file:-
<pre>
<b>Tags:</b>
<%= join_tags(#post) %>
<%unless #tag_counts.nil?%>
<% #tag_counts.each do |tag_name, tag_count| %>
<tr><td><%= link_to(tag_name, posts_path(:name => tag_name)) %></td>
<td>(<%=tag_count%>)</td>
</tr><% end %>
<%end%>
</pre>
3. And one important thing is that there should be many to many relationship between tags and post.

Resources