Rails Model, View, Controller และ Helper: เกิดอะไรขึ้น?


155

ใน Ruby on Rails Development (หรือ MVC โดยทั่วไป) ฉันควรทำตามกฎอย่างรวดเร็วว่าจะวางตรรกะไว้ที่ใด

กรุณาตอบด้วยการยืนยัน - ด้วยอย่าใส่สิ่งนี้ไว้ที่นี่แทนที่จะทำอย่างนั้น

คำตอบ:


173

MVC

ตัวควบคุม : ใส่รหัสที่นี่ซึ่งเกี่ยวข้องกับการทำงานตามที่ผู้ใช้ต้องการและตัดสินใจว่าจะให้พวกเขาทำงานอย่างไรไม่ว่าพวกเขาจะเข้าสู่ระบบไม่ว่าพวกเขาควรจะเห็นข้อมูลบางอย่าง ฯลฯ ในท้ายที่สุดตัวควบคุมจะดูคำขอ และทำงานหาข้อมูล (รุ่น) ที่จะแสดงและมุมมองที่จะแสดงผล หากคุณมีข้อสงสัยเกี่ยวกับว่ารหัสควรไปในตัวควบคุมแล้วมันอาจไม่ควร ให้ควบคุมของคุณผอม

มุมมอง : มุมมองควรมีรหัสขั้นต่ำเท่านั้นเพื่อแสดงข้อมูลของคุณ (รุ่น) ซึ่งไม่ควรทำการประมวลผลหรือคำนวณจำนวนมาก แต่ควรแสดงข้อมูลที่ถูกคำนวณ (หรือสรุป) โดยตัวแบบหรือสร้างจากคอนโทรลเลอร์ ถ้ามุมมองของคุณจำเป็นต้องทำการประมวลผลที่ไม่สามารถทำได้โดยตัวแบบหรือตัวควบคุมให้ใส่รหัสในตัวช่วย โค้ด Ruby จำนวนมากในมุมมองทำให้มาร์กอัปอ่านยาก

รุ่น : โมเดลของคุณควรเป็นที่ที่รหัสทั้งหมดของคุณเกี่ยวข้องกับข้อมูลของคุณ (เอนทิตีที่สร้างเว็บไซต์ของคุณเช่นผู้ใช้โพสต์บัญชีเพื่อน ฯลฯ ) อาศัยอยู่ หากรหัสต้องการบันทึกอัปเดตหรือสรุปข้อมูลที่เกี่ยวข้องกับเอนทิตีของคุณให้ใส่ที่นี่ มันจะสามารถใช้งานได้อีกครั้งในมุมมองและตัวควบคุมของคุณ


2
ผู้คนเริ่มเคลื่อนตัวออกจากรูปแบบไขมัน ฉันชอบคิดว่าแบบจำลองของฉันเป็นโครงสร้างข้อมูล จากนั้นฉันเขียนวัตถุ Ruby บางอย่างที่ใช้ลักษณะการทำงานเริ่มต้นด้วยแบบจำลอง (มันปฏิบัติต่อโมเดลเนื่องจากเป็นข้อมูลในแบบเดียวกับที่คุณอาจใช้กับสตริงและอาร์เรย์เป็นข้อมูลในวัตถุนอก Rails) นี่เป็นวิดีโอที่ดีพร้อมตัวอย่างของเทคนิคนี้
Joshua Cheek

@AdamDonahue ฉันไม่แน่ใจว่าสิ่งที่อ้วนสามารถมองเห็นเป็นสิ่งที่ดี ตันของความรับผิดชอบดีกว่าอยู่ในบริการ
fatuhoku

35

วิธีเพิ่มคำตอบของ pauliephonic:

ตัวช่วย : ฟังก์ชั่นเพื่อทำให้การสร้างมุมมองง่ายขึ้น ตัวอย่างเช่นหากคุณวนซ้ำรายการวิดเจ็ตเพื่อแสดงราคาของพวกเขาให้วางไว้ในตัวช่วย (พร้อมด้วยบางส่วนสำหรับการแสดงผลจริง) หรือถ้าคุณมีชิ้นส่วนของ RJS ที่คุณไม่ต้องการให้มุมมองวุ่นวายให้ใส่มันเข้าไปในตัวช่วย


ที่จริงแล้วเราไม่ได้ใส่วิธี sign_in ใน Helper? ตามแบบฝึกหัด RoR แนะนำที่นี่ >>> ruby.railstutorial.org/book/…
Ivan Wang

14

