Is it possible to define virtual attributes in activerecord corresponding to SQL expressions?

左心房为你撑大大i 提交于 2020-01-14 10:33:10

问题


I'm after something like virtual attribute, but that would work on the database level: say I have a field age and I would like to add a "virtual field" age_quintile which equals age/5, but in such a way that it is possible to say:

Person.select(:age_quintile,"agv(height)").
  group(:age_quintile).
  order(:age_quintile)

corresponding to:

  SELECT (age/5) as age_quintile, avg(height) 
    FROM persons 
GROUP BY (age/5) 
ORDER BY (age/5);

or

Person.maximum(:age_quintile)

corresponding to

SELECT max(age/5) 
  FROM persons;

So, I imagine I would declare such attributes in the model, like:

class Person < ActiveRecord::Base
  ...
  magic_attribute :age_quintile, :integer, 'age/5'

end

where the last bit is an SQL expression and type is necessary for casting from strings.

Is there a way to do that with vanilla ActiveRecord or with some gem?

Update

The reason for wishing to declare such attributes in the model, and not - as suggested - use an aliased expression verbatim in select is that we would like the attributes participate in a generic query API and appear to the user of the API as any other attribute. So the following should be possible:

class PeopleController < ApplicationController
  def search
    group_columns = params[:group].split(" ") # age_quintile could be one of
    measurements = params[:measurements].split(" ") # height could be one of
    aggregates = %w[min avg max]
    select_columns = measurement.map{|m| 
      aggregates.map{|fn| "#{fn}(#{m})"} 
    }.flatten
    render :json => Person.
                      select( group_columns + select_columns ).
                      group(group_columns).
                      search(group_columns)
  end
end

and a query string ?group=age_quintile&measurements=height would result in:

  SELECT (age/5) as age_quintile, min(height), avg(height), max(height)
    FROM persons 
GROUP BY (age/5) 
ORDER BY (age/5);

回答1:


It's possible. What's more, it is done automatically by ActiveRecord:

@people = Person.
  select('(age/5) as age_quintile, height').
  group(:age_quintile).
  order(:age_quintile)
person = @people.first
person.age_quintile
# => age_quintile value (person.age / 5)


来源:https://stackoverflow.com/questions/19321340/is-it-possible-to-define-virtual-attributes-in-activerecord-corresponding-to-sql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!