During development with Rails, I was worried about how to handle render when implementing the form, so I was able to reconfirm the difference between redirect_to and render while investigating, so I will leave it as a reminder. By the way, I will also write about what I was worried about with render for a moment. (Specifically, handling before_action)
・ Ruby 2.6.5 ・ Rails 6.0.3
I made an application to register restaurant information, and set the following actions on the controller.
shops_controller.rb
def new
@shop = Shop.new
end
def create
@shop = @owner.shops.new(shop_params)
if @shop.save
redirect_to :index
else
render :new
end
end
I wrote this without thinking about anything anymore, but if saving fails, why use render to return to the post form again? Let's look back on that.
** In conclusion, I want to return to the input form again while retaining the input contents **.
So why can that be achieved by using render instead of redirect_to? Let's look back at the behavior of redirect_to and render.
** redircet_to is a process that allows the client side to access the specified action (or path). ** ** As a result, you will access the page after revisiting the flow of MVC. Specifically, it is a flow of "access the specified action again ⇨ execute the action of the controller ⇨ display the corresponding view".
It does exactly the same thing as accessing an action view from a url.
Render, on the other hand, just displays the view corresponding to the specified action without going through the ** action again. ** ** Unlike redirect_to, it returns the view without executing the contents of the new action.
Let's take a look at the code again based on the explanation above.
shops_controller.rb
def new
@shop = Shop.new
end
def create
@shop = @owner.shops.new(shop_params)
if @shop.save
redirect_to :index
else
render :new
end
end
Since the new action is a new registration page for shop information, @ shop = Shop.new is defined in the action. (Create an empty instance) After this, the value entered in the form is passed as params, and it can be saved by successfully passing it as the information of @shop created this time by the create action.
If saving fails (in the case of else), it will be returned to the form again, but if ** redirect_to is used at this time, the new action will be executed again and @shop will become an empty instance again. ** **
On the other hand, if ** render is used, the new action is not used, so @shop will display the form view again while retaining the values of params received by the create action. ** **
haml:new.html.haml
.shop-wrapper
= form_with model: [@owner, @shop], html: {class: "shopform"}, local: true do |f|
The above is an excerpt of the view, but since the form receives @owner and @shop and displays the contents, if the @shop has contents, the contents will be displayed properly.
That's why you should use render when the create action fails.
By the way, when I set render this time, I first encountered the following error.
For a moment, this happened, but I set the following before_aciton for the new action.
shops_controller.rb
before_action :set_select_lists, only: [:new]
#Omission
private
def set_select_lists
@stations = Station.all.map {|station| [station.name, station.id] }.unshift(["Please choose from the following", nil])
@genres = Genre.all.map {|genre| [genre.name, genre.id] }.unshift(["Please choose from the following(Mandatory)", nil])
@marks = Mark.all.map {|mark| [mark.favorite, mark.id] }.unshift(["Please choose from the following(Mandatory)", nil])
end
I made a pull-down selection list in the form and set it with before_action.
As I wrote earlier, render does not go through the new action again, so ** before_action is not performed → There is no set value and an error occurs in the view display **.
In response to this, for a moment I thought, "If there is a variable that I have to define unexpectedly at @shop, can I use render?", But after thinking for a few minutes, I solved it immediately.
Rewrite the create action as follows.
shops_controller.rb
def create
@shop = @owner.shops.new(shop_params)
if @shop.save
else
set_select_lists
render :new
end
end
By performing set_select_lists that was done in before_action before rendering with create action, it is possible to render with the value also acquired (render only renders the new view after performing create action). Because it is displayed)
For a moment? ?? ?? But it wasn't such a complicated story.
Actually, the behavior of redirect_to and render was the place where I first touched programming with Progate and was the most troubled in about a month. When I noticed the difference here, I had the image that my understanding of MVC deepened at the same time.
I hope it will be helpful for beginners like me.
Recommended Posts