Tablica dwu wymiarowa, problem z odwolaniem sie do jej elementow

Mam następujący kod w kontrolerze (gdize photo to wynik zapytania z bazy danych z limitem ustawionym na 5)

@data= [[0]*3]*5 i = 0 photo.each do |v| @data[i][0] = getInfo(:photo_id => v) @data[i][1] = getInfo1(:photo_id => v) @data[i][2] = getInfo2(:photo_id => v) i = i + 1 end
W widoku po wywolaniu: <%= @data.inspect %>
dostaje 5 wpisow z takimi samymi danymi.

W związku z tym mam pytanie: jak mozna dostac sie do danych z tablicy tudzież jak poprawnie zapisać tablicę danymi
Przy okazji zapytam czy przy metodzie .each jest jakoś “dodany” iterator, tak, żebym nie musial tworzyć swojego “i”

chyba chodzi Ci o coś takiego (zamieniłem Ci nazwę zmiennej z 5ma zdjęciami na photos)

@data = photos.map do |photo| opts = {:photo_id => photo} [getInfo(opts), getInfo1(opts), getInfo2(opts)] end
each w wersji z indeksem nazywa się each_with_index ,
http://ruby-doc.org/core-1.9.3/Enumerable.html

Właśnie o to mi chodziło. Pięknie dziekuję.

Pokaż większy kawałek kodu i napisz co chcesz uzyskać. Taki kod w kontrolerze to raczej słaby pomysł :stuck_out_tongue:

W zasadzie już wszystko działa. Zastanawiam się tylko dlaczego mówisz, że taki kod w kontrolerze to słaby pomysł?

nie wiem co dokładnie próbujesz zrobić, ale kontroler nie powinien robić więcej (pomijam tu autentykacje, autoryzacje itp) niż pobranie danych z modelu i wrzucenie tego do widoku.

Potrzebuje w widoku przedstawić 3 zmienne. Jedną z nich jestem w stanie bez problemu pobrać z modelu, dwie pozostałe muszę uzyskać na podstawie innych metod, które mam w kontrolerze. W związku z tym chcę: pobrać zmienna z widoku, podstawić ją do dwóch innych metod i efekt tego przesłać do widoku tak, abym otrzymał tam dwu wymiarową tablicę “po przejściu której” (pętla for each) dostane się do wszystkich potrzebnych mi elementów.
Czy to jest zły sposób rozwiązania problemu?

tak brzmi, pokaz kod, model, kontroler, widok i napisz co chcesz zrobic, widac jakby sie przydalo przeniesc kod z kontrolera od modelu po pierwsze

Kontroler:

@data = [[0]*3]*5 votes = zapytanie0 @data = votes.map do |v| [zapytanie1(v),zapytanie2(v),zapytanie3(v)] end return @data
W modelu nie mam nic, tj. tylko tyle ile wygenerowałem poleceniem rails generate model

W widoku:

<% @data.each do |d| %> <%=d[0] %> <%=d[1] %> <%=d[2] %> <% end %>
Zapytam przy okazji jeszcze o dwie sprawy:

  1. Czy return w rubym jest wymagany, ew. kiedy warto go stosować etc.
  2. Czy przy wykonywaniu metody each powstaje jakaś zmienna, która podlega inkrementacji wraz z każdym kolejnym przebiegiem pętli ?

[quote=trojek]Zapytam przy okazji jeszcze o dwie sprawy:

  1. Czy return w rubym jest wymagany, ew. kiedy warto go stosować etc.
  2. Czy przy wykonywaniu metody each powstaje jakaś zmienna, która podlega inkrementacji wraz z każdym kolejnym przebiegiem pętli ?[/quote]
  3. Return to ostatnia linia w danej metodzie / funkcji zwracająca jakąś wartość

def a 3 end
zwróci 3

def b if false 3 else 4 end end
zwróci 4

  1. http://www.ruby-doc.org/core-1.9.3/Enumerator.html#method-i-each_with_index

Czy dobrze rozumiem, że jeżeli nie napiszę return w ostatniej lini tylko nawe zmiennej to efekt będzie taki sam jak bym napisał “return nazawa_zmiennej”. Jeżeli tak to po co sie przydaje slowo return w rubym ?

@trojek, nie wiem, czy zaczynasz z rubym, czy ogólnie z programowaniem, ale to nie jest ładny kod. Spróbuj poczytać sobie o założeniach programowania obiektowego ogólnie. Dosyć ciężko się to czyta, nie do końca wiem co chcesz uzyskać. Napisz w miarę dokładnie co ten kod ma robić, to mogę Ci z tym pomóc, ale w tym momencie chcąc pozamykać to w senswny sposób w metody nie mam pojęcia jak je w ogóle nazwać ;).

Tak, dobrze rozumiesz, a return przydaje się, żeby zwrócić coś nie na końcu metody :wink:

