2012-04-27 10 views
8

Bir ActiveRecord modelinde bir öznitelik belirleyicisi oluşturmaya çalışıyorum, rayları sql sorgularını oluşturmadan önce text2ltree() postgres işlevindeki değerini kaydır. Örneğin Öznitelik ayarlayıcısı SQL işlevi üzerinden değer gönderme nasıl

,

post.path = "1.2.3" 
post.save 

oluşturmak mı

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

Bunu yapmanın en iyi yolu nedir gibi bir şey?

+0

Bir Postgres işlevi (saklı yordam) yazabilir ve sonra sadece 'SELECT myfunc ('1.2.3')' komutunu kullanabilirsiniz. Bu rotayla ilgileniyorsanız bir örnek verebilirim. –

cevap

2

DÜZENLEME: tam olarak yukarıdaki aradıklarını başarmak için, modeli dosyasında varsayılan ayarlayıcı geçersiz kılmak için kullanabilir ediyorum:

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

Sonra yukarıdaki var kod çalışır.

ActiveRecord'un iç yapısı ve onun metalaştırılmamış meta alt öğeleri hakkında daha fazla bilgi edinmek istiyorum, bu nedenle aşağıdaki yorumlarda açıkladığınız şeyi gerçekleştirmeye çalıştım.

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 

Konsol çıktı:

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> 

Sana include ActiveRecord içinde modül isterdim tahmin Gerçek hayatta İşte (bu her post.rb içindedir) benim için çalıştı bir örnek: : Temel, bir dosyada daha önce yük yolunda bir dosyada. Ayrıca, veritabanı işlevine ilettiğiniz argümanın türünü doğru bir şekilde ele almanız gerekir. Son olarak, her bir veritabanı bağdaştırıcısı tarafından connection.execute'un uygulandığını öğrendim, bu nedenle sonuca erişme şekliniz Postgres'te farklı olabilir (bu örnek, sonuç kümesinin bir dizi karma sayısı ve ilk veri kaydının anahtarı olarak döndüğü SQLite3'tür) . 0]

Bu blog yayını inanılmaz yararlı oldu:

http://www.fakingfantastic.com/2010/09/20/concerning-yourself-with-active-support-concern/

Raylar eklenti-yazarlık için rehber olarak:

http://guides.rubyonrails.org/plugins.html

Ayrıca, değerinin ne olduğuna göre, Postgres'te bunu bir sorgu yeniden yazma kuralı oluşturmak için bir geçiş kullanarak hala yapacağımı düşünüyorum, ancak bu harika bir öğrenme deneyimi için yapıldı. Umarım çalışır ve şimdi nasıl yapılacağını düşünmeden durabilirim.

+1

Bunu düşündüğümden tamamen farklı bir yolu, Postgresql'in sorgu yeniden yazma motorunu kullanmak olurdu. Tetik kullanan bir şey gibi. Değeri işlevden geçirilecek şekilde güncelleştirmeleri yeniden yazmak için yalnızca kuralı ayarlarsınız. Bunun tersi, modelinizin temiz olması ve sadece veritabanına bir çağrı yapmanızdır. Dezavantajı, veritabanı-agnostik değil, ki bu sizin durumunuzda bir sorun olmayabilir. Örnek vermek için sözdizimine yeterince aşina değilim, ancak işte dokümanlar için bir bağlantı: http://www.postgresql.org/docs/8.4/static/sql-createrule.html –

+0

Burada daha etkili bir yöntem olmalı bunu yapmak için daha etkili bir yol olmalı. Bu, ActiveRecord/Arel –

+0

ya da "yama" kelimesini içerir. "Verimli" ile performans demek, sorgu yeniden yazma metodu üstündür; Ralara, db'ye iki çağrı yapılmasını engelleyecek herhangi bir şeyi nasıl uygulayabileceğinizi anlamıyorum. Eğer "verimli" demekse, sizden daha hızlı (daha önce bunu yapmak istediğiniz tek yer olmadığı varsayılarak), daha iyi ifade ederseniz, bunun bir seçenek olduğuna katılıyorum. –

İlgili konular