在我的应用程序中,我有很多页面需要显示人员列表,并允许用户使用表单对其进行过滤。这些页面通常看起来很相似。过滤器共享部分,但仍不相同。
我想知道如何避免对不同的控制器重复几乎相同的代码?我尝试了作用域,但无论如何我仍然需要解析参数并在视图中填充表格。
谢谢!
答案 0 :(得分:0)
免责声明:https://github.com/dubadub/filtered的作者在这里。
ActiveRecord提供了一种用于关联的merge方法。它与两个查询部分相交,从而可以将查询逻辑分解为多个部分。
基于这个想法,我创建了一个宝石https://github.com/dubadub/filtered。
在您的情况下,可能是这样的:
# app/controllers/people_controller.rb
class PeopleController < ApplicationController
before_action :set_filter
def index
@people = People.all.merge(@filter)
end
private
def set_filter
@filter = PersonFilter.new(filter_params)
end
def filter_params
params.fetch(:filter, {}).permit(:age, :active, :sorting)
end
end
# app/filters/person_filter.rb
class PersonFilter < ApplicationFilter
field :age
field :active do |active|
-> { joins(:memberships).merge(Membership.where(active: active)) }
end
field :sorting do |value|
order_by, direction = value.values_at("order", "direction")
case order_by
when "name"
-> { order(name: direction) }
when "age"
-> { order(age: direction) }
else
raise "Incorrect Filter Value"
end
end
end
# app/views/people/index.slim
= form_for(@filter, url: search_path, method: "GET", as: :filter) do |f|
.fields
span Age
= f.select :age, (18..90).map { |a| [ a, a ] }
.fields
span Active
= f.check_box :active
.fields
span Sorting
span Name
= f.radio_button :sorting, "name asc"
= f.radio_button :sorting, "name desc"
span Age
= f.radio_button :sorting, "age asc"
= f.radio_button :sorting, "age desc"
.actions
= f.submit "Filter"
希望有帮助!
答案 1 :(得分:0)
您看过查询对象吗?
https://mkdev.me/en/posts/how-to-use-query-objects-to-refactor-rails-sql-queries
它们允许您在许多地方重用代码,您只需传递params.permit(...)即可获取AR输出。
# app/queries/user_query.rb
class UserQuery
attr_accessor :initial_scope
def initialize(scoped = User.all)
@initial_scope = initial_scope
end
def call(params) # is what you pass from your controller
scoped = by_email(@initial_scope, params[:email]
scoped = by_phone(scoped, params[:phone]
# ...
scoped
end
def by_email(scoped, email = nil)
email ? where(email: email) : scoped
end
def by_phone(scoped, phone = nil)
phone ? where(phone: phone) : scoped
end
end
# users_controller.rb
class UsersController < ApplicationController
def index
@users = UserQuery.new(User.all)
.call(params.permit(:email, :phone))
.order(id: :desc)
.limit(100)
end
end
# some other controller
class RandomController < ApplicationController
def index
@users = UserQuery.new(User.where(status: 1))
.call(params.permit(:email))
.limit(1)
end
end
您可能可以重构此示例,以减少为编写更丰富的对象的查询而花费的前期投资,如果您提出了替代方案,请在此处张贴,以便其他人可以学习如何使用查询对象。