W Railsach, jak renderujesz JSON za pomocą widoku?

125

Załóżmy, że jesteś w kontrolerze użytkowników i chcesz uzyskać odpowiedź json na żądanie pokazu, byłoby miło, gdybyś mógł utworzyć plik w swoim katalogu views / users / dir o nazwie show.json i po # show użytkowników akcja jest zakończona, renderuje plik.

Obecnie musisz zrobić coś w stylu:

def show
  @user = User.find( params[:id] )
  respond_to do |format|
    format.html
    format.json{
      render :json => @user.to_json
    }
  end
end

Ale byłoby miło, gdybyś mógł po prostu utworzyć plik show.json, który jest automatycznie renderowany w następujący sposób:

def show
  @user = User.find( params[:id] )
  respond_to do |format|
    format.html
    format.json
  end
end

Oszczędziłoby mi to mnóstwo smutku i zmyłoby to okropnie brudne uczucie, które odczuwam, gdy renderuję mój json w kontrolerze

Mateusz
źródło
Patrząc teraz na ten post, wygląda na to, że nie zaoszczędziłbym dużo, ale mam bardziej skomplikowane przypadki, zaufaj mi, kiedy powiem, że to powoduje u mnie bóle głowy
Matthew
1
W Railsach 3 możesz po prostu zadzwonić format.jsonz show.json.erbplikiem. Zobacz moją odpowiedź.
James Lim

Odpowiedzi:

64

W swoim respond_tobloku powinieneś być w stanie zrobić coś takiego :

respond_to do |format|
    format.json 
    render :partial => "users/show.json"
end

który wyrenderuje szablon w formacie app/views/users/_show.json.erb.

Alex Reisner
źródło
5
To dobrze, ale szybko przekonasz się, że erb to bolesny sposób generowania json. Sprawdź moją odpowiedź na kilka alternatyw.
tybro0103
1
Czy można to zrobić bez użycia częściowej?
Wylliam Judd
55

Spróbuj dodać widok users/show.json.erbPowinno to zostać wyrenderowane kiedy żądasz formatu JSON i uzyskasz dodatkową korzyść z renderowania go również przez erb, więc Twój plik może wyglądać mniej więcej tak

{
    "first_name": "<%= @user.first_name.to_json %>",
    "last_name": "<%= @user.last_name.to_json %>"
}
erik
źródło
9
Możesz użyć @user.first_name.to_jsonzamiast escape_javascript. Istnieje kilka subtelnych różnic między tym, co pozwala JS, a tym, co jest ściśle JSON. (I te różnice stają się ważne, gdy przeglądarki implementują własne parsery JSON.)
James A. Rosen
1
Prawdopodobnie powinieneś zmienić pojedyncze cudzysłowy na podwójne cudzysłowy, ponieważ JSON (w przeciwieństwie do JS) akceptuje tylko ciągi w podwójnych cudzysłowach.
Abe Voelker
1
To dobrze, ale szybko przekonasz się, że erb to bolesny sposób generowania json. Sprawdź moją odpowiedź na kilka alternatyw.
tybro0103
Wiem, że to stara odpowiedź, ale jest całkowicie błędna. to_json zwróci już sformatowany ciąg json „”, więc wynikowy json nigdy nie będzie prawidłowy z dodatkowymi cudzysłowami („” wartość ””). Ponadto, jeśli imię użytkownika ma wartość nil, wynikowy plik json będzie miał ciąg „null” jako wartość. Ponadto <% = używa funkcji ucieczki html, która zmienia znaki html w danych wejściowych.
d4n3
Myślę, że musisz również usunąć cudzysłowy, w <%= xyz.to_json %>przeciwnym razie zostaną ci dodatkowe cytaty.
akostadinov
32

Jak wspominali inni, potrzebujesz widoku users / show.json, ale istnieją opcje do rozważenia w przypadku języka szablonów ...

ERB

Działa po wyjęciu z pudełka. Świetne dla HTML, ale szybko przekonasz się, że jest okropne dla JSON.

RABL

