Ruby on rails SQLite3的通用Ruby解决方案;例如;或PostgreSQL“;“我喜欢”吗;?

Ruby on rails SQLite3的通用Ruby解决方案;例如;或PostgreSQL“;“我喜欢”吗;?,ruby-on-rails,sqlite,postgresql,search,pattern-matching,Ruby On Rails,Sqlite,Postgresql,Search,Pattern Matching,我使用SQLite3进行开发,使用PostgreSQL进行部署。然而,我面临以下问题: 我使用SQLite3进行的简单搜索: def self.search(search) if search find(:all, :conditions => ["style LIKE ? OR construction LIKE ?", "%#{search}%", "%#{search}%"]) else find(:all) end end 但是,它

我使用SQLite3进行开发,使用PostgreSQL进行部署。然而,我面临以下问题:

我使用
SQLite3
进行的简单搜索:

def self.search(search)
    if search
      find(:all, :conditions => ["style LIKE ? OR construction LIKE ?", "%#{search}%", "%#{search}%"])
    else
      find(:all)
    end
end
但是,它不适用于
PostgreSQL
,我需要将
LIKE
替换为
ILIKE
,以解决问题:

def self.search(search)
    if search
      find(:all, :conditions => ["style ILIKE ? OR construction ILIKE ?", "%#{search}%", "%#{search}%"])
    else
      find(:all)
    end
end
有没有一种“Ruby方式”可以跨任何数据库进行这些搜索

编辑-根据你的回答,我不相信我能找到一个通用的Ruby解决方案


我遵循了,最终显示两个数据库。。。嗯,令人失望…

不幸的是,我认为你不会找到解决这个问题的好办法。您可以使用的唯一其他语法不是:conditions,而是使用.where子句:

where(["style ILIKE ? OR construction ILIKE ?", "%#{search}%", "%#{search}%"])
不幸的是,正如您可能已经意识到的,这种替代语法将遇到完全相同的问题。这只是开发环境与生产环境有很大不同时会遇到的麻烦之一——SQLite和PostgresSQL之间还有其他相当大的差异。我建议您在开发机器上安装Postgres并使用它。这将使开发变得更加容易,代码也更加简洁。

不,没有“ruby方式”来搜索数据库——ruby on Rails(特别是)包含了帮助器方法,用于在ActiveRecord支持的RDB上执行CRUD操作,但没有比您提供的示例更好的搜索方式

Rails文档中与此讨论相关的部分如下所示

作为旁注,不必执行
find(:all)

Rails文档使用与Doy LIKE语句相同的语法,即:

Person.exists?(['name LIKE ?', "%#{query}%"])
使用上述方法是完全安全的

下面这样的语句不安全的原因是,
where
字符串直接传递到您的数据库查询中,而不进行任何清理,这使得您的数据库容易被利用(即,
params[:first_name]中的一个简单撇号)
可能会打乱整个查询,使数据库易受攻击(特别是SQL注入)。在上面的示例中,ActiveRecord可以清理传递到查询中的参数

Client.where("first_name LIKE '%#{params[:first_name]}%'")

虽然在生产和开发中使用不同的数据库不是一个好的做法,但使用
squel
gem仍然是一个很好的例子:

有了它,您可以使用DSL编写查询,DSL比原始sql更简单、更清晰、更可读,gem将处理它到特定于所用RDBMS的sql的转换


Ryan Bates对此有一段很好的视频:

在数据库中使用类似的
搜索可能会很痛苦。当然,它不会使用成本非常高的索引

一个较长的答案:我建议在开发中使用Postgres(抛弃sqlite3),然后在所有可搜索字段上建立全文索引
style,construction
via Postgres'
tsvector
type


使用索引时,Postgres中的全文搜索速度非常快。

问题的根源在于:

我使用SQLite3进行开发,使用PostgreSQL进行部署

那是个坏主意™. 您将继续遇到不兼容,或者更糟:在造成损坏之前无法意识到某些不兼容。
在开发和生产中使用相同的RDBMS(PostgreSQL),省去了无意义的麻烦


当您被不幸的设置所困扰时,有一个简单的解决方法:

lower(style) LIKE lower(?)
在这两种平台上都可以工作

  • 如果提供小写搜索模式,则可以删除右侧的
    下(

  • 在标准SQLite
    lower(X)
    中,仅折叠ASCII字母。关于更多信息,我引用以下章节:

    lower(X)函数返回字符串X的一个副本,其中包含所有 转换为小写的ASCII字符。默认内置的lower() 函数仅适用于ASCII字符。在上进行大小写转换的步骤 非ASCII字符,加载ICU扩展名

    我的

  • 适用于UTF-8开箱即用


作为一个受欢迎的副作用,您可以使用
较低的(样式)
在PostgreSQL中加速该查询,这比使用
ILIKE
样式上的基本索引要快

此外,由于PostgreSQL 9.1,您可以使用GIN或GIST索引来加速任何
查询,如
ILIKE
查询-三叉图不区分大小写。此相关答案中的详细说明和链接:


我曾经遇到过同样的问题,以下是我的解决方案:

我编写了一个小lib,可以为每个数据库使用该函数:

class AdapterSpecific

  class << self
    def like_case_insensitive
      case ActiveRecord::Base.connection.adapter_name
      when 'PostgreSQL'
        'ILIKE'
      else
        'LIKE'
      end
    end    

    def random
      #something
    end
  end
自从写完之后,我将部署数据库迁移到了Postgres,因为这是一个更好的设置,原因有几个(参见其他答案)


您也可以考虑对Postgres使用全文搜索,这将使您的文本搜索更加高效,有关基本实现或需要更多定制,请参阅。

我认为Arel是解决此问题的最佳方法。它由Rails用于活动记录,并且与数据库无关。您的代码在sqlite3或postgres中也可以使用,这似乎适合您的情况。在postgres环境中,使用matches方法将自动切换到ilike。 例如:


您可以从github获得更多信息:

非常感谢,但从上一页来看,它说
将自己的条件构建为纯字符串会让您容易受到SQL注入攻击。例如,Client.where(“first#u name,比如“%”{params[:first_name]}%')是不安全的。
出于这个原因,我认为有更好的方法(“ruby方法”)可以做到这一点。是的,这不是一个好方法
def self.search(search)
    if search
      find(:all, :conditions => ["style #{AdapterSpecific.like_case_insensitive} :query OR construction #{AdapterSpecific.like_case_insensitive} :query", {:query => "%#{search}%"}])
    else
      find(:all)
    end
end
users=User.arel_table
User.where(users[:style].matches("%#{search}%").or(users[:construction].matches("%#{search}%")))