简体   繁体   中英

What is the Rails 4 way to deal with filters?

Background: I have a few filters which have to be available through every CRUD page on the system: search, livesearch, column sorting and pagination;

This is what I currently have:

.lib/record_filters.rb 
 module RecordFilters

 @@valid_directions = %w[asc desc]

 def search_for(record)
   record.present? ? where('name LIKE ?', record+"%") : all
 end

 def records_matching(search_term)
   where('name LIKE ?', search_term+"%").map(&:name)
 end

 def order_records_by(attribute, direction)
   order(sort_table_by(attribute) +" "+ sort_records_order_by(direction))
 end

 private

 def sort_table_by(attribute)
   column_names.include?(attribute) ? attribute : "name"
 end

 def sort_records_order_by(direction)
   @@valid_directions.include?(direction) ? direction : "asc"
 end

end

./app/models/ticket_type.rb
class TicketType < ActiveRecord::Base
  include RecordFilters 

  validates_presence_of :name
  validates_uniqueness_of :name  

end

./app/controllers/ticket_types_controller.rb
class TicketTypesController < ApplicationController
  before_action :set_ticket_type, only: [:show, :edit, :update, :destroy]

  def index
    @ticket_types = TicketType.search_for(params[:search]).order_records_by(params[:sort], params[:direction]).paginate(per_page: 12, page: params[:page])
    respond_to do |format|
      format.html
      format.js
      format.json { render json: TicketType.records_matching(params[:term]) }
     end
   end
   ...
end

./config/application.rb
...
config.autoload_paths << "#{Rails.root}/lib"

The problem: Upon accessing the index on the browser, Rails returns NoMethodError for search_for

Question: What is the Rails Way to implement such filters? What am I doing wrong?

Thanks!

This is because Ruby's include will add the module's methods as instance methods :

module A
  def value
    5
  end
end
class B
  include A
end
puts B.new.a # prints 5
puts B.a # fails

If you want them as class methods , like the class object itself was extended, use extend :

method A
  def value
    5
  end
end
class C
  extend A
end
puts C.a # prints 5
puts C.new.a # fails

You can also, if you really want include , define some new methods in the module's included callback:

module A
  def self.included(mod)
    # mod is whatever (module or class) included A.
    # in this case, it's B.
    mod.class_eval do
      def self.value
        "class"
      end
      # there's no reason to do this here, instead of
      # in the module itself, but just for demonstration purposes:
      def inst
        "inst"
      end
    end
  end
end

class B
  include A
end

puts B.value # prints "class"
puts B.new.inst # prints "inst"

您的方法将作为实例方法添加,但是您像类方法那样调用它们,我建议您研究http://api.rubyonrails.org/classes/ActiveSupport/Concern.html为您实现关注模式楷模。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM