Skip to content

Commit

Permalink
Add has_one scope support to virtual_delegate
Browse files Browse the repository at this point in the history
This enhances virtual_delegates so that scopes added as part of a
`has_one` relation are respected.

Because of the changes, an implicit `limit = 1` was necessary to support
the `has_one`, and the easiest way to accomplish that while still
keeping `select_from_alias` in a similar form was to allow passing a
block so the arel (prior to being converted to a string) could be
updated.

Also of note, `select_from_alias` also had a few changes to it beyond
that:

  - The "query" is now built up from the scope on the model, not a raw
    arel_table from the to_ref model.
  - Instead of a `project`, we call a `.select` on the "query" (scope
    from the relation), which already has a similar arg structure, but
    allows us to remove the select_values properly before converting it
    to arel (happens right after the `.select`).  We work with raw
    `Arel` after that.
  - The `table_alias` functionality is now done through the `from`
    clause, `from(to_table)` allows us to still keep the same alias
    functionality we had.  Under the covers, this does the same thing,
    it is just previously the starting point was an `Arel::Table`, and
    now it is a `Arel::SelectManager`.  The `Arel::Table` version ends
    up returning a `SelectManager` anyway, so what we are doing is
    functionally equivalent.
  • Loading branch information
NickLaMuro committed Jun 8, 2018
1 parent ad1145a commit f33a768
Showing 1 changed file with 18 additions and 4 deletions.
22 changes: 18 additions & 4 deletions lib/extensions/ar_virtual.rb
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,9 @@ def virtual_delegate_arel(col, to_ref)
if to_ref.macro == :has_one
lambda do |t|
src_model_id = arel_attribute(to_ref.association_primary_key, t)
VirtualDelegates.select_from_alias(to_ref, col, to_ref.foreign_key, src_model_id)
VirtualDelegates.select_from_alias(to_ref, col, to_ref.foreign_key, src_model_id) do |arel|
arel.limit = 1
end
end
elsif to_ref.macro == :belongs_to
lambda do |t|
Expand Down Expand Up @@ -287,10 +289,22 @@ def virtual_delegate_arel(col, to_ref)
#

def self.select_from_alias(to_ref, col, to_model_col_name, src_model_id)
to_table = select_from_alias_table(to_ref.klass, src_model_id.relation)
query = if to_ref.scope
to_ref.klass.instance_exec(nil, &to_ref.scope)
else
to_ref.klass.all
end

to_table = select_from_alias_table(to_ref.klass, src_model_id.relation)
to_model_id = to_ref.klass.arel_attribute(to_model_col_name, to_table)
to_column = to_ref.klass.arel_attribute(col, to_table)
Arel.sql("(#{to_table.project(to_column).where(to_model_id.eq(src_model_id)).to_sql})")
to_column = to_ref.klass.arel_attribute(col, to_table)
arel = query.select(to_column).arel
.from(to_table)
.where(to_model_id.eq(src_model_id))

yield arel if block_given?

Arel.sql("(#{arel.to_sql})")
end

# determine table reference to use for a sub query
Expand Down

0 comments on commit f33a768

Please sign in to comment.