ajax-datatables-rails icon indicating copy to clipboard operation
ajax-datatables-rails copied to clipboard

Sorting on a model method (not a database column)

Open twicebishop opened this issue 9 years ago • 16 comments

Is there any way I can configure AjaxDatatablesRails to sort based on a model method? It's working great on all the other columns based on database columns, but I get errors when attempting a model method.

In the example below, I'd like to search based on the model method "row_total":

class SearchTimecardRowDatatable < AjaxDatatablesRails::Base
  def sortable_columns
    @sortable_columns ||= ['Timecard.start_date',
                           'TimecardRow.monday',
                           'TimecardRow.tuesday',
                           'TimecardRow.wednesday',
                           'TimecardRow.thursday',
                           'TimecardRow.friday',
                           'TimecardRow.saturday',
                           'TimecardRow.sunday',
                           'TimecardRow.row_total'
                           'Timecard.timecard_state']
  end
....
end

class TimecardRow < ActiveRecord::Base
  def row_total
    0.0 +
    (self.monday    || 0.0) +
    (self.tuesday   || 0.0) +
    (self.wednesday || 0.0) +
    (self.thursday  || 0.0) +
    (self.friday    || 0.0) +
    (self.saturday  || 0.0) +
    (self.sunday    || 0.0)
  end
end

twicebishop avatar Feb 15 '16 23:02 twicebishop

@twicebishop its not possible on current version. look at the latest version and look at this example project https://github.com/ajahongir/ajax-datatables-rails-v-0-4-0-how-to/

ajahongir avatar Feb 17 '16 07:02 ajahongir

@twicebishop It currently released on request https://github.com/antillas21/ajax-datatables-rails/pull/123 you can look it at sample project

ajahongir avatar Mar 13 '16 10:03 ajahongir

@ajahongir Hi, I'm checking the latest version of the gem, but I don't see the way to sort over a model method, but watching the documentation and the sample project, it seems that in the end you filter by an association or a custom_column which maps to an already existing database column, maybe this is not possible in the way I'm visualizing it.

For example, let's take the following scenario of a Model:

class SalesOrder < ActiveRecord::Base

  has_many :item_lists
  def total
    subtotal=0
    self.item_lists.each do |item|
      if item.material_price == nil
        subtotal += item.qty * item.material.unit_price
      else  
        subtotal += item.qty * item.material_price
      end
    end
  subtotal
  end
end

I want to be able to order by the method "total", which is not a database column, but in order for this happen, it obviously needs to get evaluated before being able to order/sort it, it would be something like doing a SortBy on the AR Relation and then paginate over it:

SalesOrder.all.sort_by(&:total)

But this returns an Array which is not accepted as a return value for the "get_raw_records" method. This is one of the simplest scenarios, there are others where the logic inside the model method is much more complicated.

Is there any easier/cleaner way to accomplish this using this gem? Do you have any recommendation?

kuronae12 avatar Jan 14 '17 06:01 kuronae12

you can try to override https://github.com/antillas21/ajax-datatables-rails/blob/v-0-4-0/lib/ajax-datatables-rails/base.rb#L39

ajahongir avatar Jan 16 '17 05:01 ajahongir

@ajahongir Yeah, thanks, already modified the gem in order to be able to make this orders by custom model methods.

kuronae12 avatar Jan 18 '17 03:01 kuronae12

@kuronae12 can you please share how you did it? Thanks

nsantiago2719 avatar Sep 22 '17 09:09 nsantiago2719

I don't know if it's even possible due to pagination and that sort of things.

n-rodriguez avatar May 10 '18 21:05 n-rodriguez

Hi, i have a similar problem:

My model school

has_many :buildings
has_many :education_types, through: :buildings

In the education_types I have male_students_number and female_students_number

How can i shot by school.students_number in my schools_table?

Nittarab avatar Sep 12 '18 10:09 Nittarab

In the end I decided to create a counter in the school table

Nittarab avatar Sep 14 '18 16:09 Nittarab

In the end I decided to create a counter in the school table

A lot better :+1: (http://yerb.net/blog/2014/03/13/three-easy-steps-to-using-counter-caches-in-rails/)

n-rodriguez avatar Oct 03 '18 23:10 n-rodriguez

Maybe I explained myself badly, male_students_number and female_students_number are fields and not associations. So I could not use counter caches

Nittarab avatar Oct 04 '18 09:10 Nittarab

I don't know if it's even possible due to pagination and that sort of things.

@n-rodriguez Does this gem support use of calculated fields at all? Because it appears that the view_columns method requires each column in the datatable to be represented, but calculated fields won't have a true source. What is the recommended way of approaching this, if at all possible.

What I am trying to do is: given a Price table with a cost attribute a size attribute and a #cost_per_unit (cost/size) method, I want to sort things by cost_per_unit

gs2589 avatar Jan 10 '19 22:01 gs2589

@gs2589 @n-rodriguez I have similar case, where I need to do search by calculated column. Basically I have gross_price column in DB and then I have multiple discounts via has_many association which allows me to calculate neto_price. I'd be happy for any hint how to accomplish search by my neto_price value. If that helps, my model method looks like this:

  def neto_price
    if self.discounts.any?
      total = 1
      self.discounts.pluck(:value).each do |discount|
        (total = total * (1 - (discount/100))) if discount.present?
      end
      (self.base_price * total).to_f.round(2)
    else
      self.base_price
    end
  end

matissg avatar Apr 22 '19 15:04 matissg

@gs2589 I also have calculated fields, where in view_columns ||= I have binded this to methods that are not present in database.

@view_columns ||= {
      id: { source: "User.id"}, # ok
      name: { source: "User.name" }, # ok
      role: { source: "User.current_role"} # calculated
    }

It works great if you don't need filtering (search bar) , the render works and the pagination too. But using the search bar generates an error, as it is searching for the calculated method directly in database . ActiveRecord::StatementInvalid (Mysql2::Error: Champ 'users.role' inconnu dans where clause: SELECT COUNT(*) FROM users WHERE .....

Unless I'm missing some tweaking feature, I think the Databable object needs to be aware of real database column or calculated ones, in order to know where to search when filtering results.

Ex-Ark avatar May 29 '19 09:05 Ex-Ark

Hi, is there an update on this? I am also looking for a way to be able to search/sort by custom/calculated methods in datatables.

gabydi106 avatar Sep 13 '20 07:09 gabydi106

@Ex-Ark Did you saw this snippet? https://github.com/ajahongir/ajax-datatables-rails-v-0-4-0-how-to/blob/master/app/datatables/city_datatable.rb

It says that you can do something like custom_column

@view_columns ||= {
   role: { source: "current_role"} # Remove User reference from view_columns definition 
}

then in get_raw_records add your calculated column to select, eg.:

def get_raw_records
  User.select('IFNULL(guest_role, admin_role) AS current_role').all
end

toomus avatar Sep 30 '20 16:09 toomus