Home > database >  Redirect to another controller's action with form validation error in Rails
Redirect to another controller's action with form validation error in Rails

Time:01-09

I have parrent and child, child form is in parrent page so i can make children

I want to redirect or render parent controller's show page in child's controller.

my controller is :

    @child= Child.new(child_params)
    @parrent= Parrent.find(params[:parrent_id])
    if @child.save
      redirect_to parrent_path(@child.parrent_id), flash: { alert: 'success' }
    else
      render template: 'parrents/show'
    end

How can i redirect or render another controller's action with keeping form validation? I have presence: true in my child model. And i have error_message in parent's view file(form of child)

When i render another controller's action, my view's code(parent) with instance variable makes error.

       # parents show page
      <% @children.each do |child| %>
       # blabla


       # child controller
          @child = SOME LOGICS
       # cannot use @parent.childs

       # render template: 'parrents/show' makes nil error of @child
       

How can i pass variable to render template another controller's action or How can i redirect with form error?

I have tried =>

    if @child.save
      redirect_to parrent_path(@child.parrent_id)
    else
      redirect_to parrent_path(@child.parrent_id), flash: { error_message: 'failed') }
      # not worked
    end
      if @child.save
        redirect_to parrent_path(@child.parrent_id)
      else
      render template: 'parrents/show', { @child }
        # not worked either
      end

but not worked

CodePudding user response:

When the client sends a request to create or update a resource with invalid data you should render - not redirect. You're responding specifically to a non-idempotent POST or PATCH request with information about the errors specific to that reqest.

A redirect on the other hand always results in a GET request (which should be idempotent). And if you wanted to carry the users input over you would have to either pass it as query string parameters or for example store it in the session (don't even try it - bad idea).

Typically you do this by re-rendering the new or edit view. When you have "embedded" the form somewhere else this can get kind of messy as your ChildrenController now has to setup all the preconditions for some other controllers view.

class ChildrenController < ApplicationController

  # POST /parents/1/children
  def create
    @parent = Parent.find(params[:parent_id])
    @child = @parent.children.new(child_params)
    if @child.save
      redirect_to @parent
    else
      # these are the preconditions required to render `parents/new`
      @foo = bar
      render template: 'parents/show'
    end
  end
end

This isn't great as it results in duplication and that ChildrenController now is also responsible for showing the parent.

It also often results in a far from ideal user experience. The solution to the problem is to instead send an XHR (ajax) request to create the child record without ever leaving the page. That way your ChildController just has to be concerned with creating the resource or just re-rendering the form if you're using Turbo/Rails UJS.

class ChildrenController < ApplicationController
  # POST /parents/1/children
  def create
    @parent = Parent.find(params[:parent_id])
    @child = @parent.children.new(child_params)
    if @child.save
      redirect_to @parent
    else
      render :new
    end
  end
end
# this replaces the turbo frame that you would have defined in the parents/show view.
# app/child/new.turbo_stream
<%= turbo_stream.update @child do %>
  <%= render "form", child: @child %>
<% end %>

This isn't a complete example and there are many ways of implementing it. I would recommend you look for tutorials for Rails CRUD with Turbo if you're on Rails 7.

  • Related