Np.

[code=ruby]def do_something
return false if something_wrong?

do other stuff

some_variable
end[/code]
W tym przykładzie, jeśli spełniony zostanie warunek, metoda zwróci false, jeśli nie - wartość zmiennej some_variable.

Uproscilem kod wpisany powyzej.
Otoz chce na podstawie jednego zapytania (o id), zadać 3 inne pytania, a następnie przesłać je do widoku. W związku z tym doszedłem do wniosku, że można to zrobić w tablicy dwu-wymiarowej, a w widoku przejrzeć wspomnianą tablicę i dla “pierwszego wymiaru”, wypisać elementy od 0 do 2 (wlacznie). Gdzie uważasz, że jest błąd w rozumowaniu ?

[quote=trojek]Kontroler:

@data = [[0]*3]*5 votes = zapytanie0 @data = votes.map do |v| [zapytanie1(v),zapytanie2(v),zapytanie3(v)] end return @data
W modelu nie mam nic, tj. tylko tyle ile wygenerowałem poleceniem rails generate model[/quote]
Chodziło mi bardziej o to, żebyś opisał to po ludzku - “mam zdjęcia i głosy, chcę zrobić…”. Nie rozumiem po co inicjalizujesz zmienną @data, jeśli 2 linijki później ją nadpisujesz.

Napiszę jak to powinno być zrobione mniej więcej, zakładając, że coś Ci ma przyjść z widoku, później możesz to zastosować w swoim kodzie i zobaczymy co wyjdzie.

[code=ruby] # kontroler

tutaj z założenia powinieneś mieć mało kodu

@data = Vote.do_something_with_votes(params[:some_data])

#model

tutaj masz metodę, która zależy od czegoś co dostajesz w kontrolerze

def self.do_something_with_votes(attributes)
#znajdujesz obiekty klasy vote, których potrzebujesz
for_this_awesome_data(attributes).map do |v|
#wykonujesz na nich metody, które coś z nimi zrobią
[v.query1, v.query2, v.query3]
end
end

def self.for_this_awesome_data(attributes)
where(:something => attributes[:something])
end

def query1
# (…)
end
def query2
# (…)
end
def query3
# (…)
end[/code]
P.S. jak widzisz ciężko jest coś takiego tłumaczyć używając jakichś wyimaginowanych nazw zmiennych, rozwiązując wyimaginowany problem. Programowanie obiektowe jest takie fajne, bo można łatwo modelować sytuacje z życia na kod. Nie ma potrzeby tego komplikować opisując problemy na poziomie - chcę przesłać zmienną gdzieś i ją odesłać - opisuj to ludzkim językiem, to będzie prościej.

Wydaje mi się, że nieco się zagalopowaliśmy. Przeważnie na forum opisuję albo hipotetyczną sytuację (gdyż staram się zapoznać z językiem), albo wstawiam zmieniony fragment kodu na taki, aby byl bardziej czytelny z punktu widzenia problemu konkretnego, a nie ogolnego. Stad moze Ci sie wydawać, że to jest zagmatwane. W tej sytuacji nie było inaczej, w zasadzie dyskusja rozwinęła się nie za moją przyczyną, a operowaliśmy na hipotetycznym przykładzie. W związku z tym proponuję na razie ten temat zamknąć, a jak będę miał coś konkretnego to założe nowy wątek dotyczący “ludzkiego problemu” i ogólnej struktury aplikacji.

Wydaje mi się, że mój kod mimo wszystko pasuje do Twojego przypadku, nie ma co się spinać, po prostu raz przekombinowałeś w jedną stronę, raz w drugą. Spróbuj zaimplementować to w taki sposób jak mniej więcej opisałem i napisz jak Ci to wyszło.

BTW: Chyba rozumiem czemu tworzysz tam zmienną @data. Metoda map zwróci Ci tablicę, nie musisz inicjalizować nowej. Spójrz na to:

a = Array.new(10) #=> [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil] a.object_id #=> 70300992919600 a = 10.times.map{ |i| i } #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a.object_id #=> 70300992871720
Ten kod zwraca tablicę, nie musi być wcześniej stworzona, tak samo u Ciebie tworzysz tablicę, a później nadpisujesz tą zmienną zupełnie inną tablicą zwróconą przez metodę map.

Zmienna @data to pozostalość po innym sposobie wykonania tego samego - po prostu zapomniałem jej usunąć. Przyzwyczajony jestem do języków, gdzie trzeba wszystko zaincjować, a później można użyć. Muszę przyznać, że RoR zaskakuje mnie pod wieloma względami faktem, że wiele rzeczy dzieje się “samo” (później dochodze, że jednak nie samo;)).
Przerzuciłem wyciąganie danych i operacje na nich do modelu <- dzięki za uwagę na ten temat.