Techioz Blog

Rails AjaxDatatablesRails::ActiveRecord 同じモデルに LEFT JOIN すると検索エラーが発生する

概要

私のトランザクション モデルには、在庫室モデル オブジェクトを参照する 2 つのフィールドがありました。これにより、検索時にエラーが発生します。これらのフィールドのいずれかによる検索または並べ替えでは、最初の left_join からのデータのみが使用されます。

class Transaction < ApplicationRecord
  belongs_to :stored_product
  belongs_to :user
  belongs_to :from_stockroom, class_name: 'Stockroom', foreign_key: 'from_stockroom_id', optional: true
  belongs_to :to_stockroom, class_name: 'Stockroom', foreign_key: 'to_stockroom_id', optional: true
  attr_accessor :user_selection

解決策

私のトランザクション モデルには、在庫室モデル オブジェクトを参照する 2 つのフィールドがありました。これにより、検索時にエラーが発生します。これらのフィールドのいずれかによる検索または並べ替えでは、最初の left_join からのデータのみが使用されます。

class TransactionsDatatable < AjaxDatatablesRails::ActiveRecord
  extend Forwardable
  def_delegators :@view, :current_user

  def initialize(params, opts = {})
    @view = opts[:view_context]
    super
  end

  def view_columns
    @view_columns ||= {
      id: { source: 'Transaction.id', cond: :eq, searchable: true },
      stored_product_id: { source: 'StoredProduct.name', searchable: true },
      user_id: { source: 'User.name', cond: :like, searchable: true },
      from_stockroom_id: { source: 'from_stockroom_name', cond: :like, searchable: true, orderable: true },
      to_stockroom_id: { source: 'to_stockroom_name', cond: :like, searchable: true, orderable: true },
      quantity: { source: 'Transaction.quantity', searchable: false, orderable: false },
      comment: { source: 'Transaction.comment', cond: :like, searchable: true, orderable: false },
      created_at: { source: 'Transaction.created_at', searchable: false }
    }
  end

  def data
    records.map do |record|
      {
        id: record.id,
        stored_product_id: record.stored_product.name,
        user_id: record.user.name,
        from_stockroom_id: record.from_stockroom.present? ? record.from_stockroom.name : 'Поставка',
        to_stockroom_id: record.to_stockroom.present? ? record.to_stockroom.name : 'Списание',
        quantity: record.quantity,
        comment: record.comment,
        created_at: record.created_at.strftime('%d.%m.%Y'),
        DT_RowId: record.id
      }
    end
  end

  def get_raw_records
    Transaction.where(deleted: false)
               .joins(:stored_product, :user)
               .joins('LEFT JOIN stockrooms AS from_stockrooms ON from_stockrooms.id = transactions.from_stockroom_id')
               .joins('LEFT JOIN stockrooms AS to_stockrooms ON to_stockrooms.id = transactions.to_stockroom_id')
               .select('transactions.*, from_stockrooms.name as from_stockroom_name, to_stockrooms.name as to_stockroom_name')
  end

  def filter_records(records)
    to_search_value = params[:columns]['4']['search']['value']
    from_search_value = params[:columns]['3']['search']['value']
    multiple_search_value = params['search']['value']
    records = records.where('LOWER(from_stockrooms.name) LIKE ?', "%#{from_search_value.downcase}%") if from_search_value.present?
    records = records.where('LOWER(to_stockrooms.name) LIKE ?', "%#{to_search_value.downcase}%") if to_search_value.present?

    return records.where(build_conditions) unless multiple_search_value.present?
    
    records.where(build_conditions)
           .or(records.where(build_conditions_for_selected_columns).and(stockrooms_colums_search(records,multiple_search_value)))
  end

  def stockrooms_colums_search(records, multiple_search_value)
    records.where('LOWER(to_stockrooms.name) LIKE ?', "%#{multiple_search_value.downcase}%")
           .or(records.where('LOWER(from_stockrooms.name) LIKE ?', "%#{multiple_search_value.downcase}%"))
  end
end

params[:columns][“4”][“search”][“value”] は、検索可能なすべての列ではなく単一列での検索に使用されます