Có thể sử dụng Trình trợ giúp định tuyến Rails (ví dụ mymodel_path (kiểu máy) trong Mô hình không?


368

Nói rằng tôi có một mô hình Rails được gọi là Thing. Điều có một thuộc tính url có thể tùy ý được đặt thành một URL ở đâu đó trên Internet. Trong mã xem, tôi cần logic thực hiện như sau:

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

Logic có điều kiện này trong quan điểm là xấu xí. Tất nhiên, tôi có thể xây dựng một hàm trợ giúp, điều này sẽ thay đổi khung nhìn này:

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

Điều đó giải quyết vấn đề dài dòng, nhưng tôi thực sự muốn có chức năng trong chính mô hình. Trong trường hợp đó, mã xem sẽ là:

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

Điều này, rõ ràng, sẽ yêu cầu một phương pháp liên kết trên mô hình. Đây là những gì nó cần để chứa:

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

Theo quan điểm của câu hỏi, thing_path () là một phương thức không xác định bên trong mã Model. Tôi cho rằng có thể "kéo" một số phương thức trợ giúp vào mô hình, nhưng bằng cách nào? Và có một lý do thực sự rằng định tuyến chỉ hoạt động tại bộ điều khiển và xem các lớp của ứng dụng? Tôi có thể nghĩ ra rất nhiều trường hợp mã mô hình có thể cần xử lý URL (tích hợp với các hệ thống bên ngoài, v.v.).


Một trường hợp sử dụng sẽ là: để tạo url rút ngắn từ goo.gl trong aftersave,
lulalala

2
Bạn có thể nên bọc mô hình của bạn trong một người thuyết trình nếu bạn muốn thêm logic xem, điều này sẽ giữ các lớp MVC tách biệt. Xem Draper ( github.com/jcasimir/draper ).
Kris

2
Xem thêm phần "Tạo URL cho các tuyến đã đặt tên" trong tài liệu tại api.rubyonrails.org/groupes/ActionDispatch/Routing/UrlFor.html
Backo

Câu trả lời:


698

Trong Rails 3, 4 và 5 bạn có thể sử dụng:

Rails.application.routes.url_helpers

ví dụ

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

14
Ypu có thể bao gồm điều này vào bất kỳ mô-đun nào và sau đó, bạn có thể truy cập các trình trợ giúp url ở đó. Thx
Viacheslav Molokov

41
Tự cứu mình khỏi việc sao chép :hosttùy chọn của bạn ở mọi nơi và đặt nó một lần trong các tệp cấu hình môi trường của bạn:Rails.application.routes.default_url_options[:host] = 'localhost:3000'
Andrew

5
include Rails.application.routes.url_helperslàm việc cho tôi trong Rails 4.1
ngày

1
Nếu bạn chỉ cần đường dẫn bạn có thể sử dụng: only_path => true dưới dạng tùy chọn mà không chuyển tham số máy chủ.
trueinViso

1
đây có vẻ là một lựa chọn tốt: hawkins.io/2012/03/ Mạnh
Renars Sirotins 10/03/2015

182

Tôi đã tìm thấy câu trả lời liên quan đến cách làm điều này bản thân mình. Bên trong mã mô hình, chỉ cần đặt:

Đối với đường ray <= 2:

include ActionController::UrlWriter

Đối với đường ray 3:

include Rails.application.routes.url_helpers

Điều này kỳ diệu làm cho thing_path(self)trả lại URL cho điều hiện tại hoặc other_model_path(self.association_to_other_model)trả lại một số URL khác.


27
Chỉ là một bản cập nhật, vì ở trên là không dùng nữa. Đây là hiện tại bao gồm:include Rails.application.routes.url_helpers
yalestar

2
Tôi nhận được NoMethodError (phương thức không xác định `tối ưu hóa_routes_generation? 'Cho # <ActionView :: Base: 0x007fe8c0eecbd0>) khi tôi thử điều này
moger777

118

Bạn cũng có thể tìm thấy cách tiếp cận sau sạch hơn bao gồm mọi phương pháp:

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

  def url
    url_helpers.thing_path(self)
  end
end

7
Tài liệu về điều này có vẻ khó tìm, vì vậy đây là một liên kết tốt liên quan đến việc sử dụng đại biểu trong ActiveSupport. simonecarletti.com/blog/2009/12/inside-ruby-on-rails-delegate
tlbrack

2
Tôi gặp undefined local variable or method 'url_helpers' for Event:Classlỗi ... :(
Augustin Riedinger

Tôi nhận được undefined method url_helpers. Tôi sẽ làm gì?
asiniy

@asiniy, bạn có chắc Bạn đã sử dụng tùy chọn ủy nhiệm cho url_helpers được viết sau khi khai báo lớp không?
Krzysztof Witczak

Không hoạt động, nhưng có thể điều này chỉ hoạt động nếu bạn tự tạo class, như thể hiện trong câu trả lời. Nếu lớp Model của bạn đã mở rộng < ApplicationRecordthì điều này sẽ không hoạt động?
skplunkerin

13

Bất kỳ logic nào phải làm với những gì được hiển thị trong khung nhìn nên được ủy quyền cho một phương thức của trình trợ giúp, vì các phương thức trong mô hình được sử dụng nghiêm ngặt để xử lý dữ liệu.

Đây là những gì bạn có thể làm:

# 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
Điều tôi không thích về các phương thức của trình trợ giúp trong trường hợp này: Khi tôi xem link_to_thing (), tôi phải quyết định xem đó là trình trợ giúp cụ thể hay ứng dụng rộng rãi (có thể dễ dàng như vậy). Tôi cần xem xét việc kiểm tra 2 tập tin cho nguồn. thing.link không có câu hỏi về tập tin nguồn.
Aaron Longwell

Ngoài ra, điều gì sẽ xảy ra nếu tôi cần sử dụng chức năng này trong tác vụ Rake (để xuất tệp CSV của URL có thể) ... đi trực tiếp vào mô hình cũng sẽ tốt hơn nhiều trong trường hợp đó.
Aaron Longwell

Nhưng sự khác biệt là link_to sẽ không có sẵn trong mô hình, vì nó là một trình trợ giúp ActionView. Vì vậy, điều này sẽ không hoạt động. Bạn có thể hack một số thuộc tính mặc định trong mô hình, vì vậy nếu nó không được đặt, nó mặc định là thứ gì đó, nhưng điều đó tùy thuộc vào bạn.
Josh Delsman

12
Khi API dịch vụ web phát triển, thường thì các mô hình cần liên hệ với các tài nguyên bên ngoài bằng dữ liệu của riêng họ và cung cấp URL gọi lại. Ví dụ: một đối tượng ảnh cần đăng chính nó lên Socialmod, đối tượng sẽ gọi lại URL của ảnh đó khi kiểm duyệt được thực hiện. Một hook after_create () sẽ có ý nghĩa để đăng lên Socialmod, nhưng làm thế nào để bạn biết URL gọi lại? Tôi nghĩ rằng câu trả lời của chính tác giả có ý nghĩa tốt.
JasonSmith

3
Mặc dù bạn đúng về mặt kỹ thuật, có những lúc mọi người chỉ cần mọi thứ để làm việc mà không phải cạo râu mỗi lần để tránh vi phạm một số mẫu thiết kế thiêng liêng hoặc những gì có bạn, có thể họ cần lấy url và thực sự lưu trữ Nó trong cơ sở dữ liệu, sẽ rất hữu ích khi một mô hình chỉ cần biết cách làm điều đó thay vì chuyển mọi thứ qua lại, đôi khi các quy tắc có thể bị phá vỡ.
giải mã


1

Mặc dù có thể có một cách tôi sẽ có xu hướng loại logic đó ra khỏi Mô hình. Tôi đồng ý rằng bạn không nên đặt nó trong chế độ xem ( giữ cho nó mỏng ) nhưng trừ khi mô hình trả lại một url dưới dạng một phần dữ liệu cho bộ điều khiển, công cụ định tuyến phải nằm trong bộ điều khiển.


4
Re: "Trừ khi mô hình trả về URL dưới dạng một phần dữ liệu". Đó chính xác là những gì đang xảy ra ở đây ... Mô hình "sở hữu" đoạn dữ liệu này, là liên kết đến một URL tại chỗ hoặc ngoài trang web. Trong một số trường hợp, URL được tạo từ Rails Routing. Trong các trường hợp khác, URL là dữ liệu do người dùng cung cấp.
Aaron Longwell

0

(Chỉnh sửa: Quên tiếng bập bẹ trước đây của tôi ...)

Ok, có thể có tình huống bạn sẽ chuyển sang mô hình hoặc đến một số url khác ... Nhưng tôi không thực sự nghĩ rằng điều này thuộc về mô hình, chế độ xem (hoặc có thể là mô hình) nghe có vẻ phù hợp hơn.

Về các tuyến đường, theo như tôi biết thì các tuyến đường dành cho các hành động trong bộ điều khiển (thường là "kỳ diệu" sử dụng chế độ xem), không trực tiếp cho các chế độ xem. Bộ điều khiển nên xử lý tất cả các yêu cầu, khung nhìn sẽ trình bày kết quả và mô hình sẽ xử lý dữ liệu và phục vụ nó cho khung nhìn hoặc bộ điều khiển. Tôi đã nghe rất nhiều người ở đây nói về các tuyến đường đến các mô hình (đến mức tôi hoàn toàn bắt đầu tin tưởng nó), nhưng theo tôi hiểu thì: các tuyến đường đi đến các bộ điều khiển. Tất nhiên, rất nhiều bộ điều khiển là bộ điều khiển cho một mô hình và thường được gọi <modelname>sController(ví dụ: "UsersContoder" là bộ điều khiển của mô hình "Người dùng").

Nếu bạn thấy mình viết số lượng logic khó chịu trong một khung nhìn, hãy thử di chuyển logic ở nơi nào đó phù hợp hơn; yêu cầu và logic giao tiếp bên trong có thể thuộc về bộ điều khiển, logic liên quan đến dữ liệu có thể được đặt trong mô hình (nhưng không hiển thị logic, bao gồm các thẻ liên kết, v.v.) và logic hiển thị hoàn toàn liên quan sẽ được đặt trong một trình trợ giúp.


Nói rằng bạn có một mô hình hình ảnh. Nếu Hình ảnh có URL bên ngoài được liên kết với nó, thì hãy trỏ đến URL đó. Nếu không, hãy trỏ đến trang hiển thị của Image để tải lên một hình ảnh? Chỉ là một ý tưởng.
Josh Delsman

Làm thế nào về ví dụ ít chung chung này: link_to "Hình ảnh kích thước đầy đủ", image.link Phương thức liên kết trong mô hình sẽ liên kết đến URL tại chỗ (image_path) hoặc nói, một URL Flickr nếu người dùng cung cấp một và .url đã được đặt trên hình ảnh.
Aaron Longwell
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.