รูปแบบ MVC เกี่ยวข้องกับ UI จริง ๆ เท่านั้น คุณไม่ควรใส่ตรรกะทางธุรกิจที่ซับซ้อนลงในคอนโทรลเลอร์เพราะมันจะควบคุมมุมมอง แต่ไม่ใช่ตรรกะ ผู้ควบคุมควรคำนึงถึงตัวเองด้วยการเลือกมุมมองที่เหมาะสมและมอบหมายสิ่งที่ซับซ้อนมากขึ้นให้กับรูปแบบโดเมน (Model) หรือชั้นธุรกิจ

การออกแบบโดเมนขับเคลื่อนมีแนวคิดของบริการซึ่งเป็นสถานที่ที่คุณติดตรรกะซึ่งจำเป็นต้องจัดวางวัตถุประเภทต่าง ๆ จำนวนมากซึ่งโดยทั่วไปหมายถึงตรรกะที่ไม่ได้อยู่ในชั้นเรียนแบบตามธรรมชาติ

โดยทั่วไปฉันคิดว่า Service layer เป็น API ของแอปพลิเคชันของฉัน เลเยอร์บริการของฉันมักจะจับคู่กับความต้องการของแอปพลิเคชันที่ฉันสร้างอย่างใกล้ชิดดังนั้นเลเยอร์บริการทำหน้าที่ทำให้การโต้ตอบที่ซับซ้อนมากขึ้นง่ายขึ้นซึ่งพบได้ในระดับล่างของแอปของฉันนั่นคือคุณสามารถบรรลุเป้าหมายเดียวกันได้ แต่คุณต้องดึงคันโยกให้มากขึ้นเพื่อให้ทำงานได้

โปรดทราบว่าฉันไม่ได้พูดถึง Rails ที่นี่ฉันกำลังพูดถึงรูปแบบสถาปัตยกรรมทั่วไปที่จัดการปัญหาเฉพาะของคุณ


นี่เป็นคำตอบที่ยอดเยี่ยม :)
Carlos Martinez

12

คำอธิบายที่สมบูรณ์แบบอยู่ที่นี่แล้วประโยคที่เรียบง่ายหนึ่งประโยคเป็นบทสรุปและจดจำได้ง่าย:

เราต้องการรุ่น SMART, THIN Controllers และ DUMB Views

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



7

ใส่สิ่งที่เกี่ยวข้องกับการอนุญาต / ควบคุมการเข้าถึงในคอนโทรลเลอร์

แบบจำลองทั้งหมดเกี่ยวกับข้อมูลของคุณ การตรวจสอบความสัมพันธ์, CRUD, ตรรกะทางธุรกิจ

จำนวนการดูเป็นเรื่องเกี่ยวกับการแสดงข้อมูลของคุณ แสดงและรับอินพุตเท่านั้น

ตัวควบคุมกำลังเกี่ยวกับการควบคุมข้อมูลที่จะไปจากแบบจำลองของคุณไปยังมุมมองของคุณ (และมุมมองใด) และจากมุมมองของคุณไปยังแบบจำลองของคุณ ตัวควบคุมสามารถอยู่ได้โดยไม่มีรุ่น

ฉันชอบคิดว่าตัวควบคุมเป็นพนักงานรักษาความปลอดภัย / พนักงานต้อนรับที่นำลูกค้าของคุณ (ขอ) ไปที่เคาน์เตอร์ที่เหมาะสมที่คุณถามคำถามพนักงานขาย (ดู) พนักงานฝากเงิน (ดู) จากนั้นไปและรับคำตอบจากผู้จัดการ (รุ่น) ที่คุณไม่เคยเห็น คุณร้องขอจากนั้นกลับไปที่พนักงานรักษาความปลอดภัย / พนักงานต้อนรับ (ตัวควบคุม) และรอจนกว่าคุณจะถูกนำไปบอกพนักงานคนอื่น (ดู) ที่บอกคำตอบกับผู้จัดการ (รุ่น) บอกพวกเขาในการตอบคำถามของคนอื่น (มุมมอง) .

ในทำนองเดียวกันหากคุณต้องการบอกพนักงาน (ดู) บางสิ่งบางอย่างส่วนใหญ่แล้วสิ่งเดียวกันจะเกิดขึ้นยกเว้นพนักงานที่สองจะบอกคุณว่าผู้จัดการยอมรับข้อมูลของคุณหรือไม่ อาจเป็นไปได้ว่าเจ้าหน้าที่รักษาความปลอดภัย / พนักงานต้อนรับ (ตัวควบคุม) อาจบอกให้คุณเดินขึ้นเขาเนื่องจากคุณไม่ได้รับอนุญาตให้แจ้งข้อมูลดังกล่าวกับผู้จัดการ

