2014-11-20 10 views
25

Załóżmy, że mam model User z atrybutami :id, :first_name, :last_name, and :email. W mojej aplikacji użytkownicy-goście nie powinni widzieć User's email and last_name. Wiem jak wybrać konkretne wartości, jeśli chcę listę użytkowników, ale nie wiem, jak mogę dostać konkretne atrybuty konkretnego użytkownika jakUzyskiwanie określonych atrybutów z modelu ActiveRecord

User.find_by(id: 5).select(:id, :first_name). 

jedno rozwiązanie, które jest użytkownik

User.find_by(id: 5).attributes.slice('id', 'first_name') 

, ale otrzymuję skrót zamiast rekordu AR. Mógłbym zrobić tylko to, czego nie wiem, które filtry powinienem filtrować, ponieważ muszę najpierw znać użytkownika.

Czy możesz mi pomóc?

+0

Jak odróżnić ** Gość ** z ** zwykły użytkownik **? – Pavan

Odpowiedz

62

Co Choco powiedział, że będzie działać, jeśli chcesz tablicę instancji nie aktywny rekord. Jeśli chcesz aktywną instancję rekordów, wykonaj następujące czynności:

User.where(id: 5).select(:id, :first_name).take 

Oto kilka dodatkowych informacji. Nie jestem pewien, ile masz/nie wiesz, więc zakładam, że wiesz mniej, niż więcej.

Zakładam, że zdajesz sobie sprawę z tego, co robisz powyżej, to jest metoda łańcuchowa - tzn. Wywołujesz metodę, a następnie wywołujesz inną metodę na wyniku pierwszej metody. Na przykład:

User.find_by(id: 5).attributes.slice('id', 'first_name') 

Dzwonisz metodę find_by_id na klasie User. Ta metoda zwróci instancję z klasy User (tj. Aktywną instancję rekordu). Ta instancja ma metodę o nazwie attributes, którą wywołujesz. Metoda attributes zwraca instancję klasy Hash reprezentującą pola z poprzedniej aktywnej instancji rekordu. Hash ma metodę slice, którą wywołujemy po kolei. Metoda slice zwraca inne wystąpienie Hash, zawierające podzestaw określonych przez ciebie pól.

Tak więc należy jasno określić, że podczas łączenia metod nie wywołuje się każdej kolejnej metody na tej samej zasadzie - wywołuje się ją w zwracanej wartości poprzedniej metody w łańcuchu .

OK, więc z tego na drodze:

Wszystkie metody find przeznaczone są do zapytań do bazy danych i zwróci jeden przypadek modelu aktywnego zapisu lub zwykły tablicy rubinowy zawierającego wiele instancji Active Record modele.

Wiele innych metod - select, where, itp., NIE trafiają od razu w bazę danych i NIE są przeznaczone do zwracania aktywnej instancji rekordu. Wszystkie zwracają instancję ActiveRecord::Relation.Numer ActiveRecord::Relation przypomina potencjalną grupę rekordów spełniających określone warunki - możesz dodać do niej dodatkowe warunki. To jak "zapytanie o bazę danych, które czeka, aby się wydarzyć" lub "zapytanie o bazę danych, które mogło, ale nie musiało się jeszcze wydarzyć".

Po wywołaniu metody jak where, order lub select na ActiveRecord::Relation, zwróci instancję ActiveRecord::Relation, co oznacza, że ​​masz instancji tej samej klasy, a może metody łańcuchowe z tej klasy ładnie np User.where(name: 'Fred').select(:id, :name).order('name ASC')

Twoje wystąpienie ActiveRecord::Relation będzie bardzo inteligentny i nie będzie przeszkadzało trafienia bazy danych do czasu wywołania metody, która wyraźnie wskazuje, chcesz rekordy teraz - jak each, all, take itp

Tak więc, poszedłem na dłużej, niż planowałem, więc zakończę. Oto kod po raz pierwszy wspomniano, z podziałem, mocno skomentował wyjaśnienie poniżej:

User.where(id: 5).select(:id, :first_name).take 

złamanie go:

my_relation = User.where(id: 5) 
# The database will not have been hit yet - my_relation 
# is a query waiting to happen 

my_second_relation = my_relation.select(:id, :first_name) 
# The database has STILL not been hit. 
# the relation now contains both the conditions 
# from the previous my_relation, and the new 'select' 
# criteria we specified 

my_user = my_second_relation.take 
# OK, 'take' means we want the first record 
# matching all our criteria, 
# so my_second_relation will hit the database 
# to get it, and then return an Active Record 
# instance (ie, an instance of the User class) 

Wow ... poszedłem na dłużej niż oczekiwano. Mam nadzieję, że niektóre z nich były przydatne!

+0

Doskonałe ...... – Filippos

+4

Jedno z najlepszych wyjaśnień ActiveRecord :: Relacje, które kiedykolwiek przeczytałem! Dziękuję Ci!! – thenextmogul

13

Spróbuj tego:

User.where(id: 5).pluck(:id, :first_name) 

zwraca tablicę zawierającą identyfikator i first_name wartości

2

Będzie to działa tak samo

User.select(:id, :first_name).find(5)