Buy my course: Security for Rails Developers.
Hi there,
This week I want to show you how I add static pages in a Rails application, since I just did this recently.
I like to put all of them into the same controller so they are nicely separated, so I generate a new controller called ‘StaticPagesController`. Then I add my routes:
get '/privacy-policy', to: 'static_pages#privacy'
get '/terms', to: 'static_pages#terms'
And I create my views in app/views/static_pages/
.
Since Rails 7.0, I can omit the controller methods, Rails will render the appropriate views regardless.
That’s it. This would be today’s Rails trick, but since it would be super short, let’s dig into how Rails renders the views without the controller methods being defined.
As I found out, this feature called “implicit rendering”. What happens is, when Action Controller is processing a request, it is trying to find the appropriate method for the action it receives from the router:
# action_pack/lib/abstract_controller/base.rb
def method_for_action(action_name)
if action_method?(action_name)
action_name
elsif respond_to?(:action_missing, true)
"_handle_action_missing"
end
end
This method is overridden in action_pack/lib/action_controller/metal.rb
to check if there is any template available for the action, and if so, it renders the template, of not, it just renders a head: :no_content
:
# action_pack/lib/action_controller/metal.rb
def method_for_action(action_name)
super || if template_exists?(action_name.to_s, _prefixes)
"default_render"
end
end
def default_render
if template_exists?(action_name.to_s, _prefixes, variants: request.variant)
render
elsif any_templates?(action_name.to_s, _prefixes)
message = "#{self.class.name}\##{action_name} is missing a template " \
"for this request format and variant.\n" \
"\nrequest.formats: #{request.formats.map(&:to_s).inspect}" \
"\nrequest.variant: #{request.variant.inspect}"
raise ActionController::UnknownFormat, message
elsif interactive_browser_request?
message = "#{self.class.name}\##{action_name} is missing a template for request formats: #{request.formats.map(&:to_s).join(',')}"
raise ActionController::MissingExactTemplate.new(message, self.class, action_name)
else
logger.info "No template found for #{self.class.name}\##{action_name}, rendering head :no_content" if logger
super
end
end
Now you know how Rails can render implicit actions in your controller. Until next time!
Did you enjoy reading this? Sign up to the Rails Tricks newsletter for more content like this!
Or follow me on Twitter
I run an indie startup providing vulnerability scanning for your Ruby on Rails app.
It is free to use at the moment, and I am grateful for any feedback about it.If you would like to give it a spin, you can do it here: Vulnerability Scanning for your Ruby on Rails app!