Robin
Robin

Reputation: 8498

Can I display validation errors above of an embedded form in Rails?

Unfortunately I'm stuck with my comment functionality. The comment model has a polymorphic association with it's commentables. Here a sketch of the model: model sketch

Furthermore I have a publications controller, which displays of course some content, the comments and there is an embedded comment form. Another sketch about that:

conteroller-view sketch

  1. Showing the publication, with it's comment form.
  2. The comment form got submit and the data sent to the create action of the comment controller.
  3. Unfortunately the data failed the validation.

My question is now, how I can I show the validation errors above my embedded form? I know I could use the flash to show an error, but then the user loses the form data.

def create
  @comment = Comment.new(comment_params)
  @comment.commentable = find_commentable

  if @comment.save
    redirect_to polymorphic_url(@comment.commentable, anchor: 'comment-' + @comment.id.to_s)
  else
    # What do I need to do here?
  end
end

How can I make the @comment available in publications#show?

I'm on Rails 4.1.

Upvotes: 0

Views: 252

Answers (2)

moonfly
moonfly

Reputation: 1820

One of the ways to work around the problem is to create a special action for creating comments in PublicationsController and other commentable controllers (you may want to create a module that you will include in all commentable controllers to avoid repetition and DRY the code).

I didn't have time to check on a test Rails app, so I may have made some typos or other errors, or forget about something in the code above. Still, I hope, the idea is clear. Feel free to edit if you find a bug.

In your PublicationsController (and other commentable controllers):

def add_comment
  # PublicationsController -> Publication
  @commentable_class = self.class.to_s[0..-11].singularize.constantize
  @commentable = @commentable_class.find(params[:commentable_id]) # it is passed by the form, see below
  # set @publication for the publication-specific part of the show view
  instance_variable_set('@'+@comentable_class.to_s.underscore, @commentable) 

  @comment = Comment.new(comment_params.merge(commentable: @commentable)) 

  if @comment.save
    redirect_to action: :show, anchor: 'comment-' + @comment.id.to_s
  else
    render action: :show
  end
end

...

def comment_params
  # don't forget to define comment_params - as in CommentsController, I guess:
  params.require(:comment).permit(:author,:subject,:message)
end

In the show action of those commentable controllers just do

def show
  ...
  @commentable_class = self.class.to_s[0..-11].singularize.constantize
  @comment = Comment.new
  @commentable = instance_variable_get('@'+@comentable_class.to_s.underscore)
  ...
end

In the show view for the commentables use something like the following form for adding the new comments (based on the provided gist):

- if @comment.errors.any?
  %section.errors
    %p= t('errors.templates.body')
    %ul
      - @comment.errors.full_messages.each do |message|
        %li= message
= form_for @comment, url: {controller: @commentable_controller, action: :add_comment} do |form|
  = hidden_field_tag 'commentable_id', @commentable.id
  - unless user_signed_in?
    .row
      .small-12.columns
        = form.label :author
        = form.text_field :author, required: true, pattern: '.{3,30}', title: t('errors.messages.not_in_between', from: 3, to: 30)
  .row
    .small-12.columns
      = form.label :subject
      = form.text_field :subject, pattern: '.{5,80}', title: t('errors.messages.not_in_between', from: 5, to: 80)
  .row
    .small-12.columns
      = form.label :message
      = form.text_area :message, required: true, pattern: '.{30,5000}', title: t('errors.messages.not_in_between', from: 30, to: 5000)
  = form.submit class: 'small radius button right'

Upvotes: 1

ptd
ptd

Reputation: 3053

The way to do this is to add the following code to your show action in your PublicationsController: @comment = Comment.new (or @comment = @publication.comment.new depending). Then add some sort of <%= @comment.errors.full_messages %>-type code to your show.html.erb for the Publication. Finally, the else in your comments#create action should be: render 'publications/show'.

This will display the errors and will allow your comment form to be <%= form_for @comment ...etc %> so it will show whatever was typed into the comment form that didn't validate.

Upvotes: 1

Related Questions