Rails Routing Helpers (เช่น mymodel_path (model)) สามารถใช้ในแบบจำลองได้หรือไม่?


368

บอกว่าฉันมี Rails Model ชื่อ Thing สิ่งที่มีแอตทริบิวต์ URL ที่สามารถเลือกที่จะกำหนดให้อยู่ที่ไหนสักแห่ง URL บนอินเทอร์เน็ต ในมุมมองรหัสฉันต้องการตรรกะที่ทำต่อไปนี้:

<% if thing.url.blank? %>
<%= link_to('Text', thing_path(thing)) %>
<% else %>
<%= link_to('Text', thing.url) %>
<% end %>

ตรรกะตามเงื่อนไขนี้ในมุมมองน่าเกลียด แน่นอนฉันสามารถสร้างฟังก์ชันผู้ช่วยซึ่งจะเปลี่ยนมุมมองเป็น:

<%= thing_link('Text', thing) %>

นั่นแก้ปัญหาการฟุ่มเฟื่อย แต่ฉันชอบที่จะมีฟังก์ชั่นการใช้งานในรูปแบบของตัวเอง ในกรณีนี้รหัสการดูจะเป็น:

<%= link_to('Text', thing.link) %>

เห็นได้ชัดว่านี่จะต้องมีวิธีการเชื่อมโยงในรูปแบบ นี่คือสิ่งที่จะต้องมี:

def link
  (self.url.blank?) ? thing_path(self) : self.url
end

ถึงจุดของคำถาม, thing_path () เป็นวิธีที่ไม่ได้กำหนดไว้ในรหัสรุ่น ฉันสมมติว่าเป็นไปได้ที่จะ "ดึง" วิธีการช่วยเหลือบางอย่างลงในโมเดล แต่อย่างไร มีเหตุผลจริงหรือไม่ที่การกำหนดเส้นทางทำงานที่คอนโทรลเลอร์และดูเลเยอร์ของแอปเท่านั้น? ฉันสามารถคิดถึงหลายกรณีที่รหัสรุ่นอาจต้องจัดการกับ URL (การรวมเข้ากับระบบภายนอก ฯลฯ )


กรณีที่ใช้จะเป็น: การสร้าง URL ย่อมาจาก goo.gl ใน aftersave,
lulalala

2
คุณควรจะตัดโมเดลของคุณในผู้นำเสนอหากคุณต้องการเพิ่มตรรกะการดูซึ่งจะทำให้เลเยอร์ MVC แยกออกจากกัน ดูที่ Draper ( github.com/jcasimir/draper )
กริช

2
โปรดดูส่วน "การสร้าง URL สำหรับเส้นทางที่กำหนดชื่อ" ในเอกสารประกอบที่api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html
Backo

คำตอบ:


698

ใน Rails 3, 4 และ 5 คุณสามารถใช้:

Rails.application.routes.url_helpers

เช่น

Rails.application.routes.url_helpers.posts_path
Rails.application.routes.url_helpers.posts_url(:host => "example.com")

14
Ypu สามารถรวมสิ่งนี้ไว้ในโมดูลใดก็ได้และหลังจากนั้นคุณก็สามารถเข้าถึง url-helpers ได้ ขอบคุณ
Viacheslav Molokov

41
ช่วยตัวเองจากการคัดลอก:hostตัวเลือกของคุณทุกที่และตั้งไว้เพียงครั้งเดียวในไฟล์กำหนดค่าสภาพแวดล้อมของคุณ:Rails.application.routes.default_url_options[:host] = 'localhost:3000'
แอนดรูว์

5
include Rails.application.routes.url_helpersใช้งานได้สำหรับฉันใน Rails 4.1
ม.ค.

1
หากคุณต้องการพา ธ ที่คุณสามารถใช้: only_path => true เป็นตัวเลือกโดยไม่ต้องผ่านพารามิเตอร์โฮสต์
trueinViso

1
นี่น่าจะเป็นตัวเลือกที่ดี: hawkins.io/2012/03/ …
Renars Sirotins

182

