Jazz Jazz - 8 months ago 37
Ruby Question

Ruby on Rails: Priority fields while searching

I am trying to make a search page where the user can search project records on many different fields. I want them to be able to search on

, and

At the moment, the page shows drop down menus for "Client" and "Industry", and a text box for "Keywords", so the user can select from the database and search on keywords.

I am having problems searching on a start date as I am trying to give the user the option to search for a "Start Date" in some time scale, i.e. 3 days ago, 1 week ago... in a drop down menu, OR search on specific dates by putting in a "Start Date" and "End Date" by using jquerys datepicker.

I am wanting it to take the specific dates as priority, incase the user selects both a time scale, and specific dates.

Here is my Search View:


<% if @project_search.total_entries > 0 %>
<%= form_tag search_path, method: :get do %>

Client :
<%= select(@projects, :client, Project.all.map {|p| [p.client]}.uniq, :prompt => "-Any-", :selected => params[:client]) %></br>

Industry :
<%= select(@projects, :industry, Project.all.map {|p| [p.industry]}.uniq, :prompt => "-Any-", :selected => params[:industry]) %></br>

Select start date:
<%= select_tag "start_date_dd", options_for_select({
"Select a period" => "",
"3 days ago" => DateTime.now.to_date - 3.days, # = 259_200 sec.
"1 week ago" => DateTime.now.to_date - 1.week, # = 604_800 sec.
"1 month ago" => DateTime.now.to_date - 1.month, # = 2_592_000 sec.
"6 months ago" => DateTime.now.to_date - 6.months, # = 15_552_000 sec.
"1 year ago" => DateTime.now.to_date - 1.year, # = 31_557_600 sec.
}, :selected=>params[:start_date_dd] )%>

or select project dates between

<%= text_field_tag ("start_date") %>


<%= text_field_tag("end_date") %></br>

Keywords :

<%= text_field_tag :keywords, params[:keywords] %></br>

<%= submit_tag "Search", name: nil %>

<% end %>

Here is my project model that works without the specific dates option in search:

class Project < ActiveRecord::Base
attr_accessible :client, :end_date, :industry, :keywords, :start_date,

def self.search(search_client, search_industry, search_start_date_dd, search_keywords)
return scoped unless search_client.present? || search_industry.present? || search_start_date_dd.present? || search_keywords.present?

where(['client LIKE ? AND industry LIKE ? AND DATE(start_date) BETWEEN ? AND ? AND keywords LIKE ?',
"%#{search_client}%", "%#{search_industry}%" ,
search_start_date_dd, DateTime.now.to_date, "%#{search_keywords}%"


def self.paginated_for_index(projects_per_page, current_page)
paginate(:per_page => projects_per_page, :page => current_page)


Here is my search action from the project controller, which only takes into account the timescale search.

def search

@search = params[:client], params[:industry], params[:start_date_dd], params[:keywords]

@project_search = Project.search(*@search).order(sort_column + ' ' + sort_direction).paginated_for_index(per_page, page)

@search_performed = !@search.reject! { |c| c.blank? }.empty?

@project = Project.new(params[:project])

respond_to do |format|
format.html # search.html.erb
format.json { render :json => @project }


I had attempted to include the specific date search, but had no luck. Hopefully someone can point them in the right direction. I am a rails noob so please go easy on me. Thanks in advance.

EDIT: Here is my attempt at getting it to work.

def self.search(search_client, search_industry, search_start_date_dd, search_start_date, search_end_date, search_keywords)
return scoped unless search_client.present? || search_industry.present? || search_start_date_dd.present? || search_start_date.present? || search_end_date.present? || search_keywords.present?

where(['client LIKE ? AND industry LIKE ? AND DATE(start_date) BETWEEN ? AND ? OR DATE(start_date) BETWEEN ? AND ? AND DATE(end_date) BETWEEN ? AND ? AND keywords LIKE ?',
"%#{search_client}%", "%#{search_industry}%" , search_start_date_dd, DateTime.now.to_date, search_start_date, search_end_date, search_start_date, search_end_date,"%#{search_keywords}%"



I would modify the start_date_dd drop down to have a custom field, then add jQuery to show/hide the start_date/end_date fields. Then in your controller, you could look to see if start_date_dd was the custom field, then you should use the start_date/end_date fields.

Other comments:

I would not pass what they searched for directly to the database. I would first run something like the following:

user_supplied_start_date = Time.zone.parse(search_start_date)

That way if they give you an invalid date (parsed user_supplied_start_date == nil), you can give them a warning that you were unable to parse search_start_date and are showing them the last __ days instead.

I've also seen the following code:

def self.search
  scoped = scoped.where(['client like %?%', params[:client]) if params[:client].present?
  scoped = scoped.where(['client like %?%', params[:industry]) if params[:industry].present?

That way you're searching based on what they sent you.

You only list the clients that are currently assigned to a project. Shouldn't the user be able to search for all clients and see that _ client doesn't have any projects?

As a general rule, I prefer helper methods to having code in the view...

Project.all.map {|p| [p.client]}.uniq


# app/helpers/search_helper.rb
def clients_for_select
  Client.select("id, name").map{|c| [c.id, c.name]}