Active Record is amazing! However, you can do so much with its current public API. A common example is querying for {greater,lesser}-than attributes. People often use Areal to avoid plain/hardcoded SQL expressions.
There’s this PR that implements those comparison methods as symbols but it feels a bit hacky IMHO. This other amazing PR is similar, but it’s open for a long time and it doesn’t seem to have any plans to get merged soon.
Possible solution
Could we implement something minimal (and yet so powerful) like:
class ApplicationRecord < ActiveRecord::Base
def self.[](column)
arel_table[column]
end
end
# This is optional
module Arel
module Predications
alias_method :>, :gt
alias_method :<, :lt
alias_method :>=, :gteq
alias_method :<=, :lteq
alias_method :"!=", :not_eq
alias_method :==, :eq
end
end
# usage
Post.where(Post[:created_at] <= 30.days.ago)
# We can even use it in more places than `where`
some_query.select([Post[:author].as("author_name")])
I loved this PR! Have you changed your opinion about it? Do you think this could make into Rails 7? It’s a major release, and I think it would be a nice addition to Active Record.
I don’t understand why people find Arel necessary “better” than SQL fragments. I sort of understand it when you are writing libraries as it prevents you from having to fully abstract the fragment and specify things out like:
where "#{connection.quote_table_name self.class.table_name}.#{connection.quote_column_name 'created_at'}" <= ?", 30.days.ago
But in applications you don’t generally need as much protection. You know if your table name needs quotes or not (usually not) and you know if the table needs to be specified due to joins or not. So much of that boilerplate is removed and it becomes:
where 'created_at <= ?', 30.days.ago
or at worse
where 'my_table.created_at <= ?', 30.days.ago
To me there is something nice about SQL fragments as they are less magic. Sometimes with a DSL it is unclear exactly how to use it to get the what you want. But with SQL fragments it’s just regular SQL, strings and placeholders.
Arel is there to be used for things like libraries that have the special need to be fully abstract for any database types, table name, column name, etc. But for regular applications sql fragments seem quite sufficient.
For those that really want a DSL there are libraries like Ransack and Squeel that can provide a clever DSL.