iç içe geçmiş kaynaklarla form_for


125

Form_for ve iç içe geçmiş kaynaklar hakkında iki bölümden oluşan bir sorum var. Diyelim ki bir blog motoru yazıyorum ve bir makaleyle bir yorum ilişkilendirmek istiyorum. İç içe geçmiş bir kaynağı şu şekilde tanımladım:

map.resources :articles do |articles|
    articles.resources :comments
end

Yorum formu, makalelerin show.html.erb görünümündedir, makalenin altında, örneğin şu şekilde:

<%= render :partial => "articles/article" %>
<% form_for([ :article, @comment]) do |f| %>
    <%= f.text_area :text %>
    <%= submit_tag "Submit" %>
<%  end %>

Bu bir hata verir, "Sıfır için kimlik çağrısı, yanlışlıkla vb." Ben de denedim

<% form_for @article, @comment do |f| %>

Bu, doğru şekilde oluşturulur, ancak f.text_area'yı yorumun yerine makalenin 'metin' alanıyla ilişkilendirir ve bu metin alanındaki makale.text niteliği için html'yi sunar. Bu yüzden ben de bunu yanlış yapıyorum. İstediğim şey, 'gönder'in' CommentsController'da yaratma eylemini çağıracağı, parametrelerde bir makale_kimliği, örneğin / makaleler / 1 / yorumlar için bir gönderi isteği gibi bir form.

Sorumun ikinci kısmı, başlamak için yorum örneğini oluşturmanın en iyi yolu nedir? MakalelerController'ın gösteri eyleminde bir @ yorum oluşturuyorum, bu nedenle bir yorum nesnesi, form_for helper için kapsam dahilinde olacak. Daha sonra CommentsController'ın yaratma eyleminde, form_for'dan aktarılan parametreleri kullanarak yeni @ yorum oluşturuyorum.

Teşekkürler!

Yanıtlar:


228

Travis R haklı. (Keşke size oy verebilseydim.) Bunu kendim çalıştırdım. Bu rotalarla:

resources :articles do
  resources :comments
end

Gibi yollar elde edersiniz:

/articles/42
/articles/42/comments/99

kontrolörlere yönlendirildi

app/controllers/articles_controller.rb
app/controllers/comments_controller.rb

http://guides.rubyonrails.org/routing.html#nested-resources adresinde söylendiği gibi , özel ad alanları olmadan.

Ancak parçalar ve biçimler aldatıcı hale gelir. Köşeli parantezlere dikkat edin:

<%= form_for [@article, @comment] do |f| %>

En önemlisi, bir URI istiyorsanız, şuna benzer bir şeye ihtiyacınız olabilir:

article_comment_path(@article, @comment)

Alternatif:

[@article, @comment]

http://edgeguides.rubyonrails.org/routing.html#creating-paths-and-urls-from-objects adresinde açıklandığı gibi

Örneğin, comment_itemyineleme için sağlanan ile kısmi koleksiyonların içinde ,

<%= link_to "delete", article_comment_path(@article, comment_item),
      :method => :delete, :confirm => "Really?" %>

Jamuraa'nın söylediği şey Makale bağlamında işe yarayabilir, ancak benim için çeşitli başka şekillerde işe yaramadı.

İç içe geçmiş kaynaklarla ilgili pek çok tartışma var, örneğin http://weblog.jamisbuck.org/2007/2/5/nesting-resources

İlginç bir şekilde, çoğu insanın birim testlerinin aslında tüm yolları test etmediğini öğrendim. İnsanlar jamisbuck'ın önerisini izlediklerinde, iç içe geçmiş kaynaklara ulaşmanın iki yolunu bulurlar. Birim testleri genellikle en basit olanı alır / yayınlar:

# POST /comments
post :create, :comment => {:article_id=>42, ...}

Tercih edebilecekleri rotayı test etmek için şu şekilde yapmaları gerekir:

# POST /articles/42/comments
post :create, :article_id => 42, :comment => {...}

Bunu öğrendim çünkü bundan geçiş yaptığımda birim testlerim başarısız olmaya başladı:

resources :comments
resources :articles do
  resources :comments
end

buna:

resources :comments, :only => [:destroy, :show, :edit, :update]
resources :articles do
  resources :comments, :only => [:create, :index, :new]
