diff --git a/lib/ajax-datatables-rails/datatable/column.rb b/lib/ajax-datatables-rails/datatable/column.rb index 2698eec..dfbe5a1 100644 --- a/lib/ajax-datatables-rails/datatable/column.rb +++ b/lib/ajax-datatables-rails/datatable/column.rb @@ -32,7 +32,15 @@ def source end def table - model.respond_to?(:arel_table) ? model.arel_table : model + if model.respond_to?(:arel_table) + table_alias.present? ? model.arel_table.alias(table_alias) : model.arel_table + else + model + end + end + + def table_alias + @table_alias ||= @view_column[:table_alias] end def model diff --git a/spec/ajax-datatables-rails/base_spec.rb b/spec/ajax-datatables-rails/base_spec.rb index 02ce8ac..a678f86 100644 --- a/spec/ajax-datatables-rails/base_spec.rb +++ b/spec/ajax-datatables-rails/base_spec.rb @@ -220,4 +220,51 @@ def paginate_records(records) end end end + + describe 'Named join' do + describe '#data' do + let(:datatable) { NamedJoinDatatable.new(group_sample_params) } + let(:admin) { create(:user, username: 'johndoe', email: 'johndoe@example.com') } + + before do + user_1 = create(:user, username: 'johndoe', email: 'johndoe@example.com') + + group_1 = create(:group, admin: nil, name: 'Super Group') + user_2 = create(:user, username: 'sandbo', email: 'sandra.bo@example.com', group: group_1) + + user_3 = create(:user, username: 'msmith', email: 'mary.smith@example.com') + create(:group, admin: user_2, name: 'First group', users: [user_1, user_3]) + + user_4 = create(:user, username: 'anna', email: 'anna.belle@example.com') + create(:group, admin: user_4, name: 'Awesome group', users: [user_4]) + + create(:user, username: 'hans', email: 'han.solo@example.com') + end + + it 'returns list' do + group_names = datatable.data.map { |i| i[:group_name] } + admin_names = datatable.data.map { |i| i[:group_admin] } + expect(group_names).to eq ["Awesome group", nil, "First group", "First group", "Super Group"] + expect(admin_names).to eq ["anna", nil, "sandbo", "sandbo", nil] + end + + it 'global search' do + datatable.params[:search][:value] = 'sand' + user_names = datatable.data.map { |i| i[:username] } + expect(user_names).to eq ["johndoe", "msmith", "sandbo"] + end + + it 'sorts list asc' do + datatable.params[:order]['0'] = { column: '2', dir: 'asc' } + admin_names = datatable.data.map { |i| i[:group_admin] } + expect(admin_names).to eq ["anna", "sandbo", "sandbo", nil, nil] + end + + it 'sort list desc' do + datatable.params[:order]['0'] = { column: '2', dir: 'desc' } + admin_names = datatable.data.map { |i| i[:group_admin] } + expect(admin_names).to eq [nil, nil, "sandbo", "sandbo", "anna"] + end + end + end end diff --git a/spec/ajax-datatables-rails/datatable/column_spec.rb b/spec/ajax-datatables-rails/datatable/column_spec.rb index 6239d89..f484aaa 100644 --- a/spec/ajax-datatables-rails/datatable/column_spec.rb +++ b/spec/ajax-datatables-rails/datatable/column_spec.rb @@ -44,6 +44,12 @@ end end + describe '#table_alias' do + it 'returns nil as the table_alias' do + expect(column.table_alias).to eq nil + end + end + describe '#table' do context 'with ActiveRecord ORM' do it 'returns the corresponding AR table' do @@ -219,4 +225,22 @@ expect { datatable.to_json }.to raise_error(AjaxDatatablesRails::Error::InvalidSearchColumn).with_message("Check that column 'foo' exists in view_columns") end end + + describe 'table name overwrites for named joins' do + let(:datatable) { NamedJoinDatatable.new(group_sample_params) } + + let(:column) { datatable.datatable.columns.last } + + describe '#source' do + it 'returns the data source from view_column' do + expect(column.source).to eq 'User.username' + end + end + + describe '#table_alias' do + it 'returns the data source from table_alias' do + expect(column.table_alias).to eq 'admin' + end + end + end end diff --git a/spec/factories/group.rb b/spec/factories/group.rb new file mode 100644 index 0000000..96ec21d --- /dev/null +++ b/spec/factories/group.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :group do |f| + f.name { Faker::Team.name } + f.admin { build(:user) } + end +end diff --git a/spec/support/datatables/named_join_datatable.rb b/spec/support/datatables/named_join_datatable.rb new file mode 100644 index 0000000..2db82b9 --- /dev/null +++ b/spec/support/datatables/named_join_datatable.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class NamedJoinDatatable < AjaxDatatablesRails::ActiveRecord + def view_columns + @view_columns ||= { + username: { source: 'User.username' }, + group_name: { source: 'Group.name' }, + group_admin: { source: 'User.username', table_alias: 'admin' } + } + end + + def data + records.map do |record| + { + username: record.username, + group_name: record.group&.name, + group_admin: record.group&.admin&.username, + } + end + end + + def get_raw_records + User.left_outer_joins(group: :admin) + .where(admin: { id: [nil, 1..] }) # Hack to force alias in Rails + end +end diff --git a/spec/support/helpers/params.rb b/spec/support/helpers/params.rb index b127b77..a973ab3 100644 --- a/spec/support/helpers/params.rb +++ b/spec/support/helpers/params.rb @@ -60,6 +60,41 @@ def sample_params ) end +def group_sample_params + ActionController::Parameters.new( + { + 'draw' => '1', + 'columns' => { + '0' => { + 'data' => 'username', 'name' => '', 'searchable' => 'true', 'orderable' => 'true', + 'search' => { + 'value' => '', 'regex' => 'false' + } + }, + '1' => { + 'data' => 'group_name', 'name' => '', 'searchable' => 'true', 'orderable' => 'true', + 'search' => { + 'value' => '', 'regex' => 'false' + } + }, + '2' => { + 'data' => 'group_admin', 'name' => '', 'searchable' => 'true', 'orderable' => 'false', + 'search' => { + 'value' => '', 'regex' => 'false' + } + } + }, + 'order' => { + '0' => { 'column' => '0', 'dir' => 'asc' }, + }, + 'start' => '0', 'length' => '10', 'search' => { + 'value' => '', 'regex' => 'false' + }, + '_' => '1423364387185' + } + ) +end + def sample_params_json hash_params = sample_params.to_unsafe_h hash_params['columns'] = hash_params['columns'].values diff --git a/spec/support/models/group.rb b/spec/support/models/group.rb new file mode 100644 index 0000000..021bf1f --- /dev/null +++ b/spec/support/models/group.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +class Group < ActiveRecord::Base + belongs_to :admin, class_name: 'User' + has_many :users +end diff --git a/spec/support/models/user.rb b/spec/support/models/user.rb index 7ad18b2..dbbf7f9 100644 --- a/spec/support/models/user.rb +++ b/spec/support/models/user.rb @@ -1,6 +1,9 @@ # frozen_string_literal: true class User < ActiveRecord::Base + belongs_to :group, optional: true + has_many :admin_groups, foreign_key: :admin_id + def full_name "#{first_name} #{last_name}" end diff --git a/spec/support/schema.rb b/spec/support/schema.rb index 69a10cb..8f94de5 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -9,6 +9,14 @@ t.string :first_name t.string :last_name t.integer :post_id + t.integer :group_id + + t.timestamps null: false + end + + create_table :groups, force: true do |t| + t.string :name + t.integer :admin_id t.timestamps null: false end