jbox-web / ajax-datatables-rails

A wrapper around DataTable's ajax methods that allow synchronization with server-side pagination in a Rails app
MIT License
590 stars 227 forks source link

how to use view_columns with one class associated twice #295

Open MiroBabic opened 6 years ago

MiroBabic commented 6 years ago

Hello, this is my model

class Associate < ActiveRecord::Base
    has_many :missions
    has_many :coordinator_missions, :class_name => "Mission", :foreign_key  => "coordinator_id"
end
class Mission < ActiveRecord::Base
  belongs_to :associate
  belongs_to :coordinator, :class_name => "Associate"
end

Showing data in table with Mission.joins(:associate).joins(:coordinator) works fine, but I cannot search because of Coordinator this is my datatable code

class MissionDatatable < AjaxDatatablesRails::Base

  def view_columns
    @view_columns ||= {
       id: { source: "Mission.id", cond: :eq },
       fy: {source: "Mission.fy"},
       associate_email: {source: "Associate.email"},
       associate_id: {source: "Mission.associate_id"},
       coordinator_email: { source: "Coordinator.email" },
       coordinator_id: { source: "Mission.coordinator_id" },
       name: { source: "Mission.name" },
       fye_output: { source: "Mission.fye_output" },
       status: { source: "Mission.status" },
       created_at: { source: "Mission.created_at" },
       updated_at: { source: "Mission.updated_at" }
    }
  end

  def data
    records.map do |mission|
      {
        # example:
         id: mission.id,
         fy: mission.fy,
         associate_email: mission.associate.email,
         associate_id: mission.associate_id,
         coordinator_email: mission.coordinator.email,
         coordinator_id: mission.coordinator_id,
         name: mission.name,
         fye_output: mission.fye_output,
         status: mission.status,
         created_at: mission.created_at,
         updated_at: mission.updated_at
        }
    end
  end

  private

def get_raw_records
  Mission.joins(:associate).joins(:coordinator)
end

end

could you pls help me how to do correct setup for one model associated twice? The error in log is "wrong constant name Coordinator"

AleksandrLeontev commented 6 years ago

Same problem. These columns should be represented in the ModelName.column_name, or aliased_join_table.column_name notation. I tried to use aliased_join_table.column_name but looks like it doesn't work, or which KEY I should use?

alaarab commented 5 years ago

I have the same issue. It would be great if this were possible.

rollyar commented 4 years ago

I have the same problem. Any solution? thank you!

Datyv commented 2 years ago

My Solution was to create a fake model, which inherits from the original_table you want to search and give it the table name of the SQL-Alias.

In my case the alias was customers_invoices (which i got from the query in the logs)

class CustomersInvoice < Customer
  self.table_name = 'customers_invoices'
end

And in the datatable I named it

customer_invoice_name: { source: 'CustomersInvoice.name' },

And it worked

rshelfor commented 2 months ago

Okay, I've solved this so the searches work across both associations on the same table.

Creating a shadow model worked to resolve the error, but search functionality was not addressed by it. Searching only worked across the first association that was joined..

# Datatable for Customer
class CustomerDatatable < AjaxDatatablesRails::ActiveRecord

def view_columns
    @view_columns ||= {
      id: { source: 'Customer.id', cond: :eq, searchable: false, orderable: false },
      # other columns
      ship_company: { source: 'Address.company', cond: address_search, searchable: true, orderable: true },
      ship_city: { source: 'Address.city', cond: address_search, searchable: true, orderable: true },
      bill_company: { source: 'Address.company', cond: address_search, searchable: true, orderable: true },
      bill_city: { source: 'Address.city', cond: address_search, searchable: true, orderable: true },
    }
  end

  def address_search
    lambda do |column, search_value|
      # figure out the table column and the join alias from the column name
      column_parts = column.column_name.to_s.split('_')
      address_type = column_parts.shift
      column_name = column_parts.join('_')
      table_alias = address_type == 'ship' ? 'addresses' : 'bill_addresses_customers'
      # Build the sql with the correct format name rather than relying on the default `source` behaviour
      ::Arel::Nodes::SqlLiteral.new("#{table_alias}.#{column_name} ILIKE '%#{search_value}%'")
    end
  end

I figured out the alias for the bill address was bill_address_customers just by reviewing the sql in the logs :

SELECT
  "customers"."id" AS t0_r0,
   -- ...
FROM
  "customers"
  INNER JOIN "addresses" ON "addresses"."id" = "customers"."ship_address_id"
  INNER JOIN "addresses" "bill_addresses_customers" ON "bill_addresses_customers"."id" = "customers"."bill_address_id"
WHERE
 -- ...