Smart_listing Gem sorting - ruby-on-rails

Im integrating Smart_listing gem onto my Rails App. I have a Beer table in my database and a beer_type column. Right now im trying to set up a sorting function where Users can filter different types of beer. Similar to this functionality example.
Right now it will filter each one type of beer perfectly. However whenever there is more than 1 beer type checked, it would not display the beer types together.
product.rb
scope :with_beer_type_ales, -> (product) { where('beer_type ILIKE?', "%ales%") }
scope :with_beer_type_cream, -> (product) { where('beer_type ILIKE?', "%cream%") }
scope :like, ->(args) { where("name ILIKE? OR beer_type ILIKE? OR description ILIKE?", "%#{args}%", "%#{args}%", "%#{args}%")}
products_controller.rb
def index
products_scope = Product.all
# Make users initally sorted by name ascending
products_scope = products_scope.like(params[:filter]) if params[:filter]
products_scope=products_scope.with_beer_type_ales(params[:with_beer_type_ales]) if params[:with_beer_type_ales] == "1"
products_scope = products_scope.with_beer_type_cream(params[:with_beer_type_cream]) if params[:with_beer_type_cream] == "1"
#products = smart_listing_create :products,
products_scope,
partial: "products/list",
page_sizes: [10, 20, 30],
default_sort: {name: "asc"}
end
index.html.erb
<%= smart_listing_controls_for(:products, {class: "form-inline text-left"}) do %>
<div class="form-group filter input-append" id="search">
<%= text_field_tag :filter, '', class: "search form-control",
placeholder: "Search...", autocomplete: :off %>
<button class="btn btn-primary disabled" type="<%= :submit %>">
<span class="glyphicon glyphicon-search"></span>
</button>
</div>
<h4>Sort By Type:</h4>
<ul>
<li class="checkbox">
<label class="checkbox inline">
<%= hidden_field_tag :with_beer_type_ales, "0" %>
<%= check_box_tag :with_beer_type_ales %> Ales
</label>
</li>
<li>
<label class="checkbox inline">
<%= hidden_field_tag :with_beer_type_cream, "0" %>
<%= check_box_tag :with_beer_type_cream %> Cream
</label>
</li>
</ul>
</div>
<% end %>

You want OR not AND. When you specify multiple where clauses in a chain, rails defaults to AND.
q = Beer.where(true)
q = q.or.where('beer_type ILIKE?', "%ales%") if params[:with_beer_type_ales] == "1"
q = q.or.where('beer_type ILIKE?', "%cream%") if params[:with_beer_type_cream] == "1"

Related

Rails Hotwire - How to search within existing form

