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.