Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I need `render layout: false` in my Rails controller action?

I'm use the remote: true idiom from the Working with Javascript in Rails guide:

# new.html.slim
= form_for @thing, remote: true do |f|
  f.text_field :whatever
  f.submit 'Submit'

# thing_controller.rb
layout 'foo'

def create
end

# create.js.erb
alert('foobar')

This fails, because create.js.erb is for some reason rendered inside the 'foo' layout and returned as html, not javascript, despite the fact that the request is correctly processed as Javascript:

Processing by ThingsController#create as JS
  Parameters: {"utf8"=>"✓", "commit"=>"Submit"}
  Rendered things/create.js.erb (0.6ms)

(The problem is the same whether or not I have an explicit respond_to format block in the controller action.)

As noted here and here, including render layout: false in the controller action fixes the problem:

# thing_controller.rb
layout 'foo'

def create
  render layout: false
end

But why do I need render layout: false here? Why is Rails rendering the javascript inside an html layout? I'm particularly puzzled because I've used the same idiom in several other places and never run into this problem before.

like image 345
Sasgorilla Avatar asked Dec 03 '16 02:12

Sasgorilla


People also ask

How can you tell Rails to render without a layout?

By default, if you use the :plain option, the text is rendered without using the current layout. If you want Rails to put the text into the current layout, you need to add the layout: true option and use the . text. erb extension for the layout file.

What does render do in Rails?

Rendering is the ultimate goal of your Ruby on Rails application. You render a view, usually . html. erb files, which contain a mix of HMTL & Ruby code.

What is a layout template in Rails?

In Rails, layouts are pieces that fit together (for example header, footer, menus, etc) to make a complete view. An application may have as many layouts as you want. Rails use convention over configuration to automatically pair up layouts with respective controllers having same name.

What does render JSON do in Rails?

Rails has built-in support for converting objects to JSON and rendering that JSON back to the browser: render json: @product. You don't need to call to_json on the object that you want to render. If you use the :json option, render will automatically call to_json for you.


2 Answers

The action controller in rails responds with HTML response by default (unless otherwise instructed).

layout 'foo' enforces the use of app/views/layouts/foo.html.slim as the template for your view files. so all the views associated with the actions on your thing_controller.rb are rendered inside the layout 'foo' and the final HTML generated with layout 'foo' and view file create.html.slim is sent back to the client by default.

If you want to enforce returning js template instead of HTML file, you need to explicitly define it in your action like this:

# thing_controller.rb
layout 'foo'

def create
  respond_to do |format|
    # use :template if your view file is somewhere else than rails convention
    format.js {
      :template => "somewhere/create.js.erb", 
      :layout => false
    }
  end
end

where render layout: false enforces rails NOT TO look for any layout file to wrap your view file (i.e the rails engine just processes create.js.erb file without HTML headers defined on your 'foo' layout) for sending it back to client.

like image 123
sa77 Avatar answered Oct 10 '22 03:10

sa77


With most of the options to render, the rendered content is displayed as part of the current layout.

You can use the :layout option to tell Rails to use a specific file as the layout for the current action:

 render layout: false

You’ve heard that Rails promotes “convention over configuration.” Default rendering is an excellent example of this. By default, controllers in Rails automatically render views with names that correspond to actions

You can use it to avoid the render false for the particular action which may affect you in code latency

 layout false
 layout 'foo', :except => :create
like image 45
Tushar Pal Avatar answered Oct 10 '22 04:10

Tushar Pal