레일스 라우팅 헬퍼 (예 : mymodel_path (model))를 모델에 사용할 수 있습니까?


368

Thing이라는 Rails 모델이 있다고 가정 해 봅시다. 사물은 인터넷 어딘가에 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을 처리해야하는 경우 (외부 시스템과의 통합 등)를 생각할 수 있습니다.


유스 케이스는 다음과 같습니다 : 사후 저장에서 goo.gl에서 단축 된 URL 생성
lulalala

2
뷰 로직을 추가하려면 MVC 레이어를 분리 된 상태로 유지하려면 프리젠터에서 모델을 래핑해야합니다. Draper ( github.com/jcasimir/draper )를 참조하십시오 .
Kris

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 도우미에 액세스 할 수 있습니다. Thx
Viacheslav Molokov

41
:host어디서나 옵션 을 복사하지 않고 환경 설정 파일에 한 번 설정하십시오.Rails.application.routes.default_url_options[:host] = 'localhost:3000'
Andrew

5
include Rails.application.routes.url_helpersRails 4.1에서 나를 위해
Jan

1
경로 만 있으면 호스트 매개 변수를 전달하지 않고 : only_path => true를 옵션으로 사용할 수 있습니다.
trueinViso

1
이것은 좋은 선택 인 것 같습니다 : hawkins.io/2012/03/…
Renars Sirotins

182

이 작업을 수행하는 방법에 대한 답변을 찾았습니다. 모델 코드 안에 다음을 입력하십시오.

레일 <= 2 :

include ActionController::UrlWriter

레일 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 (# <ActionView :: Base : 0x007fe8c0eecbd0>에 대해 정의되지 않은 메소드`optimize_routes_generation? ')가 표시됩니다.
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:( ... 오류
아우구스틴 Riedinger

나는 얻는다 undefined method url_helpers. 내가 무엇을 할까?
asiniy

@asiniy, 클래스 선언 후 작성된 url_helpers에 delegate 옵션을 사용 했습니까?
Krzysztof Witczak

작동하지 않지만 class답변에 표시된 것처럼 자신 만 만들면 작동 할 수 있습니다 . Model 클래스가 이미 확장되어 있으면 < 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

또한 레이크 작업 에서이 기능을 사용해야하는 경우 (아마 URL의 CSV 파일을 내보내는 경우) ...이 경우 모델로 직접 이동하는 것이 훨씬 좋습니다.
Aaron Longwell

그러나 차이점은 link_to는 ActionView 헬퍼이기 때문에 모델에서 사용할 수 없다는 것입니다. 따라서 이것은 작동하지 않습니다. 모델에서 일부 속성 기본값을 해킹 할 수 있으므로 설정하지 않으면 기본값으로 설정되지만 사용자에게 달려 있습니다.
Josh Delsman

12
웹 서비스 API가 증가함에 따라 모델이 외부 리소스에 자체 데이터를 연결하고 콜백 URL을 제공해야하는 경우가 종종 있습니다. 예를 들어 사진 개체는 Socialmod에 자신을 게시해야하며 중재가 수행 될 때 사진의 URL로 다시 호출됩니다. after_create () 훅은 Socialmod에 게시하는 것이 합리적이지만 콜백 URL을 어떻게 알 수 있습니까? 저자 자신의 대답이 합리적이라고 생각합니다.
JasonSmith

3
엄밀히 기술적 인 의미에서 옳지 만 사람들이 모든 야크를 면도하지 않고 일할 필요가있는 경우가 있습니다. 성스러운 디자인 패턴을 위반하거나 당신이 가진 것을 피해야합니다. 아마 URL을 얻어야하고 실제로 저장해야합니다. 데이터베이스의 경우, 모델이 작업을 앞뒤로 전달하는 대신 수행하는 방법을 알면 편리하며 때로는 규칙이 깨질 수 있습니다.
nitecoder


1

방법이있을 수 있지만 모델에서 그런 종류의 논리를 유지하는 경향이 있습니다. 나는 당신이 그것을 뷰에 넣지 말아야한다는 것에 동의 하지만 ( 스키니 유지 ) 모델이 URL을 컨트롤러에 데이터 조각으로 반환하지 않는 한 라우팅 항목은 컨트롤러에 있어야합니다.


4
다시 : "모델이 데이터의 일부로 URL을 반환하지 않는 한". 이것이 바로 여기서 일어나고있는 일입니다. 모델은이 데이터를 "소유"합니다. 이는 현장 또는 외부 URL에 대한 링크입니다. 경우에 따라 URL은 Rails Routing에서 생성됩니다. 다른 경우, URL은 사용자 제공 데이터입니다.
Aaron Longwell

0

(편집 : 이전 babble을 잊어 버려라 ...)

좋아, 모델이나 다른 URL로 갈 수있는 상황이있을 수 있습니다 ...하지만 이것이 모델에 속한다고 생각하지는 않습니다.보기 (또는 모델)가 더 적절하게 들립니다.

내가 아는 한 경로에 대해서는 경로가 직접 컨트롤러가 아닌 컨트롤러의 작업 (일반적으로 "매직"보기)을 사용하는 것입니다. 컨트롤러는 모든 요청을 처리하고, 뷰는 결과를 제시해야하며, 모델은 데이터를 처리하고이를 뷰 또는 컨트롤러에 제공해야합니다. 여기서 많은 사람들이 모델로가는 길 (내가 가장 믿기 시작한 시점까지)에 대해 이야기하는 것을 들었습니다. 그러나 제가 이해하는대로 : 길은 컨트롤러로갑니다. 물론 많은 컨트롤러가 한 모델의 컨트롤러이며 종종 호출됩니다 <modelname>sController(예 : "UsersController"는 "User"모델의 컨트롤러입니다).

보기에서 불쾌한 양의 논리를 작성하는 경우 논리를보다 적절한 위치로 이동하십시오. 요청 및 내부 통신 로직은 아마도 컨트롤러에 속할 수 있으며, 데이터 관련 로직은 모델에 배치 될 수 있지만 (링크 태그 등을 포함하는 디스플레이 로직은 아님) 순수한 디스플레이 관련 로직은 헬퍼에 배치됩니다.


이미지 모델이 있다고 가정 해보십시오. 이미지에 연결된 외부 URL이 있으면 해당 URL을 가리 킵니다. 그렇지 않으면 이미지를 업로드하기 위해 이미지의 쇼 페이지를 가리 킵니까? 그냥 생각이야
Josh Delsman

이 덜 일반적인 예는 다음과 같습니다. link_to "Full Size Image", image.link 모델의 link 메소드는 온 사이트 URL (image_path)에 링크하거나 사용자가 하나를 제공 한 경우 Flickr URL에 링크합니다. 이미지에 .url이 설정되었습니다.
Aaron Longwell
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.