Rails: Bagaimana cara kerja blok response_to?

211

Saya akan melalui panduan Memulai dengan Rails dan bingung dengan bagian 6.7. Setelah membuat scaffold, saya menemukan blok yang dibuat secara otomatis berikut di controller saya:

def index
  @posts = Post.all

  respond_to do |format|
    format.html  # index.html.erb
    format.json  { render :json => @posts }
  end
end

Saya ingin memahami bagaimana sebenarnya blok response_to bekerja. Apa jenis variabel format? Apakah metode .html dan .json dari objek format? The dokumentasi untuk

ActionController::MimeResponds::ClassMethods::respond_to

tidak menjawab pertanyaan.

Cole
sumber
Akan lebih baik jika saya dapat menautkan ke dokumentasi untuk ActionController :: MimeResponds :: ClassMethods :: response_to tetapi api.rubyonrails.org tampaknya tidak menyukai hyperlink langsung ...
Cole
respond_to mengambil akhir panggilan (mis. blah.html, blah.json, dll) dan cocok dengan tampilan yang ditentukan. Respons lain dapat berupa XML, CSV, dan banyak lagi lainnya bergantung pada aplikasi.
ScottJShea
5
Bagaimana cara "cocok dengan tampilan yang ditentukan?"
Cole
Saya tidak berpikir ekstensi (xml, html, dll) memetakan ke tampilan. Jika Anda memilih render default ( format.html- tanpa argumen), ia akan menggunakan konvensi (berdasarkan URL dan kata kerja HTTP) untuk memilih tampilan (diharapkan berupa HTML). Responden (format) diperintahkan di sini untuk membuat URL yang diakhiri dengan .json dengan membuat serial menjadi json, alih - alih menggunakan tampilan dan konvensi.
Craig Celeste

Jawaban:

189

Saya baru di Ruby dan terjebak pada kode yang sama. Bagian yang saya tutupi sedikit lebih mendasar daripada beberapa jawaban yang saya temukan di sini. Ini mungkin atau mungkin tidak membantu seseorang.

  • respond_toadalah metode pada superclass ActionController.
  • dibutuhkan blok, yang seperti delegasi. Blok adalah dari dosampai end, dengan |format|sebagai argumen ke blok.
  • respond_to mengeksekusi blok Anda, dengan mengirimkan Responder ke dalam formatargumen.

http://api.rubyonrails.org/v4.1/classes/ActionController/Responder.html

  • The ResponderTIDAK mengandung sebuah metode untuk .htmlatau .json, tapi kita sebut metode ini lagian! Bagian ini membuatku luput.
  • Ruby memiliki fitur yang disebut method_missing. Jika Anda memanggil metode yang tidak ada (suka jsonatau html), Ruby memanggil method_missingmetode itu.

http://ruby-metaprogramming.rubylearning.com/html/ruby_metaprogramming_2.html

  • The Responderkelas menggunakan nya method_missingsebagai semacam pendaftaran. Saat kami memanggil 'json', kami mengatakannya untuk menanggapi permintaan dengan ekstensi .json dengan membuat serial ke json. Kita perlu menelepon htmltanpa argumen untuk mengatakannya untuk menangani permintaan .html dengan cara default (menggunakan konvensi dan tampilan).

Itu bisa ditulis seperti ini (menggunakan pseudocode mirip-JS):

// get an instance to a responder from the base class
var format = get_responder()

// register html to render in the default way
// (by way of the views and conventions)
format.register('html')

// register json as well. the argument to .json is the second
// argument to method_missing ('json' is the first), which contains
// optional ways to configure the response. In this case, serialize as json.
format.register('json', renderOptions)

Bagian ini membuatku bingung. Saya masih merasa itu tidak intuitif. Sepertinya Ruby menggunakan teknik ini sedikit. Seluruh kelas ( responder) menjadi implementasi metode. Untuk meningkatkan method_missing, kita membutuhkan turunan dari kelas, jadi kita wajib menyampaikan callback ke mana mereka melewati objek seperti metode. Untuk seseorang yang memiliki kode dalam bahasa seperti C selama 20 tahun, ini sangat terbelakang dan tidak intuitif bagi saya. Bukannya itu buruk! Tapi itu adalah sesuatu yang dibutuhkan banyak orang dengan latar belakang seperti itu, dan saya pikir mungkin itulah yang diinginkan OP.

ps perhatikan bahwa dalam RoR 4.2 respond_todiekstraksi menjadi permata responden .

Craig Celeste
sumber
Terima kasih Craig, tautan itu sebenarnya memiliki banyak informasi berguna juga, saya tidak menyadari seberapa banyak yang mungkin terjadi method_missing, mengingat Anda dapat memberikan argumen dan blok!
Aditya MP
2
Jawaban terbaik untuk menjelaskan penggunaan method_missing () sebagai mekanisme pendaftaran di kelas Responder! Saya juga sangat bingung dengan kode ini.
Alan Evangelista
1
Generator Rails 6 scaffold tampaknya menghasilkan kode dengan respond_todi controller, tanpa permata responden yang ada di Gemfile. Mungkin sedikit tentang respond_todiekstraksi ke dalam permata responden, telah diubah?
Qasim
106

