Rails 3 - Displaying submit errors on polymorphic comment model -
fairly new rails 3 , have been googling every way no avail solve following problem, tutorials stopping short of handling errors.
i have created rails 3 project multiple content types/models, such articles, blogs, etc. each content type has comments, stored in single comments table nested resource , polymorphic associations. there 1 action comments, 'create' action, because there no need show, etc belongs parent content type , should redisplay page on submit.
now have of working , comments submit , post fine, last remaining issue displaying errors when user doesn't fill out required field. if fields aren't filled out, should return parent page , display validation errors rails typically mvc.
the create action of comments controller looks this, , first tried...
def create @commentable = find_commentable @comment = @commentable.comments.build(params[:comment]) respond_to |format| if @comment.save format.html { redirect_to(@commentable, :notice => 'comment created.') } else format.html { redirect_to @commentable } format.xml { render :xml => @commentable.errors, :status => :unprocessable_entity } end end end
when fill nothing out , submit comments form, page redirect it's appropriate parent, no flash or nothing displayed. figured out why, understand, flash won't persist on redirect_to, on render. here's trouble lies.
there 'create' action in comment controller, needed point render towards 'blogs/show' (note: know isn't polymorphic, once working i'll worry then). tried in "else" block of above code...
else format.html { render 'blogs/show' } format.xml { render :xml => @commentable.errors, :status => :unprocessable_entity } end
anyway, when try submit invalid comment on blog, error message saying "showing [...]/app/views/blogs/show.html.erb line #1 raised: undefined method `title' nil:nilclass."
looking @ url, think know why...instead of directing /blogs/the-title-of-my-article (i'm using friendly_id), it's going /blogs/the-title-of-my-article/comments. figure "comments" throwing query off , returning nil.
so how can page render without throwing 'comments' on there? or there better way go issue?
not sure if matters or helps, route.rb comments / blogs looks this...
resources :blogs, :only => [:show] resources :comments, :only => [:create] end
i've been plugging away @ on last few weeks , think i've pulled off, errors/proper direction on render, filled out fields remain filled in , all. did consider ajax, prefer graceful degradation if @ possible.
in addition, admit had go hacky-sack way, including pulling in way pluralize parent model render appropriate content type's show action, , @ stage need code work, not pretty doing it.
i know can refactored way better, , hope better rails. or, else thinks can improve welcomed have @ it. anyway, here code, wanted share , hope helps in same scenario.
comments_controller.rb
class commentscontroller < applicationcontroller # include bring text helper methods controller include actionview::helpers::texthelper def create @commentable = find_commentable @comment = @commentable.comments.build(params[:comment]) respond_to |format| if @comment.save format.html { redirect_to(@commentable, :notice => 'comment created.') } else # transform class of commentable 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 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 id/type of parent model, see comment#create in controller def find_commentable params.each |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 content type blogs_controller.rb, replace appropriate instance variable @content = @article respond_to |format| format.html # show.html.erb format.xml { render :xml => @article } end end end
show.html.erb articles (change appropriate variables blog or whatever)
<h1><%= @article.title %></h1> <%= @article.body.html_safe %> <%= render :partial => 'shared/comments', :locals => { :commentable => @article } %>
shared/_comments.html.erb (i'm leaving out displaying of posted comments here simplification, showing form submit them)
<%= form_for([commentable, @comment]) |f| %> <h3>post 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 %>
shared/_errors.html.erb (i refactored partial reuse articles, blogs, comments, etc, standard error code)
<% if content.errors.any? %> <div class="flash error"> <p><strong><%= pluralize(content.errors.count, "error") %> prohibited page being saved:</strong></p> <ul> <% content.errors.full_messages.each |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %>
Comments
Post a Comment