Rails 4:始终对特定模型字段使用Postgres函数

时间:2014-12-27 10:06:40

标签: ruby-on-rails postgresql diacritics

我有一个模型Location,其字段name通常包含变音符号 - 例如“Rhône-Alpes”,“Midi-Pyrénées”和“Île-de-France”。< / p>

此模型在我的应用程序中以几种不同的方式使用,特别是对于名称的查询。例子包括:

Location.find_by(name: 'Rhône-Alpes')
Location.find_or_create_by(name: 'Rhône-Alpes', country: 'France')

这些find方法的参数因应用程序而异。我的问题是:如何在每次引用名称字段时确保调用某个Postgres函数(在本例中为unaccent())?这意味着我可以搜索“Rhone”和“Rhône”,并获得相同的结果。

最好覆盖find_byfind_or_create_by方法吗?如果是这样,最好的方法是什么?

3 个答案:

答案 0 :(得分:1)

将逻辑推入数据库层总是好的,但是如果你一直在处理很多不同的项目,你可能需要在将来执行查找而不会不知情,然后在你不能轻易地遇到问题调试所以你这样做时一定要小心。

不要覆盖find_by方法,不建议这样做,因为您可能会执行标准的find_by并产生无法预料的后果。

您是否考虑过在find_by之前清理输入?

>> ActiveSupport::Inflector.transliterate("Rhône-Alpes")
=> "Rhone-Alpes"

答案 1 :(得分:1)

我知道您在使用 name 查询时正在使用 find_by find_or_create_by ,并且您可以覆盖这些类方法,而不是完全确定如何以正确的方式做到这一点,但它应该非常简单。但是为什么不创建一个类方法来专门用 name ?查询?,就像一个范围!在那里,您可以将给定的名称作为参数和模型中的实际名称值进行转换。这样的事情(假设你有一个Ruby方法 unaccent 供你使用)......

def self.named(name)
  self.all.select {|location| unaccent(location.name) == unaccent(name) }
end

不确定这是否是您正在寻找的答案,但这是一种方法,您将此逻辑留在模型层中,独立于 DBMS 您&# 39;重新使用。

最佳。

答案 2 :(得分:0)

您可以在DB中创建虚拟列,如下所示:

CREATE TABLE customer (id SERIAL, firstname TEXT, lastname TEXT);

-- create virtual column
CREATE FUNCTION fullname(customer) RETURNS text AS $$
    SELECT $1.firstname || ' ' || $1.lastname
$$ LANGUAGE SQL;

INSERT INTO customer VALUES (DEFAULT, 'Mark', 'Pennypincher');

SELECT customer.fullname FROM customer;

(从http://momjian.us/main/blogs/pgblog/2013.html#April_1_2013被盗)

其他选项是将table和wrap列创建视图到此视图中的函数。如果您不尝试写入虚拟列 - 视图是可编辑的。