Model Rails, View, Controller, dan Helper: apa yang terjadi di mana?

155

Dalam Ruby on Rails Development (atau MVC secara umum), aturan cepat apa yang harus saya ikuti untuk kemana menempatkan logika.

Harap jawab di afirmatif - Dengan Jangan taruh ini di sini , daripada Jangan taruh di sana .

theschmitzer
sumber

Jawaban:

173

MVC

Pengontrol : Letakkan kode di sini yang berkaitan dengan mencari tahu apa yang diinginkan pengguna, dan memutuskan apa yang akan diberikan kepada mereka, menentukan apakah mereka masuk, apakah mereka harus melihat data tertentu, dll. Pada akhirnya, pengontrol melihat permintaan dan mengerjakan data apa (Model) untuk ditampilkan dan Tampilan apa yang harus disajikan. Jika Anda ragu tentang apakah kode harus masuk dalam controller, maka mungkin tidak seharusnya. Jaga pengendali Anda tetap kurus .

Tampilan : Tampilan harus hanya berisi kode minimum untuk menampilkan data Anda (Model), seharusnya tidak melakukan banyak pemrosesan atau perhitungan, itu harus menampilkan data yang dihitung (atau dirangkum) oleh Model, atau dihasilkan dari Controller. Jika Tampilan Anda benar-benar perlu melakukan pemrosesan yang tidak dapat dilakukan oleh Model atau Pengendali, masukkan kode dalam Helper. Banyak kode Ruby dalam Tampilan membuat markup halaman sulit dibaca.

Model : Model Anda harus di mana semua kode Anda yang terkait dengan data Anda (entitas yang membentuk situs Anda misalnya Pengguna, Posting, Akun, Teman dll) tinggal. Jika kode perlu menyimpan, memperbarui, atau merangkum data yang terkait dengan entitas Anda, taruh di sini. Ini akan dapat digunakan kembali di Tampilan dan Pengontrol Anda.

pauliephonic
sumber
2
Orang-orang mulai menjauh dari model gemuk. Saya suka menganggap model saya sebagai struktur data. Lalu saya menulis beberapa objek Ruby yang mengimplementasikan perilaku, menginisialisasi dengan model (itu memperlakukan model sebagai data dengan cara yang sama Anda dapat memperlakukan string dan array sebagai data dalam objek di luar Rails). Berikut video yang bagus dengan contoh teknik ini.
Joshua Cheek
@AdamDonahue Saya tidak yakin apa pun yang gemuk bisa dilihat sebagai hal yang baik. Banyak tanggung jawab lebih baik dimiliki dalam layanan.
fatuhoku
35

Untuk menambah jawaban pauliephonic:

Helper : berfungsi untuk membuat membuat tampilan lebih mudah. Misalnya, jika Anda selalu mengulangi daftar widget untuk menampilkan harganya, masukkan ke dalam helper (bersama dengan sebagian untuk tampilan aktual). Atau jika Anda memiliki sepotong RJS yang Anda tidak ingin mengacaukan tampilan, masukkan ke dalam helper.

jcoby
sumber
Sebenarnya bukankah kita juga memasukkan metode sign_in di Helper? Seperti yang disarankan oleh Tutorial RoR di sini >>> ruby.railstutorial.org/book/…
Ivan Wang
14

Pola MVC benar-benar hanya peduli dengan UI dan tidak ada yang lain. Anda tidak boleh memasukkan logika bisnis yang rumit ke dalam pengontrol karena pengontrol mengontrol tampilan tetapi bukan logika. Pengontrol harus memperhatikan dirinya sendiri dengan memilih tampilan yang tepat dan mendelegasikan hal-hal yang lebih kompleks ke model domain (Model) atau lapisan bisnis.

Domain Driven Design memiliki konsep Layanan yang merupakan tempat Anda menempelkan logika yang perlu mengatur sejumlah jenis objek yang umumnya berarti logika yang tidak secara alami termasuk dalam kelas Model.

Saya biasanya menganggap lapisan Layanan sebagai API dari aplikasi saya. Lapisan Layanan saya biasanya memetakan cukup dekat dengan persyaratan aplikasi yang saya buat sehingga lapisan Layanan bertindak sebagai penyederhanaan dari interaksi yang lebih kompleks yang ditemukan di tingkat yang lebih rendah dari aplikasi saya, yaitu Anda dapat mencapai tujuan yang sama dengan melewati lapisan Layanan tetapi Anda harus menarik lebih banyak tuas untuk membuatnya bekerja.

