Reputation: 95
Using the Ransack gem, I'm trying to sort a simple list on an index page. However, there are both uppercase and lowercase values in the sort field name
. To make them sorted useful, the sort should be case insensitive.
This is the model Vendor
:
name:string, email:string, address:string, phone:string, fax:string
This is the controller:
class VendorsController < ApplicationController
def index
@search = Vendor.search(params[:q])
@vendors = @search.result
end
And the view:
/index.html.slim
tr
th = sort_link @search, :name, "Name"
th = sort_link @search, :email, "Company Email"
th = sort_link @search, :address, "Address"
Any advice would be greatly appreciated.
Upvotes: 4
Views: 3868
Reputation: 403
RobDil's answer from 2016 is now recognized as the best way to do this for multiple columns on a model in the ransack documentation. But if you want to do this for just one column, you can do it with a custom ransacker:
class Vendor < ApplicationRecord
ransacker :name, type: :string do
Arel.sql("lower(vendors.name)")
end
end
Note that there are a couple nuances now vs. mutexkid's 2014 answer:
If you do want to create a separate name_case_insensitive ransacker, you will need to add "name_case_insensitive" to your ransackable_attributes for the Vendor object.
Credit to RobDil and mutexkid for the original answers, just thought I'd add this here as figuring out the syntax specifics took me way too long a decade after they were published.
Upvotes: 1
Reputation: 362
Ransack now has a case_insensitive
option
you can custom a predicate with case_insensitive: false
Refrences: https://github.com/activerecord-hackery/ransack/wiki/Custom-Predicates
Upvotes: 2
Reputation: 4544
You can solve this for all string columns of a model at once by using this approach:
# lib/ransack_object.rb
module RansackObject
def self.included(base)
base.columns.each do |column|
if column.type == :string
base.ransacker column.name.to_sym, type: :string do
Arel.sql("lower(#{base.table_name}.#{column.name})")
end
end
end
end
end
Then include the ransack object in your model:
class UserWithManyAttributes < ActiveRecord::Base
include RansackObject
end
Upvotes: 3
Reputation: 121
10 months, maybe too late!!
This solved my problem with posgresql
sort_link @search, 'lowercase(name)', "Name"
Upvotes: 1
Reputation: 1084
What you're looking for is a custom "Ransacker":
class Vendor < ActiveRecord::Base
ransacker :name_case_insensitive, type: :string do
arel_table[:name].lower
end
end
view:
th = sort_link(@q, :name_case_insensitive)
Upvotes: 7
Reputation: 95
Thanks to hd1 who posted the approach above. I am posting the actual code here - it's not ideal, since it seems like a wordy workaround. Still open to cleaner suggestions.
def index
@search = Vendor.search(params[:q])
@vendors = @search.result
if params[:q].present?
params[:q].each do |k, v|
if v == 'name asc'
@vendors = @search.result.sort { |p1, p2| p1.name.downcase <=> p2.name.downcase }
elsif v == 'name desc'
@vendors = @search.result.sort { |p2, p1| p1.name.downcase <=> p2.name.downcase }
end
end
end
end
Upvotes: 0