Ini adalah blok kode Ruby yang memanfaatkan metode pembantu Rails. Jika Anda belum terbiasa dengan blok, Anda akan sering melihatnya di Ruby.

respond_toadalah metode pembantu Rails yang dilampirkan ke kelas Controller (atau lebih tepatnya, kelas supernya). Ini merujuk pada respons yang akan dikirim ke View (yang menuju ke browser).

Blok dalam contoh Anda memformat data - dengan mengirimkan parameter 'format' di blok - untuk dikirim dari controller ke tampilan setiap kali browser membuat permintaan untuk data html atau json.

Jika Anda menggunakan mesin lokal Anda dan mengatur Post scaffold Anda, Anda dapat pergi ke http://localhost:3000/postsdan Anda akan melihat semua posting Anda dalam format html. Tetapi, jika Anda mengetikkan ini:, http://localhost:3000/posts.jsonmaka Anda akan melihat semua posting Anda di objek json yang dikirim dari server.

Ini sangat berguna untuk membuat aplikasi javascript berat yang harus lulus json bolak-balik dari server. Jika Anda mau, Anda dapat dengan mudah membuat api json di pagar belakang, dan hanya melewati satu tampilan - seperti tampilan indeks pengontrol Post Anda. Kemudian Anda bisa menggunakan perpustakaan javascript seperti Jquery atau Backbone (atau keduanya) untuk memanipulasi data dan membuat antarmuka Anda sendiri. Ini disebut UI tidak sinkron dan mereka menjadi sangat populer (Gmail adalah satu). Mereka sangat cepat dan memberikan pengguna akhir pengalaman yang lebih seperti desktop di web. Tentu saja, ini hanyalah satu keuntungan dari memformat data Anda.

Cara penulisan Rails 3 ini adalah sebagai berikut:

    class PostsController < ApplicationController
      # GET /posts
      # GET /posts.xml


      respond_to :html, :xml, :json

      def index
        @posts = Post.all

        respond_with(@posts)
      end

#
# All your other REST methods
#

end

Dengan menempatkan respond_to :html, :xml, :jsondi bagian atas kelas, Anda dapat mendeklarasikan semua format yang Anda ingin controller Anda kirim ke pandangan Anda.

Kemudian, dalam metode pengontrol, yang harus Anda lakukan adalah response_with (@wh whatever_object_you_have)

Itu hanya menyederhanakan kode Anda sedikit lebih banyak daripada apa yang dihasilkan Rails secara otomatis.

Jika Anda ingin tahu tentang cara kerja bagian dalam ...

Dari apa yang saya mengerti, Rails mengintrospeksi objek untuk menentukan format apa yang sebenarnya akan terjadi. Nilai variabel 'format' didasarkan pada introspeksi ini. Rails dapat melakukan banyak hal dengan sedikit info. Anda akan terkejut melihat seberapa jauh posting sederhana atau: posting akan pergi.

Misalnya, jika saya memiliki file parsial _user.html.erb yang terlihat seperti ini:

_user.html.erb

<li>    
    <%= link_to user.name, user %>
</li>

Kemudian, ini saja dalam tampilan indeks saya akan membuat Rails tahu bahwa perlu menemukan parsial 'pengguna' dan beralih melalui semua objek 'pengguna':

index.html.erb

 <ul class="users">
   <%= render @users %>     
 </ul>

akan memberi tahu Rails bahwa diperlukan untuk menemukan parsial 'pengguna' dan beralih melalui semua objek 'pengguna':

Anda dapat menemukan posting blog ini berguna: http://archives.ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with

Anda juga dapat membaca dengan teliti sumbernya: https://github.com/rails/rails

PhillipKregg
sumber
1
Tip yang bagus di jalan rails3. Saya masih mencoba untuk sampai ke bagian bawah blok respond_to, dan apa argumen blok | format | dilewati.
Cole
4
Jawaban yang bagus tetapi tidak mengatakan sesuatu yang spesifik tentang variabel format yang diteruskan ke blok. Dalam contoh yang diberikan ada format.html dan format.json - apakah keduanya dilewatkan ke response_to dan kemudian respond_to memutuskan apa yang harus dilakukan dengan mereka?
Anthony
kapan respond_todan respond_withdiperkenalkan? Saya menggunakan rel 2.3.5 dan saya mulaiNoMethodError (undefined method respond_to)
abbood
10

Dari apa yang saya ketahui, respond_to adalah metode yang dilampirkan ke ActionController, sehingga Anda dapat menggunakannya di setiap pengontrol tunggal, karena semuanya mewarisi dari ActionController. Inilah metode Rail_spon_to:

def respond_to(&block)
  responder = Responder.new(self)
  block.call(responder)
  responder.respond
end

Anda melewatkannya satu blok , seperti yang saya perlihatkan di sini:

respond_to <<**BEGINNING OF THE BLOCK**>> do |format|
  format.html
  format.xml  { render :xml => @whatever }
end <<**END OF THE BLOCK**>>

The | Format | bagian adalah argumen yang diharapkan oleh blok, jadi di dalam metode response_to kita bisa menggunakannya. Bagaimana?

Nah, jika Anda perhatikan kami melewati blok dengan awalan & dalam metode response_to, dan kami melakukannya untuk memperlakukan blok itu sebagai Proc. Karena argumen memiliki ".xml", ".html" kita dapat menggunakannya sebagai metode untuk dipanggil.

Apa yang pada dasarnya kita lakukan di kelas respond_to adalah memanggil metode ".html, .xml, .json" ke instance dari kelas Responder.

Nobita
sumber
1
Sumber untuk response_to di api dokumen berbeda dari sumber yang Anda sertakan, dan membuat saya marah. Cuplikan Anda membuatnya lebih jelas bagi saya bahwa argumen blok format sedang diberikan objek Responder. Dokumentasi Responder tampaknya menjawab pertanyaan itu, membacanya sekarang.
Cole
7

Saya ingin memahami bagaimana sebenarnya blok response_to bekerja. Apa jenis variabel format? Apakah metode .html dan .json dari objek format?

Untuk memahami apa formatitu, Anda pertama-tama dapat melihat sumbernya respond_to, tetapi dengan cepat Anda akan menemukan bahwa yang benar-benar perlu Anda perhatikan adalah kode untuk recoverve_response_from_mimes .

Dari sini, Anda akan melihat bahwa blok yang diteruskan ke respond_to(dalam kode Anda), sebenarnya dipanggil dan diteruskan dengan instance Kolektor (yang di dalam blok dirujuk sebagai format). Kolektor pada dasarnya menghasilkan metode (saya percaya pada Rails start-up) berdasarkan apa yang diketahui tentang jenis kereta api mime .

Jadi, ya, .htmldan .jsonmetode didefinisikan (saat runtime) pada Collector (alias format) kelas.

rnicholson
sumber
2

Meta-pemrograman di balik pendaftaran responden (lihat jawaban Parched Squid) juga memungkinkan Anda melakukan hal-hal bagus seperti ini:

def index
  @posts = Post.all

  respond_to do |format|
    format.html  # index.html.erb
    format.json  { render :json => @posts }
    format.csv   { render :csv => @posts }
    format.js
  end
end

Baris csv akan menyebabkan to_csv dipanggil pada setiap posting ketika Anda mengunjungi /posts.csv. Ini memudahkan untuk mengekspor data sebagai CSV (atau format lain apa pun) dari situs rel Anda.

Baris js akan menyebabkan file javascript /posts.js (atau /posts.js.coffee) di-render / dieksekusi. Saya menemukan bahwa menjadi cara yang ringan untuk membuat situs yang diaktifkan Ajax menggunakan pop-up jQuery UI.

Catharz
sumber
1

Apa jenis variabel format?

Dari java POV, format merupakan implementasi dari antarmuka anonim. Antarmuka ini memiliki satu metode bernama untuk setiap jenis mime. Ketika Anda memanggil salah satu metode tersebut (melewatinya blok), maka jika rel merasa bahwa pengguna menginginkan tipe konten itu, maka itu akan memanggil blokir Anda.

Sentuhannya, tentu saja, adalah bahwa objek lem anonim ini tidak benar-benar mengimplementasikan antarmuka - ia menangkap metode panggilan secara dinamis dan berhasil jika namanya jenis pantomim yang diketahuinya.

Secara pribadi, saya pikir itu terlihat aneh: blok yang Anda lewati dieksekusi . Akan lebih masuk akal bagi saya untuk lulus dalam hash label format dan blok. Tapi - begitulah yang dilakukan dalam RoR, tampaknya.

PaulMurrayCbr
sumber
1

Ini agak ketinggalan jaman, oleh Ryan Bigg melakukan pekerjaan yang bagus menjelaskan ini di sini:

http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to

Bahkan, mungkin sedikit lebih detail daripada yang Anda cari. Ternyata, ada banyak hal yang terjadi di belakang layar, termasuk kebutuhan untuk memahami bagaimana tipe MIME dimuat.

idStar
sumber
0

"Format" adalah jenis respons Anda. Bisa json atau html, misalnya. Ini adalah format output yang akan diterima pengunjung Anda.

Rafael Nascimento
sumber
0

Ada satu hal lagi yang harus Anda waspadai - MIME.

Jika Anda perlu menggunakan tipe MIME dan tidak didukung secara default, Anda dapat mendaftarkan penangan Anda sendiri di config / initializers / mime_types.rb:

Mime::Type.register "text/markdown", :markdown


sumber