Perhatikan bahwa saya tidak berbicara tentang Rails di sini saya berbicara tentang gaya arsitektur umum yang membahas masalah khusus Anda.

Søren Ejaan Lund
sumber
Ini adalah jawaban yang bagus :)
Carlos Martinez
12

Penjelasan sempurna di sini sudah, satu kalimat yang sangat sederhana sebagai kesimpulan dan mudah diingat:

Kami membutuhkan Model SMART, Pengontrol TIPIS, dan Tampilan DUMB.

http://c2.com/cgi/wiki?ModelViewController

kode maddin2
sumber
7

Jangan letakkan hal-hal yang terkait dengan otorisasi / kontrol akses di controller.

Semua model tentang data Anda. Validasi, Hubungan, CRUD, Logika Bisnis

Tampilan adalah tentang menunjukkan data Anda. Tampilkan dan dapatkan input saja.

Pengontrol adalah tentang mengendalikan data apa yang berjalan dari model Anda ke tampilan Anda (dan tampilan mana) dan dari tampilan Anda ke model Anda. Pengontrol juga dapat ada tanpa model.

Saya suka menganggap controller sebagai penjaga keamanan / resepsionis yang mengarahkan Anda pelanggan (permintaan) ke konter yang sesuai di mana Anda mengajukan kasir (melihat) pertanyaan. Teller (tampilan) kemudian pergi dan mendapatkan jawaban dari seorang manajer (model), yang tidak pernah Anda lihat. Anda permintaan kemudian kembali ke satpam / resepsionis (pengontrol) dan menunggu sampai Anda diarahkan untuk pergi teller lain (tampilan) yang memberi tahu Anda jawaban manajer (model) mengatakan kepada mereka dalam menanggapi pertanyaan (view) teller lain .

Demikian juga jika Anda ingin memberi tahu teller (melihat) sesuatu maka sebagian besar hal yang sama terjadi kecuali teller kedua akan memberi tahu Anda apakah manajer menerima informasi Anda. Mungkin juga penjaga keamanan / resepsionis (pengontrol) mungkin telah memberi tahu Anda untuk mendaki karena Anda tidak berwenang memberi tahu informasi itu kepada manajer.

Jadi untuk memperluas metafora, dalam dunia stereotip dan tidak realistis saya, teller (pandangan) cantik tapi berkepala kosong dan sering percaya apa pun yang Anda katakan, penjaga keamanan / resepsionis minimal sopan tetapi tidak terlalu berpengetahuan tetapi mereka tahu di mana orang harus dan tidak boleh pergi dan manajer benar-benar jelek dan kejam, tetapi tahu segalanya dan bisa mengatakan apa yang benar dan apa yang tidak.

srboisvert
sumber
4

Satu hal yang membantu memisahkan dengan benar adalah menghindari "lewati variabel lokal dari pengontrol untuk melihat" anti-pola. Alih-alih ini:

# app/controllers/foos_controller.rb:
class FoosController < ApplicationController

  def show
    @foo = Foo.find(...)
  end

end

#app/views/foos/show.html.erb:
...
<%= @foo.bar %>
...

Coba pindahkan ke pengambil yang tersedia sebagai metode pembantu:

# app/controllers/foos_controller.rb:
class FoosController < ApplicationController

  helper_method :foo

  def show
  end

  protected

  def foo
    @foo ||= Foo.find(...)
  end

end

#app/views/foos/show.html.erb:
...
<%= foo.bar %>
...

Ini membuatnya lebih mudah untuk memodifikasi apa yang dimasukkan ke dalam "@foo" dan bagaimana menggunakannya. Ini meningkatkan pemisahan antara pengontrol dan tampilan tanpa membuatnya lebih rumit.