ฉันพบคำตอบเกี่ยวกับวิธีการทำสิ่งนี้ด้วยตนเอง ภายในโค้ดรุ่นเพียงแค่ใส่:

สำหรับ Rails <= 2:

include ActionController::UrlWriter

สำหรับ Rails 3:

include Rails.application.routes.url_helpers

สิ่งนี้ทำให้thing_path(self)คืน URL สำหรับสิ่งปัจจุบันอย่างน่าอัศจรรย์หรือother_model_path(self.association_to_other_model)คืน URL อื่น ๆ


27
เพียงแค่อัปเดตเนื่องจากข้อมูลด้านบนถูกคัดค้าน นี่คือปัจจุบันรวมถึง:include Rails.application.routes.url_helpers
yalestar

2
ฉันได้รับ NoMethodError (วิธีที่ไม่ได้กำหนด `optimization_routes_generation? 'สำหรับ # <ActionView :: ฐาน: 0x007fe8c0eecbd0>) เมื่อฉันลองทำสิ่งนี้
moger777

118

คุณอาจพบว่าวิธีการต่อไปนี้สะอาดกว่าการรวมทุกวิธี:

class Thing
  delegate :url_helpers, to: 'Rails.application.routes' 

  def url
    url_helpers.thing_path(self)
  end
end

7
เอกสารเกี่ยวกับเรื่องนี้ดูเหมือนจะหายากดังนั้นนี่คือลิงค์ที่ดีเกี่ยวกับการใช้ผู้รับมอบสิทธิ์ใน ActiveSupport simonecarletti.com/blog/2009/12/inside-ruby-on-rails-delegate
tlbrack

2
ฉันได้รับundefined local variable or method 'url_helpers' for Event:Classข้อผิดพลาด ... :(
Augustin Riedinger

undefined method url_helpersฉันได้รับ ฉันจะทำยังไงดี?
asiniy

@asiniy คุณแน่ใจหรือไม่ว่าคุณได้ใช้ตัวเลือกผู้แทนไปยัง url_helpers ที่เขียนหลังการประกาศคลาส
Krzysztof Witczak

ใช้งานไม่ได้ แต่อาจเป็นไปได้ว่าสิ่งนี้จะได้ผลก็ต่อเมื่อคุณสร้างขึ้นเองclassดังที่แสดงในคำตอบ หากคลาสรุ่นของคุณขยายออกไปแล้ว< ApplicationRecordจะไม่ทำงาน
skplunkerin

13

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

นี่คือสิ่งที่คุณสามารถทำได้:

# In the helper...

def link_to_thing(text, thing)
  (thing.url?) ? link_to(text, thing_path(thing)) : link_to(text, thing.url)
end

# In the view...

<%= link_to_thing("text", @thing) %>

1
สิ่งที่ฉันไม่ชอบเกี่ยวกับวิธีการของผู้ช่วยเหลือในกรณีนี้: เมื่อฉันดูที่ link_to_thing () ฉันต้องตัดสินใจว่าเป็นตัวช่วยที่เฉพาะเจาะจงหรือเป็นแอพพลิเคชั่นที่หลากหลาย (อาจเป็นได้อย่างง่ายดาย) ฉันต้องพิจารณาการตรวจสอบ 2 ไฟล์สำหรับแหล่งที่มา thing.link ไม่มีคำถามเกี่ยวกับไฟล์ต้นฉบับ
Aaron Longwell

นอกจากนี้ถ้าฉันจำเป็นต้องใช้ฟังก์ชั่นนี้ในภารกิจ Rake (เพื่อส่งออกไฟล์ CSV ของบางสิ่งบางอย่าง URL) ... ไปที่ตัวแบบโดยตรงจะดีกว่ามากในกรณีนี้เช่นกัน
Aaron Longwell

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

12
เมื่อ API ของเว็บเซอร์วิสเติบโตขึ้นบ่อยครั้งที่รุ่นต่างๆต้องติดต่อกับแหล่งข้อมูลภายนอกด้วยข้อมูลของตนเองและระบุ URL ที่เรียกกลับ ตัวอย่างเช่นวัตถุรูปถ่ายต้องโพสต์ตัวเองไปที่ Socialmod ซึ่งจะโทรกลับไปที่ URL ของรูปถ่ายนั้นเมื่อทำการกลั่นกรอง ตะขอ after_create () จะทำให้การโพสต์ใน Socialmod แต่คุณจะรู้ได้อย่างไรว่า URL โทรกลับ? ฉันคิดว่าคำตอบของผู้เขียนเองก็สมเหตุสมผลดี
JasonSmith

3
ในขณะที่คุณถูกต้องในด้านเทคนิคอย่างเข้มงวดมีบางครั้งที่ผู้คนต้องการสิ่งที่จะทำงานโดยไม่ต้องโกนจามรีทุกครั้งเพื่อหลีกเลี่ยงการละเมิดรูปแบบการออกแบบอันศักดิ์สิทธิ์หรือสิ่งที่มีคุณบางทีพวกเขาอาจต้องได้รับ url และเก็บจริง ในฐานข้อมูลจะมีประโยชน์สำหรับรุ่นที่จะรู้วิธีการทำแทนที่จะส่งสิ่งกลับไปกลับมาบางครั้งกฎอาจเสียหาย
nitecoder


1

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


4
Re: "ยกเว้นว่าแบบจำลองนั้นคืน URL เป็นข้อมูล" นั่นคือสิ่งที่เกิดขึ้นที่นี่ ... โมเดล "เป็นเจ้าของ" ข้อมูลนี้ซึ่งเป็นลิงก์ไปยัง URL ในเว็บไซต์หรือนอกสถานที่ ในบางกรณี URL จะถูกสร้างขึ้นจาก Rails Routing ในกรณีอื่น ๆ URL นั้นเป็นข้อมูลที่ผู้ใช้ระบุ
Aaron Longwell

0

(แก้ไข: ลืมจ้อก่อนหน้าของฉัน ... )

ตกลงอาจมีสถานการณ์ที่คุณจะไปที่แบบจำลองหรือไปที่ url อื่น ๆ ... แต่ฉันไม่คิดว่าสิ่งนี้จะเป็นของโมเดลมุมมอง (หรือบางทีแบบจำลอง) ฟังดูน่าเชื่อถือมากกว่า

เกี่ยวกับเส้นทางเท่าที่ฉันรู้เส้นทางสำหรับการกระทำในตัวควบคุม (ซึ่งมักจะ "วิเศษ" ใช้มุมมอง) ไม่ตรงกับมุมมอง คอนโทรลเลอร์ควรจัดการกับคำร้องขอทั้งหมดมุมมองควรแสดงผลลัพธ์และโมเดลควรจัดการข้อมูลและให้บริการกับมุมมองหรือตัวควบคุม ฉันได้ยินผู้คนมากมายที่นี่พูดคุยเกี่ยวกับเส้นทางไปยังแบบจำลอง (จนถึงจุดที่ฉันเกือบทั้งหมดจะเริ่มเชื่อ) แต่ตามที่ฉันเข้าใจแล้ว: เส้นทางไปยังตัวควบคุม แน่นอนว่าคอนโทรลเลอร์หลายตัวเป็นคอนโทรลเลอร์สำหรับหนึ่งรุ่นและมักจะถูกเรียก<modelname>sController(เช่น "UsersController" เป็นคอนโทรลเลอร์ของโมเดล "ผู้ใช้")

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


สมมติว่าคุณมีโมเดลรูปภาพ หากรูปภาพมี URL ภายนอกที่เชื่อมโยงอยู่ให้ชี้ไปที่ URL นั้น มิฉะนั้นให้ชี้ไปที่หน้าแสดงภาพเพื่ออัพโหลดภาพ? แค่ความคิด
Josh Delsman

ตัวอย่างทั่วไปที่น้อยกว่านี้คือ link_to "ภาพขนาดเต็ม", image.link วิธีการเชื่อมโยงในแบบจำลองอาจลิงก์ไปยัง URL ในเว็บไซต์ (image_path) หรือเพื่อพูดเป็น URL Flickr หากผู้ใช้ให้ . url ตั้งอยู่บนภาพ
Aaron Longwell
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.