jhund / filterrific

Filterrific is a Rails Engine plugin that makes it easy to filter, search, and sort your ActiveRecord lists.
http://filterrific.clearcove.ca
MIT License
910 stars 124 forks source link

NoMethodError - undefined method `sorted_by' for [#<ActiveRecord::Relation []>]:Array #195

Closed ate-it closed 3 years ago

ate-it commented 4 years ago

So I'm trying to implement my first search query and I seem to be having issues with the data coming back as an array, but I cannot quite see how this is happening, any pointers would be appreciated!

filterrific (5.2.1) rails (5.2.4.1) ruby (2.6.5)

Model

class Player < ApplicationRecord
  filterrific default_filter_params: { sorted_by: 'tornid_asc' },
              available_filters: [
                :sorted_by,
                :faction_search,
              ]

  def self.options_for_sorted_by
    [
      ['Torn ID', 'tornid_asc']
    ]
  end

  scope :faction_search, lambda { |query|

                           return nil if query.blank?
                           terms = query.downcase.split(/\s+/)
                           terms = terms.map do |e|
                             (e.tr('*', '%') + '%').gsub(/%+/, '%')
                             num_or_conds = 1
                             where(
                               terms.map do |_term|
                                 '(LOWER(players.faction) LIKE ? )'
                               end.join(' AND '),
                               *terms.map { |e| [e] * num_or_conds }.flatten
                             )
                           end
                                                   }

  scope :sorted_by, lambda { |sort_option|
    direction = /desc$/.match?(sort_option) ? 'desc' : 'asc'
    case sort_option.to_s
    when /^tornid/
      order("tornid #{direction}")
    else
      raise(ArgumentError, "Invalid sort option: #{sort_option.inspect}")
    end
  }
end

Controller

 def index
    @filterrific = initialize_filterrific(
      Player,
      params[:filterrific],
      select_options: {
        sorted_by: Player.options_for_sorted_by,

      },
      sanitize_params: true,
    ) || return
    @players = @filterrific.find.page(params[:page])
    respond_to do |format|
      format.html
      format.js
    end
  rescue ActiveRecord::RecordNotFound => e
    # There is an issue with the persisted param_set. Reset it.
    puts "Had to reset filterrific params: #{e.message}"
    redirect_to(reset_filterrific_url(format: :html)) && return
  end
alydersen commented 4 years ago

Hi @JackWetson ,

I would think that with the way you have set up the faction_search scope, it would always return an array. You can try to play with the scope in console to see if it returns what you are after. I don't fully understand what your scope it trying to do, but I it seems like you want to search for records in Player where the field faction matches the query? What is the num_or_conds part? It also seems like you have to do a lot of sanitation on the query - maybe you could refactor that out in a function of its own or do it in the form?

After the cleanup of the query, I would think a basic scope : faction_search, ->(factions) { where('players.factions = ?', factions) } would do it. If factions is an array, it will return all matches.

Andreas

ate-it commented 4 years ago

@alydersen you are totally correct, i'd massively over complicated this, I've stripped this right back to the below and its working as expected, thank you

scope :faction_search, lambda { |faction|
                           return nil if faction.blank?

                           where('faction LIKE ?', faction)
                         }
alydersen commented 4 years ago

Perfect - glad it worked out :-)