【问题标题】:How can I get last ActiveRecord query data?如何获取最后一个 ActiveRecord 查询数据?
【发布时间】:2016-07-24 12:55:59
【问题描述】:

我是 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 但此类中不存在的方法。其他替代方法是使用相同的表单进行过滤和搜索。

我接受任何形式的推荐。

非常感谢。

【问题讨论】:

  • 你的两个页面都有filter1/filter2?
  • 在同一个页面中,有两个表格和一个表格。第一种形式的动作是过滤器,参数是过滤器1和过滤器2。第二种形式的action是search,param是search。
  • 好的,所以这两种形式是两种不同的操作
  • 正确,每个表单一个动作。

标签: ruby-on-rails ruby activerecord


【解决方案1】:

你不能直接这样做,因为

  1. 应用过滤器的请求和触发搜索的请求是 2 个不同的请求。
  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 %>

【讨论】:

    【解决方案2】:

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

    ActiveRecord 会进行 SQL 清理(以防止 SQL 注入),所以当您编写时:

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

    您在 SQL 端获得WHERE a in "hey"。 在您的查询中也是如此:您的 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
    

    【讨论】:

    • 它不起作用。当我提交搜索表单时,filter1 和 filter2 参数将为零,因为它们在另一个表单中。
    • 啊!请注意,您没有发布您的 HTML,因此我无法猜测。更简单的选择是使用相同的表单和不同的按钮。
    猜你喜欢
    • 1970-01-01
    • 2020-04-26
    • 2014-07-01
    • 1970-01-01
    • 2022-08-03
    • 2020-03-13
    • 1970-01-01
    • 1970-01-01
    • 2021-06-07
    相关资源
    最近更新 更多