我是Ruby on Rails的新手,所以如果问题很愚蠢,你会原谅我自己......
我有一个表和两个表单,第一个表单是过滤(通过复选框),第二个表单是搜索表。
我想要的是使用已应用的过滤器搜索表格。我真的不知道如何...我如何从控制器搜索方法访问“已经过滤”的数据。
源代码:
prices_controller.rb
def filter()
@prices = Price.where(date: Date.today).order(price: :asc)
if params[:filter1] != nil
@prices = @prices.where('filter1_field IN (?)', params[:filter1])
end
if params[:filter2] != nil
@prices = @prices.where('filter2_field IN (?)', params[:filter2])
end
respond_to do |format|
format.js
end
end
def search()
# Here I would like to use filtered prices, not all prices
@prices = Price.where(date: Date.today).order(price: :asc)
if params[:search] != nil
@prices = @prices.where('name LIKE ?', "%#{params[:search]}%")
end
end
它有效,但我没有使用过滤值... 有没有办法保存最后一个查询或类似的东西。我尝试返回搜索方法ActiveRecord :: Relation但该方法中不存在的方法。其他替代方法是使用相同的形式进行过滤和搜索。
我接受任何建议。
非常感谢。
答案 0 :(得分:1)
这里有一个非常糟糕的错误:您的IN
已损坏。
ActiveRecord执行SQL清理(以防止SQL注入),因此在您编写时:
query.where("a in ?", "hey")
在SQL端获得WHERE a in "hey"
。
您的查询中的内容相同:您的IN参数将被字符串化。
如果您的filter1
是a,b,c
,则查询将如下所示:
WHERE a iN ("a,b,c")
这根本不是你想要的。
ActiveRecord能够在传递数组时生成IN
。所以这个:
query.where(a: [1, 2, 3])
将生成:
WHERE q IN (1, 2, 3)
这就是你想要的!
现在,关于代码本身......
执行所需操作的最简单方法是将代码移动到另一个方法,并在两个位置重复使用它:
def filter()
@prices = build_filter_query(Date.today, params[:filter1], params[:filter2])
respond_to do |format|
format.js
end
end
def search()
@prices = build_filter_query(Date.today, params[:filter1], params[:filter2], params[:search]) #pass in an extra param here!
end
private
def build_filter_query(date, filter1, filter2, search = nil)
# use a local variable here
prices = Price.where(date: Date.today).order(price: :asc)
if filter1
prices = prices.where(filter_field1: filter1)
end
if filter2
prices = prices.where(filter2_field: filter2)
end
if search
prices = prices.where('name LIKE ?', "%#{search}%")
end
return prices
end
答案 1 :(得分:1)
你不能直接这样做,因为
但是,您可以将过滤阶段返回的ID存储在会话中,并在搜索阶段使用这些ID。
def filter
@prices = Price.where(date: Date.today).order(price: :asc)
if params[:filter1] != nil
@prices = @prices.where('filter1_field IN (?)', params[:filter1])
end
if params[:filter2] != nil
@prices = @prices.where('filter2_field IN (?)', params[:filter2])
end
session[:price_ids] = @prices.pluck(:id)
respond_to do |format|
format.js
end
end
def search
@prices = session[:price_ids].present? ?
Price.where(id: session[:price_ids]) :
Price.all
@prices = @price.where(date: Date.today).order(price: :asc)
if params[:search] != nil
@prices = @prices.where('name LIKE ?', "%#{params[:search]}%")
end
end
这种方法的缺点是您必须在适当的时间从会话中删除价格ID,这很难定义。
另一种方法是确保浏览器在每次请求搜索时发送过滤器(除非您的Rails应用程序是单页面应用程序的API)。每当更改过滤器时,此方法都需要重定向。
def filter
redirect_to search_path(params.slice(:filter1, :filter2))
end
def search
@prices = Price.where(date: Date.today).order(price: :asc)
if params[:filter1] != nil
@prices = @prices.where('filter1_field IN (?)', params[:filter1])
end
if params[:filter2] != nil
@prices = @prices.where('filter2_field IN (?)', params[:filter2])
end
if params[:search] != nil
@prices = @prices.where('name LIKE ?', "%#{params[:search]}%")
end
end
您的搜索表单应包含2个过滤器隐藏字段
<%= form_tag '/prices/search', method: :get do %>
<%= hidden_field_tag :filter1, params[:filter1] %>
<%= hidden_field_tag :filter2, params[:filter2] %>
<!-- other form stuff ... -->
<% end %>