Rails Yönlendirme Yardımcıları (örn. Mymodel_path (model)) Modellerde Kullanılabilir mi?


368

Diyelim ki Thing isimli bir Rails Modelim var. Şey, isteğe bağlı olarak İnternet'in herhangi bir yerinde bir URL'ye ayarlanabilen bir url özelliğine sahiptir . Görünüm kodunda, ben aşağıdakileri yapan mantık gerekir:

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

Görünümdeki bu koşullu mantık çirkin. Tabii ki, görünümü bu şekilde değiştirecek bir yardımcı işlev inşa edebilirim:

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

Bu, ayrıntı problemini çözer, ancak modelin kendisinde işlevselliğe sahip olmayı gerçekten tercih ederim. Bu durumda, görünüm kodu şöyle olur:

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

Bu, açıkça, model üzerinde bir bağlantı yöntemi gerektirecektir. Aşağıdakileri içermesi gerekir:

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

Sorunun noktasına gelindiğinde thing_path (), Model kodu içinde tanımsız bir yöntemdir. Bazı yardımcı yöntemleri modele "çekmek" mümkün olduğunu varsayıyorum, ama nasıl? Yönlendirmenin yalnızca denetleyicide çalışmasının ve uygulamanın katmanlarını görüntülemesinin gerçek bir nedeni var mı? Model kodunun URL'lerle (harici sistemlerle entegrasyon vb.) Uğraşması gerekebilecek birçok durumu düşünebilirim.


Bir kullanım durumu şöyle olur: art arda tasarrufta goo.gl'den kısaltılmış URL oluşturmak,
lulalala

2
Görünüm mantığı eklemek istiyorsanız, muhtemelen modelinizi bir sunucuya sarmalısınız, bu MVC katmanlarını ayrı tutar. Bkz. Draper ( github.com/jcasimir/draper ).
Kris

Yanıtlar:


698

Rails 3, 4 ve 5'te şunları kullanabilirsiniz:

Rails.application.routes.url_helpers

Örneğin

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

14
Ypu bunu herhangi bir modüle ekleyebilir ve bundan sonra orada url yardımcılarına erişebilirsiniz. Thx
Viacheslav Molokov

41
:hostSeçeneğinizi her yere kopyalamaktan kurtarın ve ortam yapılandırma dosyalarınızda bir kez ayarlayın:Rails.application.routes.default_url_options[:host] = 'localhost:3000'
Andrew

5
include Rails.application.routes.url_helpersbenim için çalışıyor Rails 4.1
Ocak

1
Sadece yola ihtiyacınız varsa host parametresini geçmeden bir seçenek olarak only_path => true kullanabilirsiniz.
trueinViso

1
Bu iyi bir seçenek gibi görünüyor: hawkins.io/2012/03/…
Renars Sirotins

182

Bunu kendim nasıl yapacağımla ilgili cevabı buldum. Model kodunun içine şunu koyun:

Raylar için <= 2:

include ActionController::UrlWriter

Raylar 3 için:

include Rails.application.routes.url_helpers

Bu, sihirli bir şekilde thing_path(self)mevcut şeyin other_model_path(self.association_to_other_model)URL'sini döndürür veya başka bir URL döndürür.


27
Yukarıdakiler kullanımdan kaldırıldığı için sadece bir güncelleme. Bu şu anki içerir:include Rails.application.routes.url_helpers
yalestar