James A. Rosen
sumber
uhmmm ... Yuk. Bisakah Anda menambahkan beberapa alasan / skenario untuk kapan Anda akan melakukan ini? Ini menghancurkan KISS dan YAGNI dan sangat bau (hanya untuk melemparkan satu klise lagi)
Sixty4Bit
2
1) Rails melakukan banyak keajaiban untuk menyalin variabel instance pengontrol ke instance tampilan Anda. 2) Implementasi yang disarankan juga hanya memuat foo jika diakses, yang mungkin menghemat pekerjaan beberapa waktu. Jawaban penting sebenarnya adalah 1).
webmat
11
Sigh Ini mengerikan. Pembagian variabel instance rel adalah fitur bukan anti-pola. Ini adalah gula sintaksis rendah-mental-overhead di mana-mana yang jarang jika pernah menyebabkan masalah dunia nyata. Jika Anda tidak menyukainya, baiklah, tetapi mengkodekannya dengan struktur non-standar barok membuat segalanya menjadi lebih buruk. Dalam hal ini Anda secara efektif membuat foo variabel global (tetap saja per kontroler). Mencoba untuk memperbaiki penyalahgunaan ruang variabel yang dirasakan dengan secara dramatis meningkatkan cakupannya sangat ironis.
gtd
1
Saya tidak membelinya, dasil003. Lingkup foodan dari @fooadalah sama - keduanya tercakup dalam pasangan <ControllerClass, request>. Selain itu, dengan menggunakan versi getter, saya bisa mengubah cara Fooobjek itu ditemukan / disimpan / di-cache tanpa mengubah cara tampilan mengaksesnya.
James A. Rosen
1
Saya pikir maksud Anda "lulus variabel instan" anti-pola. Sebuah instance var akan membocorkan status untuk seluruh render, bahkan dalam parsial yang bersarang. Solusi Anda juga bocor, tetapi sedikit lebih baik daripada instance var karena tidak memungkinkan penugasan kembali. Melewati lokal sebenarnya yang terbaik karena itu seperti memanggil metode; lokal tidak dapat dilihat secara parsial. Lihat jawaban ini .
Kelvin
2

Yah, itu semacam tergantung pada apa yang harus berurusan dengan logika ...

Seringkali, masuk akal untuk mendorong lebih banyak hal ke dalam model Anda, meninggalkan pengendali kecil. Ini memastikan bahwa logika ini dapat dengan mudah digunakan dari mana saja Anda perlu mengakses data yang diwakili oleh model Anda. Tampilan harus mengandung hampir tidak ada logika. Jadi sungguh, secara umum, Anda harus berusaha untuk membuatnya sehingga Anda Tidak Mengulangi Diri Anda Sendiri.

Juga, sedikit google cepat mengungkapkan beberapa contoh nyata dari apa yang terjadi di mana.

Model: persyaratan validasi, hubungan data, membuat metode, memperbarui metode, menghancurkan metode, menemukan metode (perhatikan bahwa Anda seharusnya tidak hanya memiliki versi generik dari metode ini, tetapi jika ada banyak hal yang Anda lakukan, seperti menemukan orang dengan warna merah rambut dengan nama belakang, maka Anda harus mengekstrak logika itu sehingga yang harus Anda lakukan adalah memanggil find_redH_by_name ("smith") atau sesuatu seperti itu)

Tampilan: Ini harusnya semua tentang pemformatan data, bukan pemrosesan data.

Pengendali: Di ​​sinilah pemrosesan data berjalan. Dari internet: "Tujuan pengontrol adalah untuk menanggapi tindakan yang diminta oleh pengguna, mengambil parameter apa pun yang telah ditetapkan pengguna, memproses data, berinteraksi dengan model, dan kemudian meneruskan data yang diminta, dalam bentuk akhir, ke melihat."

Semoga itu bisa membantu.

Paul Wicks
sumber
0

Dalam istilah sederhana, umumnya, Model akan memiliki semua kode yang terkait dengan tabel, hubungan sederhana atau kompleksnya (menganggapnya sebagai kueri sql yang melibatkan banyak tabel), manipulasi data / variabel untuk sampai pada hasil menggunakan logika bisnis .

Pengendali akan memiliki kode / petunjuk ke model yang relevan untuk pekerjaan yang diminta.

Tampilan akan menerima input / interaksi pengguna dan menampilkan respons yang dihasilkan.

Setiap penyimpangan besar dari ini akan membuat ketegangan yang tidak diinginkan pada bagian itu dan kinerja aplikasi secara keseluruhan dapat terpengaruh.

Anutosh
sumber
-1

Pengujian, Pengujian ... Masukkan logika sebanyak mungkin dalam model dan kemudian Anda akan dapat mengujinya dengan benar. Tes unit menguji data dan cara itu dibentuk dengan menguji model, dan tes fungsional menguji cara itu diarahkan atau dikendalikan dengan menguji pengendali, sehingga Anda tidak dapat menguji integritas data kecuali jika ada di model.

j


sumber