Aktualizacja:
Ten problem nie został właściwie zbadany. Prawdziwy problem leży wewnątrz render :json
.
Pierwsze wklejenie kodu w pierwotnym pytaniu da oczekiwany wynik. Jednak nadal istnieje zastrzeżenie. Zobacz ten przykład:
render :json => current_user
NIE jest tym samym, co
render :json => current_user.to_json
Oznacza to, render :json
że nie wywoła automatycznie to_json
metody skojarzonej z obiektem User. W rzeczywistości , jeśli to_json
jest nadpisywany w User
modelu, render :json => @user
wygeneruje ArgumentError
opisane poniżej.
Podsumowanie
# works if User#to_json is not overridden
render :json => current_user
# If User#to_json is overridden, User requires explicit call
render :json => current_user.to_json
To wszystko wydaje mi się głupie. Wydaje się, że mówi mi, że w render
rzeczywistości nie wywołuje, Model#to_json
gdy :json
określono typ . Czy ktoś może wyjaśnić, co się tu naprawdę dzieje?
Każdy genii, który może mi w tym pomóc, prawdopodobnie odpowie na moje inne pytanie: Jak zbudować odpowiedź JSON, łącząc @ foo.to_json (opcje) i @ bars.to_json (opcje) w Railsach
Oryginalne pytanie:
Widziałem kilka innych przykładów na SO, ale żaden nie robi tego, czego szukam.
Próbuję:
class User < ActiveRecord::Base
# this actually works! (see update summary above)
def to_json
super(:only => :username, :methods => [:foo, :bar])
end
end
Dostaję ArgumentError: wrong number of arguments (1 for 0)
w
/usr/lib/ruby/gems/1.9.1/gems/activesupport-2.3.5/lib/active_support/json/encoders/object.rb:4:in `to_json
Jakieś pomysły?
źródło
username
,foo
albobar
metody oczekiwać argumenty?username
nie jest to metoda, afoo
ibar
nie wymagają metod. Zaktualizowałem moje pytanie, aby pokazać, gdzie występuje błąd.Odpowiedzi:
Otrzymujesz,
ArgumentError: wrong number of arguments (1 for 0)
ponieważto_json
musi zostać zastąpiony jednym parametrem,options
hashem.def to_json(options) ... end
Dłuższe wyjaśnienie
to_json
,as_json
i renderowania:W ActiveSupport 2.3.3
as_json
został dodany w celu rozwiązania problemów, takich jak ten, który napotkałeś. Stworzenie z json powinny być oddzielone od renderowania z JSON.Teraz
to_json
obiektas_json
jest wywoływany w dowolnym momencie , jest wywoływany w celu utworzenia struktury danych, a następnie ten skrót jest kodowany jako ciąg JSON przy użyciuActiveSupport::json.encode
. Dzieje się tak dla wszystkich typów: obiektowych, liczbowych, datowych, łańcuchowych itp. (Patrz kod ActiveSupport).Obiekty ActiveRecord zachowują się w ten sam sposób. Istnieje domyślna
as_json
implementacja, która tworzy skrót zawierający wszystkie atrybuty modelu. Należy nadpisaćas_json
w modelu, aby utworzyć żądaną strukturę JSON .as_json
, podobnie jak staryto_json
, pobiera skrót opcji, w którym można określić atrybuty i metody do uwzględnienia deklaratywnie.def as_json(options) # this example ignores the user's options super(:only => [:email, :handle]) end
W twoim kontrolerze
render :json => o
może akceptować ciąg lub obiekt. Jeśli jest to łańcuch, jest on przekazywany jako treść odpowiedzi, jeśli jest to obiektto_json
, co wyzwala,as_json
jak wyjaśniono powyżej.Tak więc, o ile modele są poprawnie reprezentowane za pomocą
as_json
nadpisań (lub nie), kod kontrolera do wyświetlania jednego modelu powinien wyglądać następująco:format.json { render :json => @user }
Morał tej historii jest następujący: unikaj dzwonienia
to_json
bezpośrednio, pozwólrender
zrobić to za siebie. Jeśli chcesz dostosować dane wyjściowe JSON, wywołajas_json
.format.json { render :json => @user.as_json(:only => [:username], :methods => [:avatar]) }
źródło
as_json
. Jak widać w dokumentacji ActiveRecord :: Serialization ( api.rubyonrails.org/classes/ActiveRecord/… ), jest bardzo mało (nie) dokumentacji na ten temat. Spróbuję :)as_json
doktorzy!Jeśli masz z tym problemy w Railsach 3, zastąp
serializable_hash
zamiastas_json
. Dzięki temu Twoje formatowanie XML również będzie darmowe :)To zajęło mi całą wieczność, zanim to rozgryzłem. Mam nadzieję, że to komuś pomoże.
źródło
serializable_hash
? Kiedy go używam, zmienia moje kolejne wyjście XML z zawijania obiektu jego nazwą (np. „Cytat” dla obiektu cytatu ”), aby zamiast tego zawsze zawijać go„ <hash> ”.to_xml
Dla osób, które nie chcą ignorować opcji użytkowników, ale także dodają swoje:
def as_json(options) # this example DOES NOT ignore the user's options super({:only => [:email, :handle]}.merge(options)) end
Mam nadzieję, że to pomoże każdemu :)
źródło
options
= {}
Zastąp nie to_json, ale as_json. A z as_json zadzwoń, co chcesz:
Spróbuj tego:
def as_json { :username => username, :foo => foo, :bar => bar } end
źródło
as_json
tylko dla ActiveResource?render :json => current_user
, otrzymuję oczekiwany wynik domyślny (wszystkie atrybutyUser
modelu w formacie JSON). Kiedy dodamas_json
metodę do mojegoUser
modelu i spróbuję tego samego,