Zapisywanie stringa do bazy danych

Witam,

obiect.status

atrybut “status” objektu ściąga się z bazy jako int. Chciałbym w nim zmienić liczbę na pozycji 2 więc zamieniam do stringa i zamieniam pierwszy index.

obiekt.status.to_s[1] = "1" obiekt.save
Problem polega na tym, że nie zapisze mi stringa w bazie (chociaż pole jest varchar). A gdy zamienię na inta to mi obcina zera z początku (w tym przypadku w indeksie zerowym).

Jak mam pobrać ten atrybut od razu w stringu, żeby go tak później zapisać ?

pozdrawiam
Bartosz Sosna

Zakładając, że pytasz o railsy…:slight_smile:
Jeśli status zwraca inta, to albo masz namieszane w modelu, albo w bazie jest integer.
Wypisz sobie obiekt.class.columns_hash[“status”].sql_type i będziesz miał jasność.

[quote=brtsos]obiekt.status.to_s[1] = "1" obiekt.save
[/quote]
Obiekt.status.to_s tworzy nowy obiekt (klasy String), z tekstową reprezentacją wartości obiekt.status.
Nie zmieniasz w ten sposób wartości oryginalnego obiektu.
Taka edycja (zmiana wartości stringa pod indeksem) też nie jest najlepszym pomysłem, co chcesz osiągnąć?

Tak pytanie dotyczy Railsów :slight_smile:

[quote=maciekd]Jeśli status zwraca inta, to albo masz namieszane w modelu, albo w bazie jest integer.
Wypisz sobie obiekt.class.columns_hash[“status”].sql_type i będziesz miał jasność.[/quote]
Zwraca varchar(255) więc string. Nie rozumiem czemu nie chce zapisać.

[quote=maciekd]Obiekt.status.to_s tworzy nowy obiekt (klasy String), z tekstową reprezentacją wartości obiekt.status.
Nie zmieniasz w ten sposób wartości oryginalnego obiektu.[/quote]
Masz rację, ale ten zapis też nie działa (nie zapisuje w bazie):

obiekt.status = obiekt.status.to_s obiekt.status[1] = "1"
O dziwo zapisuje, gdy później zamienię obiekt w inta :

obiekt.status = obiekt.status.to_i

Int jednak mnie nie interesuje, ponieważ urywa mi zera na początku.

Trzymam w bazie ciąg zer “000000000”. Gdy użytkownik wykona daną akcję, zamieniam np. 3 index na 1.
I chciałbym zapisać w bazie 001000000.

pozdrawiam i dzięki za odpowiedz

Troche malo napisales, ale z tego co widze trzymasz tam tablice bitow, wiec moze skorzystasz z gema, ktory nazywa sie BitArray (https://github.com/peterc/bitarray)? Jest duzo szybszy niz operowanie na stringu.

Tak czy siak chciałbym wiedzieć dlaczego ten kod nie zapisuje mi do bazy wyniku …

// obiekt.status wynosi "000000" i jest stringiem newStatus = obiekt.status // przypisuję go do zmiennej newStatus newStatus[1] = "1" //podmieniam 1 index na 1 więc newStatus wynosi "010000" i jest stringiem (sprawdziłem) obiekt.status = newStatus // przypisuję nową wartość "010000" do obiektu obiekt.save //zapisuję, ale w bazie nic się nie zmienia
Ale taki kod zadziała :

obiekt.status = "0010101010" obiekt.save
Nie mam pojęcia dlaczego …

Model tego obiektu masz pusty? Jakieś walidacje, callbacki, includy?

Standard + 2 walidacje nie mające nic wspólnego z statusem :

[code]class XXX < ActiveRecord::Base
attr_accessible :from, :name, :status, :to, :user_id
belongs_to :user

validates :name, :presence => true
validates :name, :length => {:maximum => 30}

end[/code]

ActiveRecord updatuje tylko pola, które uległy zmianie.
Generalnie odpowiadają za to mixiny dirty (activemodel, activerecord).
Tu jest dokładna linijka porównania, czy wartość się zmieniła https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/attribute_methods/dirty.rb#L90

Mutacja stringa (to robi Twój kod) przejdzie przez tą metodę i zwróci false (tak, jakby wartość kolumny status nie uległa zmianie).
Żeby Twój przykład zadziałał, musisz podstawić pod status inny obiekt (duplikat).

newStatus = obiekt.status.dup newStatus[1] = "1" //podmieniam 1 index na 1 więc newStatus wynosi "010000" i jest stringiem (sprawdziłem) obiekt.status = newStatus // przypisuję nową wartość "010000" do obiektu obiekt.save //zapisuję, ale w bazie nic się nie zmienia

Duplikacja objektu zadziałała. Dziękuję bardzo za pomoc i wyjaśnienie.