8

RailsがSQLクエリを生成する前に、ActiveRecordモデルの属性セッターにその値をtext2ltree()postgres関数でラップさせようとしています。

例えば、

post.path = "1.2.3"
post.save

次のようなものを生成する必要があります

UPDATE posts SET PATH=text2ltree('1.2.3') WHERE id = 123 # or whatever

これを行うための最良の方法は何ですか?

4

1 に答える 1

3

編集:上記で探しているものを正確に実現するには、これを使用してモデルファイルのデフォルトのセッターをオーバーライドします。

def path=(value)
  self[:path] = connection.execute("SELECT text2ltree('#{value}');")[0][0]
end

次に、上記のコードが機能します。

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

コンソール出力:

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> 

include実生活では、ActiveRecord :: 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でも移行を使用してクエリ書き換えルールを作成することでこれを行うと思いますが、これは素晴らしい学習体験になりました。うまくいけば、それがうまくいき、私は今それを行う方法について考えるのをやめることができます。

于 2012-04-30T19:02:32.913 に答える