2016-07-24 73 views
0

我是Ruby on Rails的新手,所以你原谅自己,如果问题很傻...如何获取最后一个ActiveRecord查询数据?

我有一个表和两种形式,第一种形式是过滤(通过复选框),第二种是搜索表格。

我想要的是用已经应用的过滤器搜索表格。我真的不知道要做什么......我如何从控制器搜索方法访问“已经过滤”的数据。

的源代码:

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有/过滤器2? – Ven

+0

在同一页面中,有两种形式和一张表格。第一种形式的操作是过滤器,参数是filter1和filter2。第二种形式的行为是搜索,参数是搜索。 – Antonio

+0

好吧,所以这两种形式是两种不同的动作 – Ven

回答

1

你不能这样做,因为直接

  1. 应用于过滤器的请求,并触发该请求的搜索是各色2 nt请求。
  2. Rails为每个请求初始化一个新的控制器实例,所以用于过滤的控制器和用于搜索的控制器是2个不同的对象。他们不共享任何实例变量。

但是,您可以将筛选器阶段返回的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 %> 
+0

它适用于我。谢谢 – Antonio

1

这里有一个非常糟糕的错误:你的IN坏了。

的ActiveRecord做SQL消毒(防止SQL注入),所以当你写:

query.where("a in ?", "hey") 

你得到WHERE a in "hey" SQL一边。 在你的查询中是一样的:你的IN参数将被串化。

如果您filter1a,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 
+0

它不起作用。当我提交搜索表单时,filter1和filter2参数将为零,因为它们是另一种形式。 – Antonio

+0

啊!请注意,您没有发布您的HTML,所以我无法猜测。一个更简单的选项是使用相同的表单和不同的按钮。 – Ven

相关问题