ดังนั้นเพื่อขยายคำอุปมาในโลกที่ตายตัวและไม่สมจริงของฉันผู้บอกเล่า (มุมมอง) นั้นสวย แต่ไร้สมองและมักจะเชื่อสิ่งที่คุณบอกพวกเขาเจ้าหน้าที่รักษาความปลอดภัย / พนักงานต้อนรับนั้นสุภาพเล็กน้อย แต่ไม่ค่อยมีความรู้มากนัก ไม่ควรไปและผู้จัดการน่าเกลียดจริง ๆ และมีความหมาย แต่รู้ทุกอย่างและสามารถบอกได้ว่าอะไรจริงและอะไร


4

สิ่งหนึ่งที่ช่วยแยกอย่างถูกต้องคือการหลีกเลี่ยง "รูปแบบการส่งผ่านตัวแปรในท้องถิ่นจากตัวควบคุมเพื่อดู" แทนสิ่งนี้:

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

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

end

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

ลองย้ายไปที่ทะเยอทะยานที่มีอยู่ในวิธีการช่วยเหลือ:

# 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 %>
...

สิ่งนี้ทำให้ง่ายต่อการปรับเปลี่ยนสิ่งที่ได้รับใน "@foo" และวิธีการใช้งาน มันเพิ่มการแยกระหว่างตัวควบคุมและมุมมองโดยไม่ทำให้ซับซ้อนมากขึ้น


อืมมม ... คุณช่วยเพิ่มเหตุผล / สถานการณ์ดีๆสำหรับตอนที่คุณทำสิ่งนี้ได้ไหม สิ่งนี้ทำให้ KISS และ YAGNI แตกและมีกลิ่นเหม็นมาก (เพียงแค่โยนอีกหนึ่งถ้อยคำที่เบื่อหู)
Sixty4Bit

2
1) Rails ใช้เวทมนตร์มากมายในการคัดลอกตัวแปรอินสแตนซ์ของคอนโทรลเลอร์ไปยังอินสแตนซ์มุมมองของคุณ 2) การนำไปปฏิบัติที่แนะนำนั้นจะโหลดเพียง foo เท่านั้นหากมีการเข้าถึงซึ่งอาจบันทึกงานบางเวลา คำตอบที่สำคัญคือ 1)
webmat

11
เฮ้อนี่มันแย่มาก การแชร์ตัวแปรอินสแตนซ์ Rails เป็นคุณสมบัติที่ไม่ใช่รูปแบบการต่อต้าน เป็นน้ำตาลซินแทคติกที่พบได้ทั่วไปและมีค่าใช้จ่ายต่ำซึ่งไม่ค่อยเกิดขึ้นหากมีปัญหาในโลกแห่งความเป็นจริง ถ้าคุณไม่ชอบมันก็ดี แต่การเขียนโค้ดรอบ ๆ ด้วยโครงสร้างที่ไม่ได้มาตรฐานแบบบาโรกทำให้สิ่งเลวร้ายลงอย่างไม่สิ้นสุด ในกรณีนี้คุณทำให้ foo เป็นตัวแปรโกลบอล (ต่อคอนโทรลเลอร์) ความพยายามที่จะแก้ไขการล่วงละเมิดขอบเขตการรับรู้ของตัวแปรโดยการเพิ่มขอบเขตอย่างมากนั้นน่าขันมาก
gtd

1
ฉันไม่ได้ซื้อมัน dasil003 ขอบเขตfooและจาก@fooนั้นเหมือนกัน - ทั้งคู่ถูกกำหนดขอบเขตไว้ที่คู่ <ControllerClass, request> นอกจากนี้โดยใช้เวอร์ชัน getter ฉันสามารถเปลี่ยนวิธีการFooค้นหา / จัดเก็บ / แคชของวัตถุโดยไม่เปลี่ยนวิธีการที่มุมมองเข้าถึง
James A. Rosen

1
ฉันคิดว่าคุณหมายถึงรูปแบบการต่อต้าน "ตัวแปรอินสแตนซ์" อินสแตนซ์ var จะทำให้สถานะการรั่วไหลสำหรับการเรนเดอร์ทั้งหมดแม้จะอยู่ในส่วนที่ซ้อนกันอย่างลึก โซลูชันของคุณมีสถานะรั่วไหล แต่ก็ยังดีกว่า var แบบอินสแตนซ์เล็กน้อยเนื่องจากไม่อนุญาตให้โอนย้ายอีกครั้ง การผ่านท้องถิ่นนั้นดีที่สุดเพราะมันเหมือนการเรียกวิธีการ ไม่สามารถเห็นคนท้องถิ่นได้ ดูคำตอบนี้
เคลวิน

