Nic*_*gan 8 sql postgresql activerecord ruby-on-rails arel
我试图让一个ActiveRecord模型中的属性设置器在rails生成其sql查询之前将其值包装在text2ltree()postgres函数中.
例如,
post.path = "1.2.3"
post.save
Run Code Online (Sandbox Code Playgroud)
应该生成类似的东西
UPDATE posts SET PATH=text2ltree('1.2.3') WHERE id = 123 # or whatever
Run Code Online (Sandbox Code Playgroud)
这样做的最佳方法是什么?
编辑:为了准确实现您在上面寻找的内容,您可以使用它来覆盖模型文件中的默认设置器:
def path=(value)
self[:path] = connection.execute("SELECT text2ltree('#{value}');")[0][0]
end
Run Code Online (Sandbox Code Playgroud)
然后你上面的代码就可以工作了。
我有兴趣了解更多有关 ActiveRecord 的内部结构及其难以理解的元编程基础的信息,因此作为练习,我尝试完成您在下面的评论中描述的内容。这是一个对我有用的示例(全部在 post.rb 中):
module DatabaseTransformation
extend ActiveSupport::Concern
module ClassMethods
def transformed_by_database(transformed_attributes = {})
transformed_attributes.each do |attr_name, transformation|
define_method("#{attr_name}=") do |argument|
transformed_value = connection.execute("SELECT #{transformation}('#{argument}');")[0][0]
write_attribute(attr_name, transformed_value)
end
end
end
end
end
class Post < ActiveRecord::Base
attr_accessible :name, :path, :version
include DatabaseTransformation
transformed_by_database :name => "length"
end
Run Code Online (Sandbox Code Playgroud)
控制台输出:
1.9.3p194 :001 > p = Post.new(:name => "foo")
(0.3ms) SELECT length('foo');
=> #<Post id: nil, name: 3, path: nil, version: nil, created_at: nil, updated_at: nil>
Run Code Online (Sandbox Code Playgroud)
在现实生活中,我假设您想要includeActiveRecord::Base 中的模块,位于加载路径较早位置的文件中。您还必须正确处理传递给数据库函数的参数类型。最后,我了解到这connection.execute是由每个数据库适配器实现的,因此在 Postgres 中访问结果的方式可能会有所不同(此示例是 SQLite3,其中结果集作为哈希数组返回,第一个数据记录的键是0]。
这篇博文非常有帮助:
http://www.fakingfantastic.com/2010/09/20/concerning-yourself-with-active-support-concern/
Rails 插件创作指南也是如此:
http://guides.rubyonrails.org/plugins.html
另外,就其价值而言,我认为在 Postgres 中我仍然会使用迁移来创建查询重写规则来执行此操作,但这带来了很好的学习体验。希望它能起作用,我现在可以停止思考如何去做。
| 归档时间: |
|
| 查看次数: |
994 次 |
| 最近记录: |