Skip to content

Commit

Permalink
Merge pull request #17473 from NickLaMuro/virtual_delegate_has_one_sc…
Browse files Browse the repository at this point in the history
…ope_support

Add has_one scope support to virtual_delegate
  • Loading branch information
kbrock authored Jun 11, 2018
2 parents b2ba3ff + fec164a commit 0ce8fb4
Show file tree
Hide file tree
Showing 2 changed files with 35 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
17 changes: 17 additions & 0 deletions spec/lib/extensions/ar_virtual_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -622,11 +622,19 @@ def self.connection

include VirtualFields
end

class CompSys < ComputerSystem
has_one :first_os, -> { order(:name) },
:class_name => "OperatingSystem",
:foreign_key => "computer_system_id",
:dependent => :destroy
end
end

after do
TestOtherClass.remove_connection
Object.send(:remove_const, :TestOtherClass)
Object.send(:remove_const, :CompSys)
end

it "delegates to another table" do
Expand All @@ -644,6 +652,15 @@ def self.connection
sql = TestOtherClass.all.select(:id, :ocol1, TestOtherClass.arel_attribute(:col1).as("x")).to_sql
expect(sql).to match(/"test_classes"."col1"/i)
end

it "delegates has_one relationships with limit 1" do
CompSys.virtual_delegate :first_os_name, :to => 'first_os.name'
comp_sys = CompSys.create!
OperatingSystem.create(:name => "foo", :computer_system_id => comp_sys.id)
OperatingSystem.create(:name => "bar", :computer_system_id => comp_sys.id)
query = CompSys.all.select(:id, :first_os_name)
expect(query.map(&:first_os_name)).to match_array(["bar"])
end
end
end

Expand Down

0 comments on commit 0ce8fb4

Please sign in to comment.