2011-02-17 48 views
3

對於Rails 3來說是相當新穎的東西,並且一直在使用谷歌搜索來解決以下問題,大多數教程都沒有處理錯誤。Rails 3 - 在多態評論模型上顯示提交錯誤

我創建了一個帶有多種內容類型/模型(例如文章,博客等)的Rails 3項目。每個內容類型都有註釋,所有內容都作爲嵌套資源存儲在一個註釋表中,並且具有多態關聯。對於評論只有一個動作,'創建'動作,因爲不需要展示等,因爲它屬於父內容類型,並且應該在提交時簡單地重新顯示該頁面。

現在我大部分工作和評論提交和發佈都很好,但最後剩下的問題是當用戶沒有填寫必填字段時顯示錯誤。如果這些字段沒有填寫,它應該返回到父頁面並顯示驗證錯誤,比如Rails通常對MVC所做的一樣。

的創建我的評論的動作控制器看起來是這樣的,這是我第一次嘗試......

def create 
    @commentable = find_commentable 
    @comment = @commentable.comments.build(params[:comment]) 

    respond_to do |format| 
     if @comment.save 
     format.html { redirect_to(@commentable, :notice => 'Comment was successfully created.') } 
     else 
     format.html { redirect_to @commentable } 
     format.xml { render :xml => @commentable.errors, :status => :unprocessable_entity } 
     end 
    end 
end 

當你沒有填寫和提交意見的形式,該頁面不重定向到它的適當的父母,但不會顯示任何內容或閃光。現在我明白了爲什麼,據我所知,閃光燈不會持續在redirect_to上,只能在渲染上。現在,這是麻煩所在。

在註釋控制器中只有'創建'動作,所以我需要將渲染指向'blogs/show'(注意:我知道這不是多形的,但是一旦我得到這個工作,我會那麼擔心)。我想這個在上面的代碼中的「其他」塊...

else 
    format.html { render 'blogs/show' } 
    format.xml { render :xml => @commentable.errors, :status => :unprocessable_entity } 
end 

無論如何,當我嘗試在博客提交無效評論,我得到一個錯誤信息「顯示[...] /app/views/blogs/show.html.erb第1行出現的地方:未定義的方法'標題'爲零:NilClass。「

看着這個URL,我想我知道爲什麼......而不是直接指向/ blogs/the-title-of-my-article(我使用的是friendly_id),它會去/ blogs/the-title -of-MY-文章/評論。我認爲額外的「註釋」是拋出查詢並返回零。

那麼我怎樣才能讓頁面呈現沒有在那裏拋出額外的「評論」?還是有更好的方法去解決這個問題?

不知道它的事項或幫助,但徵求意見/博客route.rb看起來像這樣...

resources :blogs, :only => [:show] do 
    resources :comments, :only => [:create] 
end 

回答

0

你得到一個錯誤,因爲blogs/show看法可能是指@blog對象,當您在評論控制器中呈現時,它不存在。

你應該回去使用redirect_to而不是渲染。當您發佈無效評論時,它不會顯示Flash,因爲如果評論未保存,您並未告訴它設置Flash。閃存將一直持續到下一個請求。

+0

你是對的,當我設置一條消息如':alert =>'有字段丟失'時,消息通過下一個請求持續存在。然而,我忽略了一些使得這個問題的事情。應填寫的字段不會突出顯示(field_with_errors),上面的閃光燈也不會顯示哪些字段錯誤。第二個問題 - 具有redirect_to的較大問題是,所有填寫的字段在重定向時都會丟失,如果某個字段被忽略,那麼在用戶方面會出現問題。我谷歌搜索的大部分內容一直在說只有渲染才能支持它們。 – Shannon 2011-02-17 21:11:11

+0

這是正確的,你可以在會話中保存失敗的`@ comment`,以便在重定向後訪問它,但這有點過分。我個人認爲最好的方法是通過AJAX保存評論。以下是一些可幫助您開始使用的資源:http://railscasts.com/episodes/74-complex-forms-part-2 http://railscasts.com/episodes/45-rjs-tips http:// www .stjhimy.com/posts/7 – 2011-02-17 21:27:45

3

