ManageIQ / ManageIQ/activerecord-virtual_attributes
Support condensed virtual_attribute definitions
Open
@kbrock is already working on this.
Since Sep 17, 2025.
enhancement
stale
- Dominant language
- Ruby
- Stars
- 10
- Forks
- 11
- PR merge metrics
- No merged PRs in 30d
Description
I'm trying to guage what people think of this new syntax.
- It has the ruby and sql definitions together rather than scattered.
- It has 2 blocks (arel and ruby) back to back.
- It auto generates the "use attribute from
select()" line. i.e.:return self["archived"] if has_attribute?("archived") - The "use attribute if from
select()" is missing all over our code, so that is a win. - The ruby method will be defined using metadata rather than ruby. (something to be said for plain old ruby)
- This can be added incrementally.
NOTE: If you look in the code, the t.grouping() adds parens around the SQL. This is no longer necessary and going through this will allow us to remove it.
Before
def archived?
return self["archived"] if has_attribute?("archived")
ems_id.nil? && storage_id.nil?
end
alias_method :archived, :archived?
virtual_attribute :archived, :boolean, :arel => (lambda do |t|
t.grouping(t[:ems_id].eq(nil).and(t[:storage_id].eq(nil)))
end)
After
virtual_attribute :archived, :boolean, :arel => -> (t) {
t[:ems_id].eq(nil).and(t[:storage_id].eq(nil))
} do
ems_id.nil? && storage_id.nil?
end
alias_method :archived, :archived?
Before 2
class VmOrTemplate
def normalized_state
return self["normalized_state"] if has_attribute?("normalized_state")
%w[archived orphaned template retired disconnected].each do |s|
return s if send(:"#{s}?")
end
power_state&.downcase || "unknown"
end
virtual_attribute :normalized_state, :string, :arel => (lambda do |t|
Arel::Nodes::Case.new
.when(arel_table[:archived]).then(Arel.sql("'archived'"))
.when(arel_table[:orphaned]).then(Arel.sql("'orphaned'"))
.when(t[:template].eq(t.create_true)).then(Arel.sql("'template'"))
.when(t[:retired].eq(t.create_true)).then(Arel.sql("'retired'"))
.when(arel_table[:disconnected]).then(Arel.sql("'disconnected'"))
.else(t.lower(t.coalesce([t[:power_state], Arel.sql("'unknown'")])))
end)
end
After 2
class VmOrTemplate
virtual_attribute :normalized_state, :string, :arel => -> (t) {
Arel::Nodes::Case.new
.when(arel_table[:archived]).then(Arel.sql("'archived'"))
.when(arel_table[:orphaned]).then(Arel.sql("'orphaned'"))
.when(t[:template].eq(t.create_true)).then(Arel.sql("'template'"))
.when(t[:retired].eq(t.create_true)).then(Arel.sql("'retired'"))
.when(arel_table[:disconnected]).then(Arel.sql("'disconnected'"))
.else(t.lower(t.coalesce([t[:power_state], Arel.sql("'unknown'")])))
} do
%w[archived orphaned template retired disconnected].each do |s|
return s if send(:"#{s}?")
end
power_state&.downcase || "unknown"
end
end
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.