I have a Rails 5.1 application and a Ransack search form with a dropdownlist containing some database columns. One of the column is finish_date and has values in format eg "2007-12-31". In the input field I have to type exactly the full date to get a match but I want to change the behaviour that it accepts only the year as input value.
How can I pass in a custom predicate that transforms the input value from full date eg. 2007-12-31 to only year?
What I'm looking for is a Ransack equivalent for the sql query:
SELECT *
FROM imagecapturing
WHERE YEAR(finish_date) = 2007
My Ransack form:
<%= search_form_for #search do |f| %>
<%= f.grouping_fields(f.object.new_grouping) do |g| %>
<%= g.condition_fields(g.object.new_condition) do |c| %>
<%= c.predicate_select only: %i(cont not_eq eq) %>
<%= c.value_fields do |v| %>
<%= v.text_field :value %>
<% end %>
<% end %>
<% end %>
<%= f.submit "filter" %>
<% end %>
in my controller:
#search = Imagecapturing.ransack params[:q]
#imagecapturings = #search.result.page params[:page]
Use Ransacker:
You can write something like this in your model:
ransacker :custom_years do |args|
query = <<-SQL
Year(finish_date)
SQL
Arel.sql(query)
end
See also using Ransacker on Ransack Wiki
It looks like you can accomplish the results you need using scopes. You can see the test project I created here:
https://github.com/wmavis/so_rails_ransack
The documentation has an example of how to use scopes here:
https://github.com/activerecord-hackery/ransack/#using-scopesclass-methods
I added the following to my Imagecapturing model:
def self.finish_year(year)
where("strftime('%Y', finish_date) = ?", year)
end
def self.ransackable_scopes(auth_object = nil)
%i(finish_year)
end
(I had to use strftime because my test project was using sqlite, but you can change that to YEAR(finish_date) like you wanted)
In the view, I just use the search field named finish_year:
<%= f.label :finish_year %>
<%= f.search_field :finish_year %>
Let me know if you have any issues getting it working.
Related
I'm using Ransack for search, which is working fine. But I would like the user to be able to search for multiple keywords in the same search input field.
For example if I have blog "I live in Ohio", I would like the user to be able to search "I Ohio", and it would find the blog. I tried the following which doesn't work:
<%= search_form_for #search do |f| %>
<%= f.search_field :title_or_description_cont_any %>
<% f.submit %>
<% end %>
And here is my controller:
def index
#search = Blog.ransack(params[:q])
#blogs = #search.result
end
I would have thought cont_any would work, but for some reason it doesn't?
UPDATE: I'm using also active_admin, I don't know if that matters?
I too had this question (also Rails 5). What finally worked for me was using *_cont_all and passing it an array of search terms.
View: (generic Rails form_with so I can just send params, because our use cases are too long/wordy/complex for the ransack search form to be easily readable!)
= form_with url: book_search_path, method: :get do |f|
.input-label Book Title
= f.text_field :title_terms, value: #title_terms
. . .
Then in my controller, I used *_cont_all, but passed it an array of terms split on spaces.
(Note that I'm not using params[:q], I just create an empty hash and call it 'q', then pass q to ransack -- Book.ransack(q))
# make an array of terms, split on spaces
q[:book_titles_cont_all] = params[:title_terms].split(' ')
Finally, I pass q to Book.ransack(q) and send the results to my view.
It seems that you have to pass to the predicate an array of words, _cont_any or cont_all or other forms of them.
I had fixed it using split string like the code shown below.
if params[:q].present? and params[:q][:name_cont_all].present?
words = params[:q][:name_cont_all].split(" ")
params[:q][:name_cont_all] = words
end
this worked for me
I think what Shuaib did was the right way to go, a more complete answer would be:
def index
q = params[:q]
if q&.key?(:title_or_description_cont_any) && q[:title_or_description_cont_any].is_a?(String)
q[:title_or_description_cont_any] = q[:title_or_description_cont_any].split
end
#search = Blog.ransack(params[:q])
#blogs = #search.result
end
This checks the existence of the field in question and split it if it is a String.
I think it should be like the following
def index
#search = Blog.ransack(params[:q])
#blogs = #search.result(distinct: true)
end
Your form should look like this,
<%= search_form_for #q do |f| %>
<%= f.search_field :title_or_description_cont %>
<% end %>
Title and description need to be actual fields in your database. For example if you created a Post model with fields in it containing header, subtitle and shortDescription, you will need to use these fields instead of title and description.
<%= f.input :title_or_description_cont_any %>
<%= f.input :title_or_description_cont %>
something like this:
<%= f.input :header_or_shortDescription_cont_any %>
Trying to implement simple search on rails app.
productions_controller
def filter
if params[:filter]
#productions = Production.where('productions.status like ?', "%#{Production.statuses[params[:filter]]}%")
else
#productions = Production.all
end
end
There is a list of records on the index page. I am implementing search/filter on those list based on status which are in enum datatype.
index.html.erb
<%= form_tag [:filter, :productions], :method => 'get' do %>
<p>
<%= text_field_tag :filter, params[:filter] %>
<%= submit_tag "Filter", :status => nil %>
</p>
<% end %>
When I entered a keyword pre in the text field, this is what happens in the logs
Processing by ProductionsController#filter as HTML
Parameters: {"utf8"=>"✓", "filter"=>"pre", "commit"=>"Filter"}
Rendering productions/filter.html.erb within layouts/application
Production Load (0.4ms) SELECT "productions".* FROM "productions" WHERE (productions.status like '%%')
Rendered productions/filter.html.erb
It looks like it's taking the entered keyword but not while querying. May be I'm wrong. Could somebody help me here ?
Adding production.rb as requested
class Production < ApplicationRecord
enum status:{
Preproduction:1,
Postproduction: 2,
Completed:3
}
end
As the status are stored as integers you can use the below method to filter the productions based on the status value.
def filter
filtered_statuses = params[:filter].present? ? Production.statuses.select{|k, v| k.to_s.include?(params[:filter])} : nil
if filtered_statuses
#productions = Production.where(status: filtered_statuses.values)
elsif params[:filter].present?
#productions = [] # To return empty if no search filter matches production statuses
else
#productions = Production.all
end
end
Actually, you can't use enums with LIKE statements like you are doing. It would only work if you queried it like this.
#productions = Production.where(status: "Preproduction")
Here is another post with a similar issue:
rails 5 enum where "like"
I would recommend you change
<%= form_tag [:filter, :productions], :method => 'get' do %>
<p>
<%= text_field_tag :filter, params[:filter] %>
<%= submit_tag "Filter", :status => nil %>
</p>
<% end %>
to this
<%= form_tag [:filter, :productions], :method => 'get' do %>
<p>
<%= select_tag :filter, options_for_select(Production.statuses) %>
<%= submit_tag "Filter", :status => nil %>
</p>
<% end %>
Just pass only params[:filter]
like these
def filter
if params[:filter]
#productions = Production.where('productions.status like ?', "%#{params[:filter]}%")
else
#productions = Production.all
end
end
You are passing pre as filter and you do not have any status with pre and that is the same reason you are unable to find any data.
However you still need to update code a bit
#productions = Production.where('productions.status like ?', "%#{Production.statuses[params[:filter].capitalize]}%")
Problem is not with code as if the filter word doesn't matches any key it will give you nil as you are already doing string interpolation so it will become blank and finally you are trying to access "%%" which looks like your enum is not working. If you are providing filter for enum provide select filed instead of input and directly filter data based on status as mentioned in answers.
Hope this might help
hi so I'm trying to do 2 things, one of them is to basically redirect to a model's ID number so input is "1" and redirects to
localhost:3000/model/1
and the second part is actually doing a search. each model has a text field string for license_no and I want to be able to search and return results
currently, I am not sure how I would combine these into 1 search form if thats possible or if it would require 2 separate search forms
i have a search form with only the license_no field but it always returns no results found...
apologize that the model name isn't in singular, the guide I was using to learn RoR had it that way and everything worked, but I have so many references to renters in my project that it would be a while to find all of them
index.html.erb
<%= form_tag search_renters_path, method: get do |f| %>
<%= text_field_tag :license, nil, placeholder: "License Number" %>
<%= submit_tag 'Search', class: "btn-large" %>
<% end %>
models/renters.rb
class Renters < ActiveRecord::Base
validates_presence_of :license_no
def self.search(params)
renters = Renters.where("license_no LIKE?", "%#{params[:license]}%")
end
end
controller.rb
def search
#renter = Renters.search([params])
end
search.html.erb - snippet
<% if #renter.blank? %>
no results
<% else %>
#show results
<% end %>
editted code
models/renters.rb
def self.search(params)
license_query = "%#{params[:license]}%"
id_query = "%#{params[:id]}%"
renters = Renters.where("license_no LIKE ?", license_query) if params[:license].present?
renters = Renters.where("id LIKE ?", id_query) if params[:id].present?
end
controller
def search
#renter = Renters.search(params)
end
search form
<%= form_tag search_renters_path, method: :get do |f| %>
<%= text_field_tag :license, nil, placeholder: "Driver's License" %>
<%= text_field_tag :id, nil, placeholder: "ID number" %>
<% end %>
I'm trying to use the if present? statements to allow a user to decide whether to input ID No or License No. you don't need to input both just one. currently, if I search for a license no, it returns no results. but when I search for an ID, it returns the relevant result
you can do something like this if you are getting value on params[:licence] from your form submit on your controller action search
controller.rb
def search
#renter = Renters.search(params[:licence])
end
app/models/renters.rb
class Renters < ActiveRecord::Base
def self.search(query)
like_query = "%#{query}%"
renters = Renters.where("id LIKE ? OR license_no LIKE ?", like_query, like_query)
end
end
I've created a rails app where a user chooses their preference between different vegetables. The database is formatted as follows:
Prefid (key)
Userid
veg1
veg2
preference
The form follows a format --
<%= form_for :pick do |f| %>
<%= f.collection_select( :id, Players.all, :id, :name) %>
<%= f.radio_button(pref.id, veg.veg1) %>
<%= f.radio_button(pref.id, veg.veg2) %>
<%= f.submit %>
<% end %>
Right now, when the form is submitted, I have this as my create method --
def create
#prefs = Prefs.new()
#prefs[:player_id] = post_params[:id]
post_params.delete(:id)
post_params.each do |key, value|
#prefs.games_id = key
#prefs.pick = value
#prefs.save
end
redirect_to #picks
end
This method doesn't work. It only submits the first pick into the database. I've read a few different ways to do this, but none of them really follow the same format as my application.
Im following Ryan's Railscast 278 for searching but I am encountering an issue. In the example he uses, the controller and model are the exactly the same. Both are article. The code I have is a little different. What am I doing wrong here?
Different Model I am using:
models/compact_disc.rb
class CompactDisc < ActiveRecord::Base
searchable do
text :title
end
end
controllers/products_controller.rb
def show
#search = CompactDisc.search do
fulltext params[:search]
end
#compact_disc = #search.results
end
views/products/show.html.erb
<%= form_tag new_user_list_path, :method => :get do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
<% for compact_disc in #compact_disc %>
<%= image_tag "list_images/#{compact_disc.photo_url}" %>
<%= compact_disc.title %><br/>
<% end %>
When I click search there are no results but the syntax is similiar to what he had in the Railscast.
Thanks for your help!
Your syntax is ok, but I would recommend making the search method a class method of CompactDisc:
class CompactDisc < ActiveRecord::Base
searchable do
text :title
end
def self.full_text_search(query)
solr_search do
fulltext query
end
end
end
Then in your controller you can call it like
CompactDisc.full_text_search(params[:query])
Your data might not be showing up because you haven't indexed it yet. Have you made sure to do the following in the rails console?
CompactDisk.index
Sunspot.commit
Also, depending on how your schema.xml is set up, you may need to type in the exact title in order for it to match. It's hard to debug exactly what's going on without having the data. Can you confirm that if you use the solr analyzer you can query CompacDiscs on title fine?