2
Bunu denediğimde NoMethodError (# <ActionView :: Base: 0x007fe8c0eecbd0> için tanımlanmamış yöntem `` optimize_routes_generation? '')
Aldım

118

Aşağıdaki yöntemi her yöntemi dahil etmekten daha temiz bulabilirsiniz:

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

  def url
    url_helpers.thing_path(self)
  end
end

7
Bununla ilgili belgelerin bulunması zor görünüyordu, bu yüzden ActiveSupport'ta delege kullanımı ile ilgili iyi bir bağlantı. simonecarletti.com/blog/2009/12/inside-ruby-on-rails-delegate
tlbrack

2
Bir undefined local variable or method 'url_helpers' for Event:Classhata alıyorum ... :(
Augustin Riedinger

Anladım undefined method url_helpers. Ne yapacağım?
asiniy

@asiniy, sınıf bildiriminden sonra yazılan url_helpers için temsilci seçeneğini kullandığınızdan emin misiniz?
Krzysztof Witczak

Çalışmıyor, ancak classyanıtta gösterildiği gibi, yalnızca kendiniz oluşturursanız bu işe yarayabilir . Model sınıfınız zaten genişliyorsa, < ApplicationRecordbu işe yaramaz mı?
skplunkerin

13

Görünümde görüntülenenlerle ilgili olan herhangi bir mantık, modeldeki yöntemler kesinlikle veri işlemek için olduğu için yardımcı bir yönteme devredilmelidir.

İşte yapabilecekleriniz:

# 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
Bu durumda yardımcı yöntemler hakkında sevmediğim şey: link_to_thing () 'e baktığımda, bunun bir şeye özgü veya uygulama çapında bir yardımcı olup olmadığına karar vermeliyim (kolayca ya da olabilir). Kaynak için 2 dosyayı kontrol etmeyi düşünmeliyim. thing.link kaynak dosya hakkında hiçbir soru bırakmaz.
Aaron Longwell

Ayrıca, bu işlevselliği bir Komisyon görevinde kullanmam gerekirse (belki de URL'lerin bir CSV dosyasını dışa aktarmak için) ... doğrudan modele gitmek de bu durumda çok daha iyi olurdu.
Aaron Longwell

Ancak fark, bir ActionView yardımcısı olduğu için link_to'nun modelde mevcut olmamasıdır. Yani, bu işe yaramaz. Modeldeki bazı öznitelik varsayılanlarını hackleyebilirsiniz, bu nedenle ayarlanmadıysa, varsayılan olarak bir şeydir, ancak bu size bağlıdır.
Josh Delsman

12
Web hizmetleri API'leri büyüdükçe, çoğu zaman modellerin harici kaynaklarla kendi verileriyle iletişim kurması ve geri arama URL'leri sağlaması gerekir. Örneğin, bir fotoğraf nesnesinin kendisini Sosyalleştirme'ye göndermesi gerekir; bu, denetleme gerçekleştirildiğinde o fotoğrafın URL'sini geri çağırır. Bir after_create () kancası Socialmod'a mesaj göndermek mantıklı olur, ancak geri arama URL'sini nasıl bilirsiniz? Bence yazarın kendi cevabı mantıklı.
JasonSmith

3
Kesinlikle teknik anlamda haklı olmanıza rağmen, insanların her yakı tıraş etmek zorunda kalmadan çalışması gereken şeylere ihtiyaç duyduğu zamanlar vardır, bazı kutsal tasarım desenlerini veya neye sahip olduğunuzu ihlal etmekten kaçınmaktır, belki de url'yi almaları ve aslında saklamaları gerekir veritabanında, o zaman bir model için sadece şeyler ileri geri geçmek yerine, nasıl yapılacağını bilmek kullanışlı olurdu, bazen kurallar bozulabilir.
nitecoder


1

Bu tür bir mantığı Modelden uzak tutmanın bir yolu olsa da. Bunu görünümde ( sıska tutun ) koymamanız gerektiğini kabul ediyorum, ancak model bir url'yi denetleyiciye bir veri parçası olarak döndürmüyorsa, yönlendirme öğeleri denetleyicide olmalıdır.


4
Re: "Model bir veri parçası olarak bir URL döndürmüyorsa". Burada olan tam olarak budur ... Model, bir site içi veya site dışı URL'ye bağlantı olan bu veri parçasına "sahiptir". Bazı durumlarda URL, Rails Routing'den oluşturulur. Diğer durumlarda URL, kullanıcı tarafından sağlanan verilerdir.
Aaron Longwell

0

(Düzenle: Önceki gevezemi unut ...)

Tamam, modele veya başka bir url'ye gidebileceğiniz durumlar olabilir ... Ama bunun modele ait olduğunu düşünmüyorum, görünüm (veya belki model) daha uygun görünüyor.

Rotalar hakkında, bildiğim kadarıyla, yollar doğrudan görünümlere değil, kontrolörlerdeki eylemler içindir (genellikle "sihirli" bir görünüm kullanır). Denetleyici tüm istekleri işlemeli, görünüm sonuçları sunmalı ve model verileri işlemeli ve görünüme veya denetleyiciye sunmalıdır. Burada bir çok insanın modellere giden güzergahlar hakkında konuştuğunu duydum (en çok onu açmaya başladığım noktaya kadar), ama anladığım kadarıyla: yollar kontrolörlere gidiyor. Tabii ki birçok kontrolör bir model için kontrolördür ve genellikle denir <modelname>sController(örn. "UsersController", "Kullanıcı" modelinin kontrolörüdür).

Kendinizi bir görünümde kötü miktarlarda mantık yazarken bulursanız, mantığı daha uygun bir yere taşımayı deneyin; istek ve dahili iletişim mantığı muhtemelen denetleyiciye aittir, veri ile ilgili mantık modele yerleştirilebilir (ancak bağlantı etiketlerini içeren görüntü mantığı değil) ve tamamen görüntülenen mantık bir yardımcıya yerleştirilir.


Bir Görüntü modeliniz olduğunu varsayalım. Resmin kendisiyle ilişkilendirilmiş bir dış URL'si varsa, o URL'yi işaret edin. Aksi takdirde, bir resim yüklemek için Resmin şov sayfasını gösterilsin mi? Sadece bir fikir.
Josh Delsman

Bu daha az genel örneğe ne dersiniz: link_to "Tam Boyutlu Resim", image.link Modeldeki bağlantı yöntemi, site URL'sine (image_path) veya kullanıcı bir URL sağladıysa bir Flickr URL'sine bağlanır ve .url resme ayarlandı.
Aaron Longwell
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.