在過去的幾周裏,我一直在關注這個問題,並且我認爲我終於完成了它,關於渲染的錯誤/正確的方向,填充的字段保持填充。我確實考慮過AJAX,但是如果可能的話,我會傾向於優雅地降級。另外,我承認我必須採取一種非常黑客式的方式,包括以一種方式來複制父模型以呈現適當的內容類型的顯示動作,並且在這個階段,我需要代碼來只是工作,不一定看起來很漂亮。

我知道它可以被重構的方式更好,我希望這樣做,因爲我得到更好的Rails。或者,其他任何認爲他們可以改進這一點的人都歡迎擁有它。無論如何,這裏是我所有的代碼,只是想分享回來,並希望這可以幫助同一場景中的某個人。

comments_controller.rb

class CommentsController < ApplicationController 
    # this include will bring all the Text Helper methods into your Controller 
    include ActionView::Helpers::TextHelper 

    def create 
     @commentable = find_commentable 
     @comment = @commentable.comments.build(params[:comment]) 

     respond_to do |format| 
      if @comment.save 
       format.html { redirect_to(@commentable, :notice => 'Comment was successfully created.') } 
      else 

       # Transform class of commentable into pluralized content type 
       content_type = find_commentable.class.to_s.downcase.pluralize 

       # Choose appropriate instance variable based on @commentable, rendered page won't work without it 
       if content_type == 'blogs' 
        @blog = @commentable 
       elsif content_type == 'articles' 
        @article = @commentable 
       end 

       format.html { render "#{content_type}/show" } 
       format.xml { render :xml => @commentable.errors, :status => :unprocessable_entity } 
      end 
     end 
    end 

    private 

    # Gets the ID/type of parent model, see Comment#create in controller 
    def find_commentable 
     params.each do |name, value| 
      if name =~ /(.+)_id$/ 
       return $1.classify.constantize.find(value) 
      end 
     end 
    end 
end 

articles_controller.rb

class ArticlesController < ApplicationController 

    def show 
    @article = Article.where(:status => 1).find_by_cached_slug(params[:id]) 
    @comment = Comment.new 

    # On another content type like blogs_controller.rb, replace with appropriate instance variable 
    @content = @article 

    respond_to do |format| 
     format.html # show.html.erb 
     format.xml { render :xml => @article } 
    end 
    end 

end 

show.html.erb中的文章(更改博客或任何合適的變量)

<h1><%= @article.title %></h1> 

<%= @article.body.html_safe %> 

<%= render :partial => 'shared/comments', :locals => { :commentable => @article } %> 

共享/ _comments .html.erb(我只是爲了簡化而忽略顯示發佈的評論示出表單提交他們)

<%= form_for([commentable, @comment]) do |f| %> 
    <h3>Post a new comment</h3> 

    <%= render :partial => 'shared/errors', :locals => { :content => @comment } %> 

    <div class="field"> 
     <%= f.label :name, :value => params[:name] %> 
     <%= f.text_field :name, :class => 'textfield' %> 
    </div> 

    <div class="field"> 
     <%= f.label :mail, :value => params[:mail] %> 
     <%= f.text_field :mail, :class => 'textfield' %> 
    </div> 

    <div class="field"> 
     <%= f.text_area :body, :rows => 10, :class => 'textarea full', :value => params[:body] %> 
    </div> 

    <%= f.submit :class => 'button blue' %> 
<% end %> 

共享/ _errors.html.erb(I重構此作爲部分重用爲文章,博客,評論,等等,但是這僅僅是一個標準的錯誤碼)

<% if content.errors.any? %> 
    <div class="flash error"> 
     <p><strong><%= pluralize(content.errors.count, "error") %> prohibited this page from being saved:</strong></p> 
     <ul> 
      <% content.errors.full_messages.each do |msg| %> 
       <li><%= msg %></li> 
      <% end %> 
     </ul> 
    </div> 
<% end %> 
0

我稍微重構@Shannon的答案,使其更具動感。在我的'find_parent'方法中,我抓取url路徑並獲取控制器名稱。在'create'方法中,我創建了一個'instance_variable_set',它爲文章(@article)或博客(@blog)創建一個動態變量,或者它可能會創建一個動態變量。

希望你會喜歡我所做的?請讓我知道你是否有疑問或是否有什麼可以改進的地方?

​​