using order_by expression and distinct true in rails 6 with postgresql
My initial suggestion is to create a Status
model and table with status
and priority
columns and then create a formal relationship with your existing model as this will allow simple addition and reordering in the future without any code change.
I lieu of this, the error is fairly clear:
for SELECT DISTINCT, ORDER BY expressions must appear in select list
This means that when using SELECT DISTINCT you can only order by columns that appear in the SELECT clause
To solve this I would recommend the following:
- remove "ASC" from the
self.order_by_status
method (so that we can reuse the CASE statement - then update the scope as follows
scope :by_status_priority, -> {
select(arel_table[Arel.star],Arel.sql(order_by_status).as('status_order') )
.order(Arel.sql(order_by_status).asc)
}
TL;DR Explanation of ActiveRecord and Arel
You will see Arel
a few times in the above. Arel
is the underlying query assembler for rails and offers a significant amount of flexibility allowing for much more composable queries.
Every ActiveRecord
object exposes its Arel::Table
via a method called arel_table
. This part arel_table[Arel.star]
will be assembled as "table_name"."*" (select everything)
This part Arel.sql(order_by_status)
will return an Arel::Nodes::SqlLiteral
which allows us to chain aliasing (as in as('status_order')
) as well as ordering (as in .asc
).
We could even build your entire CASE statement using Arel
via
def self.order_by_status
STATUS_ORDER.each_with_index.inject(Arel::Nodes::Case.new) do |cassette, (s, i)|
cassette.when(arel_table[:status].eq(s)).then(i)
end
end
This will allow you to get rid of the Arel.sql
wrappers in by_status_priority
(which are for raw sql strings) so the scope can now become
scope :by_status_priority, -> {
select(arel_table[Arel.star],order_by_status.as('status_order'))
.order(order_by_status.asc)
}
ActiveRecord
provides a lot of convenience methods to expose the Arel
query interface e.g. select
, where
, order
, joins
, etc. but it would be impossible to expose everything in such a simple way as to provide an easy top level DSL; however almost everyone of these "top-level" methods will accept Arel
arguments without issue allowing you to build any query you could possibly want. If it is valid SQL then Arel
can construct it.
Ransack sort on count of HABTM or HMT associated records
Given you have your entities queried with the above scope, for example your index query always has:
# controller
@search = Theme.ransack(params[:q])
@themes = @search.result(distinct: true).with_quotes_count
Have a try of:
# model
ransacker :quotes_count_sort do
Arel.sql('quotes_count')
end
And use the name of the sort in sort_link
?
Make an OR with ransack
Try the following:
Position.search( {:description_or_code_cont => field}).result(:distinct => true).to_sql
Related Topics
Split Seeds.Rb into Multiple Sections
How to Use Regex for Utf8 in Ruby
Ssl_Connect Syscall Returned=5 Errno=0 State=Sslv2/V3 Read Server Hello A
Ruby: Yield Block from a Block
Create a Human-Readable List with "And" Inserted Before the Last Element from a Ruby List
Openssl Trouble with Ruby 1.9.3
How to Integrate 'Premailer' with Rails
Ruby on Rails Map.Root Doesn't Seem to Be Working
Catching Timeout Errors with Ruby Mechanize
Spacing Around Parentheses in Ruby
Rails: Violates Foreign Key Constraint
Rails: Undefined Method 'Truncate' in Model
Unicode Characters in a Ruby Script
How to Sign_In for Devise to Test Controller with Minitest
Nil.To_JSON Cannot Be Parsed Back to Nil
Which Ruby Classes Support .Clone
How Get Best Performance Rails Requests Parallel Sidekiq Worker