2010-12-17 18 views
9

Czy istnieje sposób na niestandardową serializację dla pól w szynach, metoda uruchamiana, gdy pole jest zapisywane i ładowane w celu konwersji z/do łańcucha, który ostatecznie jest zapisywany w bazie danych .Niestandardowa serializacja dla pól w Railsach

W szczególności chcę mieć pole typu symbol, taki jak płeć, z możliwymi wartościami: męski i żeński przechowujący "męski" i "żeński" w bazie danych. Istnieją pewne obejścia, takie jak:

def gender 
    read_attribute(:gender).try(:to_sym) 
end 

ale pozostawia obj.attributes niezmienione, więc jest to nieszczelny abstrakcją.

Odpowiedz

10

Można to zrobić w Rails 3.1. Obiekt, który chcesz serializować, musi odpowiadać metodom load i dump.

Oto przykład serializacji łańcucha w Base64.

class User < ActiveRecord::Base 
    class Base64 
    def load(text) 
     return unless text 
     text.unpack('m').first 
    end 

    def dump(text) 
     [text].pack 'm' 
    end 
    end 

    serialize :bank_account_number, Base64.new 
end 

Aby uzyskać więcej informacji zobacz: http://archives.edgerails.info/articles/what-s-new-in-edge-rails/2011/03/09/custom-activerecord-attribute-serialization/index.html

+3

Link do szczegółów wydaje się być już niestety nieaktualny. Czy był jakiś powód, dla którego zdefiniowałeś 'dump' i' load' jako metody instancji i przekazałeś nową instancję do 'serialize'? W przeciwieństwie do definiowania ich jako metod klasowych i przekazywania klasy do "serializacji"? Próbuję to zrozumieć, dzięki! – plainjimbo

+0

Tutaj robię dzikie zdjęcia w ciemności, ale wygląda na to, że serializacja ActiveRecord użyje dowolnego obiektu odpowiadającego na ': dump' i': load'. Więc nie. Nie ma powodu, dla którego są to metody instancji w przeciwieństwie do metod klasowych. – RyanScottLewis

0

Ty może użyć metody serialize wewnątrz modelu. Proszę odwołać się do tego linku: (. Ps Szukane słowo "serializacji" w tę stronę; D) http://api.rubyonrails.org/classes/ActiveRecord/Base.html

W skrócie, można to zrobić:

class YourModel < ActiveRecord::Base 
    serialize :db_field 
end 

Rails byłoby pole automatycznie serializacji przed zapisaniem do bazy danych i deserializować go po pobraniu z bazy danych.

+1

Problem polega na tym, że konwertuje on na yaml, co sprawia, że ​​dane są trudniejsze do użycia w zapytaniach, gdy wystarczy zapisać prosty symbol na konwersję ciągów znaków. To właśnie miałem na myśli, zapisując "męski" i "żeński" w bazie danych, to znaczy zamiast "---: mężczyzna" i "---: kobieta"). – Pablo

0

dobrze tylko męski/żeński można po prostu zrobić kolumnę logiczną jak samca, a jeśli było to fałszywe założenie, że rozumie kobiety, dodać metody otoki na nim

def female? 
    return !self.male? 
end 
+0

To tylko przykład, chcę zapisać więcej niż dwa symbole. Spróbuj z męską, żeńską, nieznaną i ukrytą. – Pablo

4
def whachamacallit 
    read_attribute("whachamacallit").to_sym 
end 
def whachamacallit=(name) 
    write_attribute("whachamacallit", name.to_s) 
end 

zapisać je jako użądlenia w bazy danych, ale wyodrębnij je jako symbole, gdy je wyciągniesz, a następnie odtwórz z powrotem przed zapisaniem. będzie działać z dowolną liczbą lub kombinacją ciągów/symboli.

ograniczyć go tylko kilka wybranych

validates_inclusion_of :whachamacallit, :in => [ :male, :female, :unknown, :hidden ] 
+0

Rozważałem to rozwiązanie, ale nie podoba mi się to, że jeśli spojrzę na obj.attributes, to pole jest oczywiście ciągiem, a nie polem, i wiem, że wróci, by mnie ugryźć, gdy mniej się spodziewam to. – Pablo

0

Właśnie wydała gem (AttributeHelpers), który robi dokładnie to. Zastrzeżenie: Jestem opiekunem tego klejnotu.

Umożliwia wywołanie attr_symbol :gender w definicji klasy, a serializacja odbywa się automagicznie.