following his tutorial, the home page from Static-Pages Controller renders a partial_form:
<%= render 'shared/micropost_form' %>
StaticPagesController.rb
def home
@micropost = current_user.microposts.build #for the form_form
@feed_items = current_user.feed.paginate(page: params[:page])
end
Then, in the MicropostController.rb, an action for the partial micropost_form is declared:
class MicropostsController < ApplicationController
def create
@micropost = current_user.microposts.build(micropost_params)
if @micropost.save
flash[:success] = "Micropost created!"
redirect_to root_url
else
@feed_items = []
render 'static_pages/home'
end
end
end
Notice how, if micropost_form success, it gets redirected static_pages's index view, but, if failed, it renders static_pages home view (which also keeps the params in the form, so the user doesn't have to writype all the data), BUT, it needs to initialize static_pages's home controller instance variables (namely, feed_items).
Now, suppose StaticPages Controller's home has a long list of complex instances variables, how can MicropostController render (to keep form data upon failure) static_pages/home without creating that many instance variables?
note: this question is related to my previous one,but I wanted to understand this basic example before.
how can MicropostController render (to keep form data upon failure) static_pages/home without creating that many instance variables?
The simple answer is that it can't. In Rails you cannot redirect internally - which is an intentional design. What that means you cannot "patch through" a request to StaticPagesController#home
once the router has matched the request.
So in order for MicropostsController
to render static_pages/home
it needs to do the same job as StaticPagesController
.
However if setting up the instance variables is arduous or you want to avoid repetition then a good technique is to use a module to extract the shared functionality.
# app/controllers/concerns/feedable.rb
module Feedable
protected
def set_feed_items!
@feed_items = FeedItem.includes(:comments).all
end
end
class StaticPagesController < ActiveRecord::Base
include Feedable
# ...
before_action :set_feed_items!, only: [:home]
end
class MicropostsController < ApplicationController
include Feedable
# ...
def create
@micropost = current_user.microposts.build(micropost_params)
if @micropost.save
flash[:success] = "Micropost created!"
redirect_to root_url
else
set_feed_items!
render 'static_pages/home'
end
end
end