2

ทีนี้มันขึ้นอยู่กับว่าตรรกะนั้นเกี่ยวข้องกับอะไร ...

บ่อยครั้งทำให้รู้สึกถึงการผลักสิ่งต่าง ๆ เข้ามาในแบบจำลองของคุณมากขึ้นทำให้ตัวควบคุมเล็กลง สิ่งนี้ทำให้มั่นใจได้ว่าตรรกะนี้สามารถใช้ได้อย่างง่ายดายจากทุกที่ที่คุณต้องการเข้าถึงข้อมูลที่โมเดลของคุณเป็นตัวแทน มุมมองไม่ควรมีตรรกะ โดยทั่วไปจริงๆแล้วคุณควรพยายามทำเพื่อที่คุณจะได้ไม่ทำซ้ำตัวเอง

นอกจากนี้ google จำนวนเล็กน้อยยังแสดงตัวอย่างที่ชัดเจนของสิ่งที่เกิดขึ้น

รุ่น: ข้อกำหนดในการตรวจสอบความสัมพันธ์ของข้อมูลวิธีการสร้างวิธีการอัปเดตวิธีทำลายวิธีค้นหา (โปรดทราบว่าคุณไม่ควรมีเพียงวิธีทั่วไปในรุ่นนี้ แต่ถ้ามีบางสิ่งที่คุณกำลังทำอยู่เช่นการค้นหาคนที่มีสีแดง เส้นผมตามนามสกุลจากนั้นคุณควรแยกตรรกะนั้นเพื่อให้สิ่งที่คุณต้องทำคือโทรหา find_redH_by_name ("smith") หรืออะไรทำนองนั้น)

มุมมอง: สิ่งนี้ควรเกี่ยวกับการจัดรูปแบบข้อมูลไม่ใช่การประมวลผลข้อมูล

ตัวควบคุม: นี่คือที่การประมวลผลข้อมูลไป จากอินเทอร์เน็ต: "วัตถุประสงค์ของคอนโทรลเลอร์คือเพื่อตอบสนองต่อการกระทำที่ผู้ใช้ร้องขอใช้พารามิเตอร์ใด ๆ ที่ผู้ใช้ตั้งค่าประมวลผลข้อมูลโต้ตอบกับรุ่นแล้วส่งข้อมูลที่ร้องขอในรูปแบบสุดท้ายออกไป ดู."

หวังว่าจะช่วย


0

กล่าวโดยทั่วไปแล้ว แบบจำลองจะมีรหัสทั้งหมดที่เกี่ยวข้องกับตารางความสัมพันธ์ที่เรียบง่ายหรือซับซ้อน (คิดว่าพวกเขาเป็นแบบสอบถาม SQL ที่เกี่ยวข้องกับหลายตาราง) การจัดการข้อมูล / ตัวแปรเพื่อให้ได้ผลลัพธ์โดยใช้ตรรกะทางธุรกิจ .

ตัวควบคุมจะมีรหัส / ตัวชี้ไปยังโมเดลที่เกี่ยวข้องสำหรับงานที่ร้องขอ

มุมมองจะยอมรับอินพุต / การโต้ตอบของผู้ใช้และแสดงการตอบสนองผลลัพธ์

การเบี่ยงเบนที่สำคัญจากสิ่งเหล่านี้จะสร้างความเครียดที่ไม่พึงประสงค์ในส่วนนั้นและประสิทธิภาพโดยรวมของแอปพลิเคชันอาจได้รับผลกระทบ


-1

การทดสอบการทดสอบ ... ใส่ตรรกะให้มากที่สุดเท่าที่จะทำได้ในโมเดลจากนั้นคุณจะสามารถทดสอบได้อย่างถูกต้อง การทดสอบหน่วยทดสอบข้อมูลและวิธีการสร้างโดยการทดสอบแบบจำลองและการทดสอบการทำงานทดสอบวิธีการกำหนดเส้นทางหรือควบคุมโดยการทดสอบตัวควบคุมดังนั้นจึงเป็นไปตามที่คุณไม่สามารถทดสอบความสมบูรณ์ของข้อมูลเว้นแต่จะอยู่ใน นางแบบ.

J

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.