Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass validation error messages to a method in a different controller?

I am just starting a rails 3 app that has a parent model and a child model (parent has_many :children).

I am trying to set things up so that after creating a new parent the user is taken to the show action of that parent (/parent/id). In this view I have included partials to show any children and a form to create a new child. After creating a new child the user is redirected to the show action for the parent where the new child will appear. This all works as intended.

However, if I try to validate fields in the new child form any error messages that occur are not appearing in the form (the necessary lines in the view are there and are correct - cut and pasted from generated scaffold code). Is there a way of passing these error messages for the child successfully to the parent show action?

Here are snippets of relevant code;

From my parent controller:

def show
  @parent = Parent.find(params[:id])
  @child = @parent.children.new

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

From my child controller:

def create
  @child = Child.new(params[:parent])

  respond_to do |format|
    if @child.save
      format.html { redirect_to(parent_path(params[:child][:parent_id]), :notice => 'Child was successfully created.') }
               #This works as intended
      format.xml  { render :xml => @child, :status => :created, :location => @child }
    else
      format.html { redirect_to parent_path(params[:child][:patient_id]) }
               #This redirects where I want it to go when validation fails but error messages are lost
      format.xml  { render :xml => @child.errors, :status => :unprocessable_entity }
    end
  end
end
like image 468
brad Avatar asked Apr 01 '11 11:04

brad


2 Answers

Alright, I solved this myself. Thanks for Terw's answer though. It works apart from giving the wrong URL because of the lack of redirect.

It was simply a matter of passing the errors via the session hash and then adding them to the child model in the parent controller.

I'm posting the code because I couldn't find any other examples of this out there. Perhaps there's a simpler way but this works perfectly so far. If anyone thinks I'm crazy then please explain.

In my child controller

def create
  @parent = Parent.find(params[:child][:parent_id])
  @child = @parent.child.build(params[:child])

  respond_to do |format|
    if @child.save
      format.html { redirect_to(parent_path(params[:admission][:parent_id]), :notice => 'Child was successfully created.') }
      format.xml  { render :xml => @child, :status => :created, :location => @child }
    else
      if @child.errors.any?
        session[:child_errors] = @child.errors
      end
      format.html { redirect_to(parent_path(params[:child][:parent_id])) }
      format.xml  { render :xml => @child.errors, :status => :unprocessable_entity }
    end
  end
end

And in my parent controller

def show
  @parent = Parent.find(params[:id])
  @child = @parent.children.new
  if session[:child_errors]
    session[:child_errors].each {|error, error_message| @child.errors.add error, error_message}
    session.delete :child_errors
  end
  respond_to do |format|
    format.html # show.html.erb
    format.xml  { render :xml => @parent }
  end
end
like image 114
brad Avatar answered Oct 21 '22 12:10

brad


What if you just render the parent's show page if the child is invalid?

def create
  @child = Child.new(params[:parent])

  respond_to do |format|
    if @child.save
      format.html { redirect_to(parent_path(params[:child][:parent_id]), :notice => 'Child was successfully created.') }
               #This works as intended
      format.xml  { render :xml => @child, :status => :created, :location => @child }
    else
      format.html { render :controller => :parent, :action => :show }
               # Display the parent's show page to display the errors
      format.xml  { render :xml => @child.errors, :status => :unprocessable_entity }
    end
  end
end

You might also want to do something like this for the crate action to make sure the parent exists.

@parent = Parent.find(params[:parent][:parent_id])
@child  = @parent.children.build(params[:parent])

Then your users can't create an invalid child, and you have the parent to render the show page again. You shouldn't give the users the ability to set the parent_id them selfes.

like image 28
ThoKra Avatar answered Oct 21 '22 13:10

ThoKra