So what I have is a model Referent that has multiple attributes for example nom and prenom.
I was able to search each attribute in my model using one search value. But then I tried having one text_field for each attribute so for nom I would have one text_field and for prenom I would have another.
So it would search for all Referent who have that nom and that prenom but I'm not capable of seperating those two search. Right now it just take one of the value and search in both nom and prenom with the same value
View:
<h2>Search Referent</h2>
<%= form_tag(referents_path, :method => "get", id: "search-form") do %>
<%= text_field_tag :search, params[:search], placeholder: "Nom" %>
<%= text_field_tag :search, params[:search], placeholder: "Prenom" %>
<%= submit_tag "Search", class: 'btn btn-info' %>
<% end %>
Controller:
def index
#referents = Referent.all
if params[:search]
#referents = Referent.search(params[:search]).order("created_at DESC")
else
#referents = Referent.all.order("created_at DESC")
end
end
Model:
def self.search(search)
where("nom || prenom ILIKE ?", "%#{search}%")
end
Right now it just seems to take the value of the second text_field and use that for the search. I'm using postgresql.
The full view:
<div class="container">
<h2>Search Referent</h2>
<%= form_tag(referents_path, :method => "get", id: "search-form") do %>
<%= text_field_tag :search_nom, params[:search], placeholder: "Nom" %>
<%= text_field_tag :search_prenom, params[:search], placeholder: "Prenom" %>
<%= submit_tag "Search", class: 'btn btn-info' %>
<% end %>
<h2>List de Referent</h2>
<table class="table table-hover">
<tr>
<th>Nom</th>
<th>Prenom</th>
<th>Titre</th>
<th>Departement</th>
<th>Cellulaire</th>
<th>Bureau</th>
<th>Fax</th>
<th>Courriel</th>
<th>Organisme Referent</th>
</tr>
<% #referents.each do |referent| %>
<tr>
<td><%= referent.nom %></td>
<td><%= referent.prenom %></td>
<td><%= referent.titre %></td>
<td><%= referent.departement %></td>
<td><%= referent.cellulaire %></td>
<td><%= referent.bureau %></td>
<td><%= referent.fax %></td>
<td><%= referent.courriel %></td>
<td><%= link_to referent.organismereferent.nom_organisation, organismereferent_path(referent.organismereferent_id) %></td>
</tr>
<% end %>
</table>
</div>
Error using Ramon answer
I would do it like this
<h2>Search Referent</h2>
<%= form_tag(referents_path, :method => "get", id: "search-form") do %>
<%= text_field_tag :search_nom, params[:search_nom], placeholder: "Nom" %>
<%= text_field_tag :search_prenom, params[:search_prenom], placeholder: "Prenom" %>
<%= submit_tag "Search", class: 'btn btn-info' %>
<% end %>
Controller
def index
#referents = Referent.all
search_nom = params[:search_nom]
search_prenom = params[:search_prenom]
#referents = Referent.search(search_nom, search_prenom).order("created_at DESC")
end
Model
def self.search(search_nom, search_prenom)
where("nom ILIKE ? or prenom ILIKE ?", "%#{search_nom}%", "%#{search_prenom}%")
end
I'm trying to save a recurring_select to a serialized attribute to handle recurring events on a rails app.
Using Jayson's post I manage to get the schedule saved but now I can't get the saved
attribute shown in index view or update the recurring_select in _form view
This is my model
class Todo < ActiveRecord::Base
attr_accessible :item, :completed, :schedule, :start_date
after_initialize :default_values
validates :item, presence: true
belongs_to :list
belongs_to :tasklib,
:foreign_key=>"item"
#recuring model
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :schedule
serialize :schedule, Hash
def schedule=(new_schedule)
write_attribute(:schedule,RecurringSelect.dirty_hash_to_rule(new_schedule).to_hash)
end
def converted_schedule
the_schedule = Schedule.new(self.start_date)
the_schedule.add_recurrence_rule(RecurringSelect.dirty_hash_to_rule(self.schedule))
the_schedule
end
end
This is my index view :
h1><%= #list.name %></h1>
<table class="table table-striped">
<thead>
<tr>
<th><%= model_class.human_attribute_name(:item) %></th>
<th><%= model_class.human_attribute_name(:start_date) %></th>
<th><%= model_class.human_attribute_name(:schedule) %></th>
<th><%=t '.actions', :default => t("helpers.actions") %></th>
</tr>
</thead>
<tbody>
<% #list.todos.each do |todo| %>
<tr>
<td><%= todo.item %></td>
<td><%= todo.start_date %></td>
<td><%= todo.schedule %></td>
<td>
<%= link_to t('.edit', :default => t("helpers.links.edit")),
edit_list_todo_path(#list, todo), :class => 'btn btn-mini' %>
<%= link_to t('.destroy', :default => t("helpers.links.destroy")),
list_todo_path(#list, todo),
:method => :delete,
:confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')),
:class => 'btn btn-mini btn-danger' %>
</td>
</tr>
<% end %>
</tbody>
</table>
and this is my _form view:
<%= simple_form_for [#list, if #todo.nil? then #list.todos.build else #todo end], :html => { :class => 'form-horizontal' } do |f| %>
<%-# f.input :item, input_html: {class: "span6", rows: 3} -%>
<%= f.collection_select :item, Tasklib.order(:name),:name,:name, include_blank: true %>
<%= f.label :start_date, "date" %>
<%= f.input :start_date %>
<%= f.label :schedule %>
<%= f.select_recurring :schedule, nil, :allow_blank => true %>
<div class="form-actions">
<%= f.submit 'Save', :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
lists_path, :class => 'btn' %>
</div>
<% end %>
OK I found it !
The model should be :
def schedule=(new_schedule)
if new_schedule == nil
new_schedule = IceCube::Schedule.new( self.start_date )
end
write_attribute(:schedule, RecurringSelect.dirty_hash_to_rule(new_schedule).to_hash)
end
def converted_schedule
if !self.read_attribute(:schedule).empty?
the_schedule = IceCube::Schedule.new( self.start_date )
the_rule = RecurringSelect.dirty_hash_to_rule( self.read_attribute(:schedule) )
if RecurringSelect.is_valid_rule?(the_rule)
the_schedule.add_recurrence_rule( the_rule)
end
the_schedule
end
end
and the form view should only set a new recurring select like:
<%= f.select_recurring :schedule, [ ["No recurring", "{}"] ], :allow_blank => true %>
I have controller looks like :
## controllers/lhgs_controller.rb
def index
#per_page = params[:per_page] || 10
#totalsolds = Totalsold.paginate(:per_page => #per_page, :page => params[:page]).order('date asc').group_by{ |s| [s.date, s.store_id, s.nomor] }
end
And views :
## index.hmtl.erb
<div id="totalsolds"><%= render 'totalsolds' %></div>
## views/_totalsolds.html.erb
<% #totalsolds.each do |(date, store, nomor), totalsold| %>
<tr>
<td><%= date.strftime("%d/%m/%Y") %></td>
<td><%= nomor %></td>
<td><%= Store.find(store).name %></td>
<% totalsold.each do |ts| %>
<td><%= ts.qty == 0 || ts.qty == nil ? "-" :prod.qty %></td>
<% end %>
<td>Rp<%= number_to_currency(totalsold.sum(&:value), :unit => "") %></td>
<td><%= link_to "edit", edit_bt_path(:store_id => store, :date => date, :nomor => nomor), :class => "btn btn-primer" %></td>
</tr>
<% end %>
...
...
<div class="row">
<div class="col-sm-6">
<% line 65 %>
<%= page_entries_info #totalsolds %>
</div>
<div class="col-sm-6">
<%= will_paginate #totalsolds, :style => 'float:right;margin-top:-5px;height:30px;' %>
</div>
</div>
I got an error :
ArgumentError in Lhgs#index
Showing C:/Sites/cms/app/views/lhgs/_totalsolds.html.erb where line
65 raised:
The #lhgs variable appears to be empty. Did you forget to pass the
collection object for will_paginate?
I found same question and solution, but I can't figure out how to use it for my case.
UPDATE :
I'm not found anywhere #lhgs variable, I tried to change #totalsolds to #lhgs and now my controller lookslike :
## controllers/lhgs_controller.rb
def index
#per_page = params[:per_page] || 10
#lhgs = Totalsold.order('date asc').group_by{ |s| [s.date, s.store_id, s.nomor] }
#lhgs = #lhgs.paginate(:per_page => #per_page, :page => params[:page])
end
And this an error :
NoMethodError in LhgsController#index
undefined method `paginate' for #<Hash:0x4c034a0>
Use rails console :
irb(main):001:0> #lhgs = Totalsold.order('date asc').group_by{ |s| [s.date, s.store_id, s.nomor] }
.... look at pastebin ......
irb(main):002:0> #lhgs.class
=> Hash
pastebin
Solved
reference
On controller :
def index
#per_page = params[:per_page] || 10
#lhgs = Totalsold.order('date asc').group_by{ |s| [s.date, s.store_id, s.nomor] }
#lhgs_keys = #lhgs.paginate(:per_page => #per_page, :page => params[:page])
end
And on view :
<% #lhgs_keys.each do |k| %>
<% #lhgs[k].group_by{ |s| [s.date, s.store_id, s.nomor] }.each |(date, store, nomor), totalsold| %>
.....
....
<% end %>
<% end %>
<div class="row">
<div class="col-sm-6">
<% line 65 %>
<%= page_entries_info #lhgs_keys %>
</div>
<div class="col-sm-6">
<%= will_paginate #lhgs_keys, :style => 'float:right;margin-top:-5px;height:30px;' %>
</div>
</div>
Try it like this:
# controllers/lhgs_controller.rb
def index
#per_page = params[:per_page] || 10
#totalsolds = Totalsold.paginate(:per_page => #per_page, :page => params[:page]).order('date asc').group_by{ |s| [s.date, s.store_id, s.nomor] }
respond_to do |format|
format.html
end
end
And the index.html can be like this:
<% #totalsolds.each do |(date, store, nomor), totalsold| %>
<tr>
<td><%= date.strftime("%d/%m/%Y") %></td>
<td><%= nomor %></td>
<td><%= Store.find(store).name %></td>
<% totalsold.each do |ts| %>
<td><%= ts.qty == 0 || ts.qty == nil ? "-" :prod.qty %></td>
<% end %>
<td>Rp<%= number_to_currency(totalsold.sum(&:value), :unit => "") %></td>
<td><%= link_to "edit", edit_bt_path(:store_id => store, :date => date, :nomor => nomor), :class => "btn btn-primer" %></td>
</tr>
<% end %>
...
<div class="row">
<div class="col-sm-6">
<% line 65 %>
<%= page_entries_info #totalsolds %>
</div>
<div class="col-sm-6">
<%= will_paginate #totalsolds, :style => 'float:right;margin-top:-5px;height:30px;' %>
</div>
</div>
I have an app where the user can create a new project and search for previous projects. On the "create new project" page, the user has the option to enter new info for each field, or select from dropdown menus, if the data is already in the database. As for the search function on the search page. The user can search on many different fields, multiple ways.
UPDATE:
Following a suggestion below, I have gone ahead a built a table that holds the many technologies per project.
Search action
def search
#search = params[:client], params[:industry], params[:role], params[:tech_id], params[:business_div], params[:project_owner], params[:status], params[:start_date_dd], params[:start_date_A], params[:start_date_B], 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])
#all_technols = Technol.all
#technol = Technol.new(params[:tech])
params[:technols][:id].each do |technol|
if !technol.empty?
#project_technol = #project.projecttechnols.build(:technol_id => technol)
end
end
respond_to do |format|
format.html # search.html.erb
format.json { render :json => #project }
end
end
New action:
def new
#project = Project.new
#all_technols = Technol.all
#project_technol = #project.projecttechnols.build
#project_technol = Projecttechnol.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #project }
end
end
Create action
def create
#all_technols = Technol.all
#project = Project.new(params[:project])
#technol = Technol.new(params[:tech])
params[:technols][:id].each do |technol|
if !technol.empty?
#project_technol = #project.projecttechnols.build(:technol_id => technol)
end
end
#project.client = params[:new_client] unless params[:new_client].blank?
#project.project_owner = params[:new_project_owner] unless params[:new_project_owner].blank?
#project.tech = params[:new_tech] unless params[:new_tech].blank?
#project.role = params[:new_role] unless params[:new_role].blank?
#project.industry = params[:new_industry] unless params[:new_industry].blank?
#project.business_div = params[:new_business_div] unless params[:new_business_div].blank?
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render json: #project, status: :created, location: #project }
else
format.html { render action: "new" }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
Tech part of the new view:
<%= stylesheet_link_tag "new" %>
<h1>Create New Project</h1>
<div class="tech">
<%#= label_tag :new_tech, "Technologies Used :" %><br/>
<%= text_field_tag :new_tech, nil, :maxlength => 30 %>
Or
<%#= f.select( :tech, Project.all.map {|p| [p.tech]}.uniq, { :prompt => "Select a previous Technology"}, { :multiple => true, :size => 5 }) %>
<!/div>
<% common_techs = [['Mainframe'],['UNIX'],['Windows Servers'],['Networking'],['CISCO'], ['Win7'], ['Telephony'], ['Web services'], ['Website'], ['Cloud'], ['Virtualisation'], ['Data Centre']] %>
<% db_techs = Technol.all.map {|p| [p.tech]}.uniq %>
<% all_tech = common_techs + db_techs %>
<%= fields_for(#project_technol) do |ab| %>
<%= ab.label "Select previous technologies" %><br/>
<%= collection_select(:technols, :id, #all_technols, :id, :tech, {}, {:multiple => true} ) %>
</div>
<% end %>
<%= stylesheet_link_tag "new" %>
<h1>Create New Project</h1>
<div class="tech">
<%#= label_tag :new_tech, "Technologies Used :" %><br/>
<%= text_field_tag :new_tech, nil, :maxlength => 30 %>
Or
<%#= f.select( :tech, Project.all.map {|p| [p.tech]}.uniq, { :prompt => "Select a previous Technology"}, { :multiple => true, :size => 5 }) %>
<!/div>
<% common_techs = [['Mainframe'],['UNIX'],['Windows Servers'],['Networking'],['CISCO'], ['Win7'], ['Telephony'], ['Web services'], ['Website'], ['Cloud'], ['Virtualisation'], ['Data Centre']] %>
<% db_techs = Technol.all.map {|p| [p.tech]}.uniq %>
<% all_tech = common_techs + db_techs %>
<%= fields_for(#project_technol) do |ab| %>
<%= ab.label "Select previous technologies" %><br/>
<%= collection_select(:technols, :id, #all_technols, :id, :tech, {}, {:multiple => true} ) %>
</div>
<% end %>
</div> <%#= small div %>
<% end %>
<div class="back_button2">
<%= button_to "Back", projects_path , :class => "button", :method => "get" %>
</div>
</div> <%#= small div %>
<% end %>
<div class="back_button2">
<%= button_to "Back", projects_path , :class => "button", :method => "get" %>
</div>
Search Page:
<html>
<%= stylesheet_link_tag "search" %>
<body>
<div id ="title1">Exception Database Search</div>
<div id = "search_op">
<%= form_tag search_path, method: :get do %>
<div class="client">
Client :
<%= select(#projects, :client, Project.order("client").map{|p| [p.client]}.uniq, :prompt => "-Any-", :selected => params[:client]) %></br>
</div>
<div class="industry">
Industry :
<%= select(#projects, :industry, Project.order("industry").map {|p| [p.industry]}.uniq, :prompt => "-Any-", :selected => params[:industry]) %></br>
</div>
<div class="role">
Role :
<%= select(#projects, :role, Project.order("role").map {|p| [p.role]}.uniq, :prompt => "-Any-", :selected => params[:role]) %></br>
</div>
<div class="tech">
<% common_techs = [['Mainframe'],['UNIX'],['Windows Servers'],['Networking'],['CISCO'], ['Win7'], ['Telephony'], ['Web services'], ['Website'], ['Cloud'], ['Virtualisation'], ['Data Centre']] %>
<% db_techs = Project.order("tech").map {|p| [p.tech]}.uniq %>
<% all_tech = Project.order("tech").map {|p| [p.tech]} + Project.order("tech").map {|p| [p.tech2]} + Project.order("tech").map {|p| [p.tech3]} + Project.order("tech").map {|p| [p.tech4]} + Project.order("tech").map {|p| [p.tech5]} %>
<%= fields_for(#project_technol) do |ab| %>
<%= collection_select(:technols, :id, #all_technols, :id, :tech, {}, {:multiple => true } ) %>
</div>
<% end %>
<div class="business_div">
Business Division :
<%= select(#projects, :business_div, Project.order("business_div").map {|p| [p.business_div]}.uniq, :prompt => "-Any-", :selected => params[:business_div]) %></br>
</div>
<div class="project_owner">
Project Owner :
<%= select(#projects, :project_owner, Project.order("project_owner").map {|p| [p.project_owner]}.uniq, :prompt => "-Any-", :selected => params[:project_owner]) %></br>
</div>
<div class="date1">
Select start dates from :
<%= 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] )%>
</div>
<%#= until now <%= l DateTime.now.to_date %><%#=,%>
<h4> OR</h4>
<div class="date2">
exact start dates
<%= text_field_tag :start_date_A, params[:start_date_A], :style => 'width: 80px;' %>
-
<%= text_field_tag :start_date_B, params[:start_date_B], :style => 'width: 80px;' %></br>
</div>
<div class="status">
Status :
<%= select(#projects, :status, Project.order("status").map {|p| [p.status]}.uniq, :prompt => "-Any-", :selected => params[:status]) %></br>
</div>
<div class="keywords">
Keywords :
<%= text_field_tag :keywords, params[:keywords] %></br>
</div>
<div class="results">
Results per page: <%= select_tag :per_page, options_for_select([10,20,50], :selected=>params[:per_page]), { :onchange => "this.form.submit();"} %></br>
<div class="buttons">
<div id="search_button">
<%= submit_tag "Search", name: nil, :class => "button" %>
</div>
<% end %>
<div class="home_button">
<%= button_to "Home", projects_path, :class => "button", :method => "get" %>
</div>
<div id="reset_button">
<%= button_to "Reset Search", search_path, :class => "button", :method => "get" %>
</div>
</div>
</div> <%#search_op div%>
<div class ="menu"></div>
<div id ="section3">
<% if #project_search.total_entries > 0 %>
<% if #search_performed %>
<% if #search_performed %>
<%= hidden_field_tag :direction, params[:direction] %>
<%= hidden_field_tag :sort, params[:sort] %>
<%= hidden_field_tag :per_page, params[:per_page] %>
<%= hidden_field_tag :page, params[:page] %>
<%= will_paginate (#project_search), :class => 'will' %>
<% end %>
</body>
</html>
Models:
class Projecttechnol < ActiveRecord::Base
attr_accessible :project_id, :technol_id
belongs_to :technol
belongs_to :project
end
class Technol < ActiveRecord::Base
attr_accessible :tech
has_many :projecttechnols
has_many :projects, :through => :projecttechnols
end
class Project < ActiveRecord::Base
attr_accessible :edited_first_name, :edited_last_name, :first_name, :last_name, :business_div, :client, :customer_benifits, :edited_date, :end_date, :entry_date, :financials, :industry, :keywords, :lessons_learned, :project_name, :project_owner, :role, :start_date, :status, :summary, :tech_id
validates_presence_of :business_div, :client, :customer_benifits, :end_date, :financials, :industry, :keywords, :lessons_learned, :project_name, :project_owner, :role, :start_date, :status, :summary#, :tech
validates_format_of :industry, :with => /\A[a-zA-Z]+\z/, :message => "field should only have letters"
validates_format_of :business_div, :with => /\A[a-zA-Z]+\z/, :message => "field should only have letters"
validates_format_of :client, :with => /\A[a-zA-Z]+\z/, :message => "field should only have letters"
validates_format_of :project_owner, :with => /\A[a-zA-Z]+\z/, :message => "field should only have letters"
validates_format_of :role, :with => /\A[a-zA-Z]+\z/, :message => "field should only have letters"
has_many :projecttechnols
has_many :technols, :through => :projecttechnols
def self.like(text); "%#{text}%"; end
def self.search(search_client, search_industry, search_role, search_tech_id, search_business_div, search_project_owner, search_exception_pm, search_status, search_start_date_dd, search_start_date_A, search_start_date_B, search_keywords)
# start with a scoped query, to apply more scopes on it afterwards
_projects = Project.scoped
# then, for each of the parameters, apply the scope only if present
if search_client.present?
_projects = _projects.where ['client LIKE ?', like(search_client)]
end
if search_industry.present?
_projects = _projects.where ['industry LIKE ?', like(search_industry)]
end
if search_role.present?
_projects = _projects.where ['role LIKE ?', like(search_role)]
end
if search_tech_id.present?
_projects = _projects.joins(:technols).where("tech.id" => search_tech_id)
end
if search_business_div.present?
_projects = _projects.where ['business_div LIKE ?', like(search_business_div)]
end
if search_project_owner.present?
_projects = _projects.where ['project_owner LIKE ?', like(search_project_owner)]
end
if search_status.present?
_projects = _projects.where ['status LIKE ?', like(search_status)]
end
todays_date = DateTime.now.to_date
if !search_start_date_A.blank? or !search_start_date_B.blank?
search_start_date_A = Date.parse(search_start_date_A).strftime("%Y-%m-%d")
search_start_date_B = Date.parse(search_start_date_B).strftime("%Y-%m-%d")
todays_date = nil
search_start_date_dd = nil
end
if search_start_date_dd.blank?
todays_date = nil
end
if search_start_date_A.present? or search_start_date_B.present?
_projects = _projects.where [' DATE(start_date) BETWEEN ? AND ?', search_start_date_A, search_start_date_B]
end
if search_start_date_dd.present?
_projects = _projects.where ['DATE(start_date) BETWEEN ? AND ?', search_start_date_dd, todays_date]
end
if search_keywords.present?
_projects = _projects.where ['keywords LIKE ?', like(search_keywords)]
end
# now you have applied only the present scopes. return the result, and watch
# the query as it executes.
_projects
end
def self.paginated_for_index(projects_per_page, current_page)
paginate(:per_page => projects_per_page, :page => current_page)
end
end
I can't seem to get the new technologys on the "new project page" to save in the Technols table. I also can't get the search to work properly. Searching for anything in the technology field returns nothing.
Ok, third question of yours about the same project, it starts to be clear where you want to go.
Have you considered storing technologies in a separate table, and an additional join table for the relationship to the Product table?
This way you can select any number of techs for a project, you can search using only one field (it will get only projects related to the chosen technology) and you won't have such complex code.
Use a select tag to choose the technologies in the project form. Validate the project object if you want it to have at least one technology or similar constraint. Use a select on the whole "Technology" table to do the search box. And use
if search_tech_id.present?
_projects = _projects.joins(:technologies).where("technologies.id" => search_tech_id)
end
instead of all that stuff concatenating LIKEs
EDIT: a way to search for projects related to many techs.
To allow searching for "many techs" you can use a multiselect field. You can also add an option for "AND"-ing or "OR"-ing the conditions (that is, search for porjocets related to all the selected techs or any of the selected techs.
In the controller, when you get the list of tech IDs, to search for projects with ALL the selected techs you have to use some SQL magic:
n_techs = search_techs_ids.size
_projects = _projects.joins(:technologies).
select("projects.*").
where("technologies.id" => search_tech_ids).
group("projects.*").
having("count(technologies.id) = #{n_techs}")
On the other side, to search for ANY tech among the selected ones, you can do
_projects = _projects.joins(:technologies).
where("technologies.id" => search_tech_ids)