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.