I have form that has a section that displays a series of checkboxes for what groups a user manages. I want to add a search box at the top of the checkboxes that allows them to search a name and have it filter the results. From there they can check whatever ones they need to and submit the main form.
The only way I have ever done this is by triggering a from submission. It is not working (not doing anything) I assume because it is within another form. Is there a way to get this to work like I have it below, or is there a better way to set up this filter?
cardrequest form:
<%= form_with(model: cardrequest, id: dom_id(cardrequest), class: "contents") do |form| %>
form fields for cardrequest ...
<div class="mb-4 space-y-4">
<%= form_with url: search_cardrequests_path, method: :get, data: { controller: "search-form", search_form_target: "form", turbo_frame: "cgs" } do |c| %>
<div>
<label for="add-guests">Select Cardholder Groups</label>
<div class="relative">
<%= c.search_field :search, data: { action: "input->search-form#search" }, value: params[:search] %>
</div>
<% end %>
</div>
<div data-controller="checkbox-select-all">
<label>
<input type="checkbox" data-checkbox-select-all-target="checkboxAll" />
<span class="btn_primary_small">Select All / Deselect All</span>
</label>
<%= turbo_frame_tag "cgs" do %>
<div class="space-y-3">
<%= form.collection_check_boxes :cardholdergroup_ids, current_user.cardholdergroups, :id, :friendlyname do |g| %>
<div class="flex items-center mr-4">
<%= g.check_box data: { checkbox_select_all_target: 'checkbox' } %>
<%= g.label %>
</div>
<% end %>
</div>
<% end %>
</div>
<% end %>
Stimulus controller:
import { Controller } from "#hotwired/stimulus"
export default class extends Controller {
static targets = [ "form" ]
search() {
clearTimeout(this.timeout)
this.timeout = setTimeout(() => {
this.formTarget.requestSubmit()
}, 200)
}
}
cardrequests controller search method:
def search
cardholdergroups = current_user.cardholdergroups
#cardholdergroups = cardholdergroups.where("friendlyname LIKE ?", "%#{search}%") if params[:search].present?
render(partial: 'cgs', locals: { cardholdergroups: #cardholdergroups })
end
routes:
resources :cardrequests do
collection do
get 'search'
end
end

Rails multiple search parameters and defaults

I have a search form to search incidents model with 3 fields: incidenttype, dayofweek and created_at. In my incidents.index method I check to see if the search param is present. Then filter the results based on the created_at range etc. How would I set this up so that if the dayofweek and incidenttype params were empty or blank it would just not use them in the query filter? Essentially if none were selected do not use those params, only the created_at.
Index method of incidents controller:
def index
if params[:search] && params[:search][:created_at].present?
start_date, end_date = params[:search][:created_at].split(' - ')
#incidents = Incident.where(created_at: start_date..end_date).where(dayofweek: params[:search][:dayofweek]).where(incidenttype: params[:search][:incidenttype])
#dayofweek = params[:search][:dayofweek]
#incidenttypes = Incident.order("incidenttype").distinct.pluck(:incidenttype)
else
#incidents = Incident.all
#incidenttypes = Incident.order("incidenttype").distinct.pluck(:incidenttype)
end
end
Form:
<%= form_for(:search, url: incidents_path, method: :get) do |f| %>
<div class="ui-bordered px-4 pt-4 mb-4">
<div class="form-row">
<div class="col-md mb-4">
<label class="form-label">Type</label>
<%= f.select :dayofweek, Incident.dayofweeks.keys, {:include_blank=> 'Any days', :selected => #dayofweek}, class: 'custom-select' %>
</div>
<div class="col-md mb-4">
<label class="form-label">Incident Type</label>
<%= f.select :incidenttype, options_for_select(#incidenttypes, :selected => params[:search][:incidenttype]), {include_blank: true}, class: 'form-control' %>
</div>
<div class="col-md mb-4">
<label class="form-label">Created date</label>
<%= f.text_field :created_at, class: 'form-control', id: 'tickets-list-created', :autocomplete => :off, value: created_at_from_parameters %>
</div>
<div class="col-md col-xl-2 mb-4">
<label class="form-label d-none d-md-block"> </label>
<button type="submit" class="btn btn-secondary btn-block">Show</button>
</div>
</div>
</div>
<% end %>
Any thoughts on how to set this up?
Replace your index method with:
def index
#incidenttypes = Incident.order(:incidenttype).distinct.pluck(:incidenttype)
#incidents = if params[:search] && params[:search][:created_at].present?
#dayofweek = params[:search][:dayofweek]
start_date, end_date = params[:search][:created_at].split(' - ')
filters = { created_at: start_date..end_date }
[:dayofweek, :incidenttype].each do |filter|
next if params[:search][filter].blank?
filters.merge!({ filter => params[:search][filter] } )
end
Incident.where(filters)
else
Incident.all
end
end

sunspot_solr facet not working in Ruby on Rails

I have a simple application which made with Rails 5 and I'm using sunspot solr for facet searching, everything is OK but facet not working my code is below:
model.rb
searchable do
text :full_name, :interested_topics,:interested_job, :city, :email, :username, :publish_month
text :city
time :created_at
string :publish_month
string :interested_job
end
def publish_month
created_at.strftime("%B %Y")
end
def full_name
first_name + ' ' + last_name
end
controller.rb
#search = User.search do |searcher|
fields = [:full_name, :interested_topics, :interested_job, :city, :email, :username, :publish_month]
cities = [:city]
searcher.any do
fulltext params[:search], :fields => fields
fulltext params[:city], :fields => cities
end
searcher.with(:created_at).less_than(Time.zone.now)
searcher.with(:publish_month, params[:month]) if params[:month].present?
searcher.with(:interested_job, params[:position]) if params[:position].present?
searcher.paginate(:page => params[:page], :per_page => 15)
end
#users = #search.results
index.html.erb
<div id="facets">
<%= render partial: "filter" %>
</div>
index.js.erb
$('#facets').html('<%= escape_javascript(render("filter")) %>');
_filter.html.erb
<h4>Browse by Publish</h4>
<ul class="list-group">
<% for row in #search.facet(:publish_month).rows -%>
<li class="list-group-item">
<input type="checkbox" class="facet-check-box-month" name="month" value="<%= row.value %>" <%= params[:month] == row.value ? "checked" : "" %>>
<%= row.value %>
(<%= row.count %>)
</li>
<% end -%>
</ul>
<h4>Browse by Interest</h4>
<ul class="list-group">
<% for row in #search.facet(:interested_job).rows -%>
<li class="list-group-item">
<input type="checkbox" class="facet-check-box-position" name="position" value="<%= row.value %>" <%= params[:position] == row.value ? "checked" : "" %>>
<%= row.value %>
(<%= row.count %>)
</li>
<% end -%>
</ul>
Checkbox showing well for facet but when I clicking than not querying.
What I'm doing wrong?
Thanks in advance.
You have missed facet calling like on the controller you can add that two lines into User block above the last line like searcher.paginate(:page => params[:page], :per_page => 15)
searcher.facet(:publish_month)
searcher.facet(:interested_job)
Then restart your sunspot:solr server, I think it will work.
For more nicer, on the filter partial use unless #search.nil? for when not found any results than not will show the checkbox like after modified
<% unless #search.nil? %>
<h4>Browse by Publish</h4>
<ul class="list-group">
<% for row in #search.facet(:publish_month).rows -%>
<li class="list-group-item">
<input type="checkbox" class="facet-check-box-month" name="month" value="<%= row.value %>" <%= params[:month] == row.value ? "checked" : "" %>>
<%= row.value %>
(<%= row.count %>)
</li>
<% end -%>
</ul>
<h4>Browse by Interest</h4>
<ul class="list-group">
<% for row in #search.facet(:interested_job).rows -%>
<li class="list-group-item">
<input type="checkbox" class="facet-check-box-position" name="position" value="<%= row.value %>" <%= params[:position] == row.value ? "checked" : "" %>>
<%= row.value %>
(<%= row.count %>)
</li>
<% end -%>
</ul>
<% end %>
Hope it helps

passing dynamic variable to partial for rendering in a modal

I have the following Code on a partial that dynamically generates a list of associated steps to a pin. Both pins and steps have image(s). Users are able to add multiple steps to a pin and then this view dynamically generates a view of these steps. For each step there are associated image(s) which I'd like to pop-up as a modal. The challenge is I keep getting the following error:
"undefined local variable or method `step' for #<#:0x00000102f498d8>"
When I stub out rendering the partial, the modal appears basically blank but works. Any ideas How do I do this?
<div class="col-md-6">
<% (0..(Step.where("pin_id = ?", params[:id]).count)-1).each do |step| %>
<div class="col-md-12">
<div class="well">
<ul class="nav pull-right">
<% if current_user == #pin.user %>
<%= link_to edit_step_path((Step.where("pin_id = ?", params[:id]).fetch(step)), :pin_id => #pin.id) do %>
<span class="glyphicon glyphicon-edit"></span>
Edit
<% end %> |
<%= link_to Step.where("pin_id = ?", params[:id]).fetch(step), method: :delete, data: { confirm: 'Are you sure?' } do %>
<span class="glyphicon glyphicon-trash"></span>
Delete
<% end %> |
<%= link_to new_step_image_path(:step_id => Step.where("pin_id = ?", params[:id]).fetch(step), :pin_id => #pin.id) do %>
Add
<span class="glyphicon glyphicon-picture"></span>
<% end %>
<% end %>
<% if StepImage.where("step_id = ?", Step.where("pin_id = ?", params[:id]).pluck(:id).fetch(step)).count == 0 %>
<% else %>
| <a href="#StepImageModal" data-toggle="modal">
<span class="glyphicon glyphicon-picture"></span> (<%= StepImage.where("step_id = ?", Step.where("pin_id = ?", params[:id]).pluck(:id).fetch(step)).count %> ) </strong>
</a>
<% end %>
</ul>
<strong> Step <%= step+1 %>
<p>
<%= Step.where("pin_id = ?", params[:id]).pluck(:description).fetch(step) %>
</p>
</div>
</div>
<%end %>
</div>
<div class="modal fade" id="StepImageModal">
<div class="modal-header">
<a class="close" data-dismiss="modal">×</a>
<h3>Modal Header</h3>
</div>
<div class="modal-body">
<%= render :partial => 'pins/step_images',
:locals => { :step => step } %>
</div>
<div class="modal-footer">
Close
</div>
</div>
I don't get what you're trying to do here
Loop
As mentioned in the comments, you've got a loop which goes through your steps. However, outside the loop, you want to display the partial
The solution to your woes will either be to set an instance variable (not desired), or use another persistent data type. I'd do this:
#app/controllers/steps_controller.rb
def action
#step = {}
end
#app/views/steps/action.html.erb
<% (0..(Step.where("pin_id = ?", params[:id]).count)-1).each do |step| %>
<% #step[step.id.to_sym] = step.details %>
<% end %>
<%= render :partial => 'pins/step_images', :locals => { :step => #step } %>
unless
Some refactoring for you:
<% unless StepImage.where("step_id = ?", Step.where("pin_id = ?", params[:id]).pluck(:id).fetch(step)).count == 0 %>
| <%= link_to "#StepImageModal", data: { toggle: "modal"} do %>
<span class="glyphicon glyphicon-picture"></span>(<%= StepImage.where("step_id = ?", Step.where("pin_id = ?", params[:id]).pluck(:id).fetch(step)).count %> ) </strong>
<% end %>
<% end %>

Coffeescript rails select one of two models

I have two models in ruby,
#photos = Photo.all
#comments = Comment.all
#objects = #photos + #comments
I have in my html a button id"only-photo" and a button "only-comments", if i click on the first I want to select only the photos.
how can I do to only select #photos from #objects? in coffeescript
here is what i tried
<div id="list">
<% #objects.each do |l| %>
<% if l.class == "Photo"%>
<div id="photo" class="photo">
<%= render "shared/photo", :photo => l %>
</div>
...
</div>
<div id="filters">
<button id="only-photo">
</button>
...
</div>
then in Coffeescript I just do:
$("#filters").on "click", "#only-photo", ->
$("#list #comment").removeClass "active"
$("#list #photo").addClass "active"
BUT I am sure there is a more elegant way to do these things!
Can't we filter on a scope from coffeescript? or anything like this?
Thank you!
Try this:
<div id="list">
<% #objects.each do |l| %>
<div id="<%= l.class.to_s.downcase %>_<%= l.id %>" class="<%= l.class.to_s.downcase =%>">
<%= render "shared/#{l.class.to_s.downcase}", :photo => l %>
</div>
<% end %>
</div>
<div id="filters">
<button id="only-photo" class="filter" value="photo">
</button>
<button id="only-comment" class="filter" value="comment">
</button>
</button>
</div>
Coffee:
$("button.filter").on "click", ->
class_to_hide = $(this).attr('value')
$("."+class_to_hide).toggleClass('active')

Resources