Ruby on rails SQLite3的通用Ruby解决方案;例如;或PostgreSQL“;“我喜欢”吗;?
我使用SQLite3进行开发,使用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
进行的简单搜索:
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}%")))