Rails 4从与搜索项匹配的多个表中返回记录

时间:2014-12-29 22:51:49

标签: ruby-on-rails ruby

我试图从两个与搜索词中的每个词匹配的数据库表(页面和文章)中返回记录。这是我的疑问:

if params.has_key?('search_term')
  words = params['search_term'].split(' ')
  query = "
    select
      p.id
      , p.title
      , p.slug
      , p.created_at
      , p.content
      , 'page' as type
    from pages p
    where 1 = 1
  "
  words.each do |word|
    query << " and p.title like '%" << word << "%' or p.content like '%" << word << "%'"
  end
  query << "
    union all
    select
      a.id
      , a.title
      , a.slug
      , a.created_at
      , a.content
      , 'article' as type
    from articles a
    where 1 = 1
  "
  words.each do |word|
    query << " and a.title like '%" << word << "%' or a.content like '%" << word << "%'"
  end
  @search_results = ActiveRecord::Base.connection.execute(query)
end

首先,如何清除循环中word的值以防止SQL注入攻击?我想知道是否有必要进一步清理word,因为我已经拆分了搜索字词串。

其次,是否有更好的方法来接近我尝试做的事情?我对Ruby / Rails比较陌生,所以欢迎指点。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

您应该尽可能使用内置的查询工具。因此,假设您有Page类和Article类,则可以使用selectwhere

matched_pages = Page.select(:title, :slug, :created_at, :content)
matched_articles = Articles.select(:title, :slug, :created_at, :content)
words.each do |word|
  matched_pages = matched_pages.where(["title LIKE :word OR content LIKE :word", {word: "%#{word}%"}])
  matched_articles = matched_articles.where(["title LIKE :word OR content LIKE :word", {word: "%#{word}%"}])
end

如果你需要将它们合并在一起,你可以将两个结果连接起来像

@search_results = matched_pages + matched_articles

然后,如果你想在视图中:

<% @search_results.each do |item| %>
  <tr>
    <td><%= item.title %></td>
    <td><%= item.slug %></td>
    <td><%= item.created_at %></td>
    <td><%= item.content %></td>
    <td><%= item.class.name.downcase %></td>
  </tr>
<% end %>

当然,您可能还想做很多其他事情,并且除了示例之外,还有其他(通常更好的)方式在视图中显示数据,但这可以帮助您了解数据的外观等。