我有一个模型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_by
和find_or_create_by
方法吗?如果是这样,最好的方法是什么?
答案 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列创建视图到此视图中的函数。如果您不尝试写入虚拟列 - 视图是可编辑的。