Walidacja

Nie wiem jak rozwiązać taki problem:
Mam formularz realizacji zamówienia i chcę sprawdzić czy zalogowany user (devise) posiada wystarczającą ilość pieniędzy na pokrycie zamówienia (system przed płacowy)
portfele mogą być w różnych walutach tak jak i zamówienia.

Mam takie relacje :
User has_many :wallets, :orders
Wallets belongs_to :user
Order belongs_to :user

Nie wiem za bardzo jak ugryźć ten problem z walidacją

Po prostu zrób własny validator w którym sprawdzisz czy user rzeczywiście posiada wymagane środki.
Co do walut to musisz je jakoś zamieniać, tu pomocny może być gem money.

Nie wiem jak wygląda u Ciebie zasada działania składania zamówień. Zakładam, że jest to po prostu tworzenie instancji np. modelu Order. Validacja musi znajdować się właśnie w tym modelu.

Wiem że muszę napisać validator i też wiem że musi znajdować się w modelu Order. Nie wiem natomiast jak się dobrać do portfela użytkownika w modelu Order.

Odwołaj się po prostu do relacji w modelu Order:

user.wallets

Najlepiej stwórz sobie metodę, która te wartości z różnych portfeli zamieni na jedna walutę a następnie zsumuje. Wtedy w modelu Order, w metodzie walidacji robisz jedynie warunek z porównaniem:

if user.sum_amount < order.amount ... end

Dobra do portfela np w PLN dokopałem się w ten sposób

[code]user.wallets(“PLN”)

puts “#{user.wallets(“PLN”).to_s}” daje w konsoli :

[#<Wallet id: 1, currency: “PLN”, avaiable: #BigDecimal:7fd975affbd0,‘0.0’,9(18), lock: #BigDecimal:7fd975affb08,‘0.0’,9(18), in_order: #BigDecimal:7fd975aff900,‘0.0’,9(18), balance: #BigDecimal:7fd975aff810,‘0.0’,9(18), user_id: 1, created_at: “2012-09-01 11:14:32”, updated_at: “2012-09-01 11:14:34”>][/code]
i jak teraz chce się odwołać do

user.wallets("PLN").avaiable dostaje error: undefined method `avaiable'

Wygląda na to, że dostajesz tablicę portfeli, zadziała user.wallets[0].avaiable, trudno powiedzieć czy powinieneś brać pierwszy portfel, czy jak jest ich więcej to ostatni itp.

Ok rozwiązałem to tak :

user.wallets.each do |w| if w.currency == sell code .... end end

zrób sobie do tego scope:

[code=ruby]app/models/wallet.rb

scope :by_currency, lamba { |cur| where(:currency => cur) }[/code]
I potem możesz zrobić tak:

user.wallets.by_currency("EUR")

I to Ci zwróci wszystkie portfele usera z daną walutą. Jeżeli powinien być tylko 1 taki portfel, to używaj tego razem z metodą first.

btw metoda powinna nazywać się available :slight_smile:

Dzięki, literówka się wkradła a raczej jej brak.
Jeszcze dorzucę takie pytanie zmianę wartości portfela wykonuję w transakcji nigdy tego nie robiłem i nie jestem pewien czy dobrze robię. I druga sprawa jak przerwać zapisywanie zamówienia jak transakcja się nie powiedzie.

[code]app/model/order.rb

before_save :transfer_money

private
def transfer_money
Wallet.transaction do
user.wallets.each do |w|
if w.currency == sell
w.available -= amount
w.in_order += amount
w.save
end
end
end
end[/code]
@Arnvald - dzięki za podpowiedź zaraz sobie to do klepie.