Dobre rozwiązanie. Musisz dodać zależność i nauczyć się jej DSL.

JSON Builder

Taka sama oferta jak RABL: Dobre rozwiązanie. Muszę dodać zależność i nauczyć się jej DSL.

Zwykły rubin

Ruby jest niesamowity w generowaniu JSON i nie ma nic nowego do nauczenia się, ponieważ możesz wywołać to_jsonobiekt Hash lub AR. Po prostu zarejestruj rozszerzenie .rb dla szablonów (w inicjatorze):

ActionView::Template.register_template_handler(:rb, :source.to_proc)

Następnie utwórz widok users / show.json.rb:

@user.to_json

Więcej informacji na temat tego podejścia można znaleźć pod adresem http://railscasts.com/episodes/379-template-handlers

tybro0103
źródło
7
Zauważ, że w rails 4, program obsługi szablonu .ruby jest domyślnie zarejestrowany na github.com/rails/rails/commit/de1060f4e02925c12004f2, więc możesz pominąć rejestrację .rb i nazwać swój plik users / show.json.ruby.
Tim Diggins,
1
Ponadto, w celu dalszej aktualizacji, json_builder został zastąpiony przez github.com/rails/jbuilder .
Tim Diggins,
27

RABL jest prawdopodobnie najładniejszym rozwiązaniem tego problemu, jakie widziałem, jeśli szukasz czystszej alternatywy dla składni ERb. json_builder i argonaut, które są innymi rozwiązaniami, wydają się nieco przestarzałe i nie będą działać z Railsami 3.1 bez poprawek.

RABL jest dostępny za pośrednictwem perełki lub sprawdź repozytorium GitHub; dobre przykłady

https://github.com/nesquena/rabl

zapnap
źródło
21

Po prostu zaktualizuj tę odpowiedź ze względu na innych, którzy trafią na tę stronę.

W Railsach 3 wystarczy utworzyć plik pod adresem views/users/show.json.erb. @userObiekt będzie dostępny do widzenia (tak jak byłoby to dla html). Nie trzeba nawet to_jsonwięcej.

Podsumowując, po prostu

# users contoller
def show
  @user = User.find( params[:id] )
  respond_to do |format|
    format.html
    format.json
  end
end

i

/* views/users/show.json.erb */
{
    "name" : "<%= @user.name %>"
}
James Lim
źródło
1
Odpowiedziałem na to 1,5 roku temu. Obecnie po prostu używam respond_with, gdy potrzebuję JSON, np respond_with @user, only: [:name]. Więcej informacji znajdziesz w tym samouczku .
James Lim
1
Aby dodać do tej odpowiedzi, jest to faktycznie niebezpieczne z dwóch powodów: pozwala na wstrzyknięcie danych użytkownika, ponieważ nie zmienia znaków nowej linii i ukośników odwrotnych, a także <% = html ucieka z danych, więc np. Sean O'Connor będzie miał swoje imię zniekształcony do Seana O'Connora.
d4n3
10

Wystarczy dodać show.json.erbplik z zawartością

<%= @user.to_json %>

Czasami jest to przydatne, gdy potrzebujesz dodatkowych metod pomocniczych, które nie są dostępne w kontrolerze, np. image_path(@user.avatar)Lub czegoś do wygenerowania dodatkowych właściwości w JSON:

<%= @user.attributes.merge(:avatar => image_path(@user.avatar)).to_json %>
Priit
źródło
8
Musiałoby to być <%= raw(@user.to_json) %>unikanie ucieczki HTML. To, co robię, polega na tym, że polegam na to_json tak długo, jak długo daje mi to, czego chcę, ale kiedy chcę zrobić coś innego, szablon to za pomocą tego, co zwykle jest { :blah => @user.the_blah }.to_json.
clacke
0

Jestem nowy w RoR, oto co się dowiedziałem. możesz bezpośrednio renderować format json

def YOUR_METHOD_HERE
  users = User.all
  render json: {allUsers: users} # ! rendering all users
END
aRtoo
źródło