end

Sanırım yinelenen rotalara sahip olmak ve birkaç birim testi kaçırmak sorun değil. (Neden test etmelisiniz? Çünkü kullanıcı kopyaları hiç görmese bile, formlarınız bunlara dolaylı olarak veya adlandırılmış yollarla başvurabilir.) Yine de gereksiz tekrarlamayı en aza indirmek için şunu tavsiye ederim:

resources :comments
resources :articles do
  resources :comments, :only => [:create, :index, :new]
end

Uzun cevap için özür dilerim. Bence pek çok insan inceliklerin farkında değil.


Çalışıyor ama, Jamuraa'nın dediği gibi denetleyiciyi değiştirmek zorunda kaldım.
Marcus Becker

Jam'in yolu işe yarıyor, ancak muhtemelen bilmediğiniz ekstra rotalarla sonuçlanabilirsiniz. Açık olmak daha iyidir.
cdunn2001

Kaynakları, @result @course içine yerleştirdim. Yine de [@result, @course]çalıştı, ama form_for(@result, url: { action: "create" }) aynı zamanda çalışıyor. Bu yalnızca son model adına ve yöntem adına ihtiyaç duyar.
Enver

@ cdunn2001 Lütfen burada neden "@article" den bu şekilde bahsetmemiz gerektiğini ve bunun ne anlama geldiğini açıklar mısınız? aşağıdaki sözdizimi ne işe yarar? : <% = form_for [@article, @ yorum] do | f | %>
Arpit Agarwal

1
Travis / @ cdunn2001 doğru anladı. Yinelemeler olmadan iç içe geçmiş yolları kullanırken hem üst hem de kaynağı ayarlamayın, aksi takdirde tüm eylemlerin iç içe olduğunu düşünecektir. Aynı şekilde, her şeyi iç içe geçirirseniz, her zaman AT.parent ayarlayın. Ayrıca, kısmen iç içe geçmiş yollara sahip bir iptal düğmesi olan ortak bir formunuz varsa, aşağıdakine benzer bir yol kullanın, böylece hangisini ayarladıysanız çalışır (alt öğenin çoğullaşmasına dikkat edin): <% = link_to 'İptal', parent_children_path (AT.parent || AT.child.parent)%>
iheggie

54

Controller'da her iki nesnenin de oluşturulmuş olduğundan emin olun: @postve @commentgönderi için, örneğin:

@post = Post.find params[:post_id]
@comment = Comment.new(:post=>@post)

Ardından görünümde:

<%= form_for([@post, @comment]) do |f| %>

Yukarıdaki gibi virgülle ayrılmış diziyi değil, form_for'da diziyi açıkça tanımladığınızdan emin olun.


Travis'inki biraz eski bir cevap, ancak bunun Rails 3.2.X için en doğru olduğuna inanıyorum. Form oluşturucunun tüm öğelerinin Yorum alanlarını doldurmasını istiyorsanız, sadece bir dizi kullanın, url yardımcılarına gerek yoktur.
Karl

1
Yalnızca eylemin iç içe olduğu üst nesneyi ayarlayın. Kaynağı yalnızca kısmen iç içe
geçirdiyseniz

35

Formda özel şeyler yapmanıza gerek yok. Gösterme eyleminde yorumu doğru bir şekilde oluşturursunuz:

class ArticlesController < ActionController::Base
  ....
  def show
    @article = Article.find(params[:id])
    @new_comment = @article.comments.build
  end
  ....
end

ve ardından makale görünümünde bunun için bir form oluşturun:

<% form_for @new_comment do |f| %>
   <%= f.text_area :text %>
   <%= f.submit "Post Comment" %>
<% end %>

varsayılan olarak, bu yorum createeylemine gidecektir ve CommentsControllerdaha sonra muhtemelen eklemek isteyeceğiniz, redirect :backböylece Articlesayfaya geri yönlendirileceksiniz .


10
form_for([@article, @new_comment])Formatı kullanmak zorunda kaldım . Sanırım bunun sebebi, bakış açısını gösterdiğim için comments#newdeğil article#new_comment. I rakam article#new_commentRaylar açıklama nesne içine yerleştiği ve bu tür onu belirtmeniz gerekmez ne işe akıllı yeterli mi?
Çorba
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.