ruby on rails yield to new ruby layout - ruby-on-rails

In a page I'm working on , i have overridden the application.html.erb because the layout is complex for pages like signup / login and some others.
So i created a new layout and I'm rendering it through the controller's action.
def new
render :layout => '../path/newlayout.html.erb'
...
end
Question is , can i use another layout as a "secondary" application.html.erb?
Can i <%yield%> to the newlayout.html.erb ?

As i searched further , i stumbled upon partials!
just create a file with the naming convention "_login.html.erb" in the same folder as your newlayout.html.erb
and just use <%= render 'login' %>
in the same position and way that you'd use <%yield%>

Related

Render :layout is searching for partial instead of layout

I understand this is a bad idea, but from what I've seen in ApplicationControllers, using:
render :layout => "something" ...
Should render using a layout located at views/layouts/something.html.erb
However, when I am making this call from inside of a view, it errors out with:
Missing partial my_controller_name/something with ...
Searched in:
* "{path here}/app/views"
Which seems to me its looking for a partial, instead of a layout as I specified. Does anyone know what is going on with that?
A sufficient example small enough to reproduce it:
<%= render :layout => 'something' do %>
<div>Hello</div>
<% end %>
This is all under Rails vs 4.0.2
render works differently in controllers than it does in views. In controllers, it's primarily for rendering action templates, while in views, it's primarily for rendering partial templates. When you want to render a specific layout for an action, you have a few options, but all of them are in the controller.
If you want every action in a particular controller to use that layout, you can either specify layout 'something' in that controller (usually near the top) or for a ApplesController, you can create a new layout in app/views/layouts/apples.html.erb and this will automatically be used as the default layout for the ApplesController.
If you want just a single action in a controller to use that layout, you can use your render layout: 'something' inside of a controller action, where the action to render is implied to be the current action.
Links from the Rails docs:
Action Rendering
Partial Rendering
Nested Layouts

Ruby on Rails views names dependences

May be my question it's a little weird for RoR developers, but i'm new in Ruby on Rails, and i only discover this world now - there is some dependencies in views names and definitions in controller?
If i have, for example, view called "parse-public-profile.html.erb" , should i add in controller definition with exactly this name? i mean "def parse-public-profile ... end"
I know, that this is basic, but simply i try to understand how controller knows, what views i have now; what i should change, if i will add/change-name of view, or how to define view, if in my "views" folder, i have another folder, for ex. "clients"
Thanks!
Rails follows REST this means methods as index, show, edit, update, destroy etc. are very common in an Rails controller. When you have a custom action(method) however on your controller Rails will look for the corresponding view file, so for example:
class UsersController < ApplicationController
def another_action
end
end
will try to render: app/views/users/another_action.html.erb
There is also the concept of partials which are normally called within a view file f.e. in users/index.html.erb
<% render :partial => 'form' %>
will try to render: app/views/users/_form.html.erb (note the _)
An in depth explanation can be found in the Rails guides
You can also use:
def index
render :template => "users/parse-public-profile"
end
The :template over rides the default file that Rails would have rendered.
For more info, see the Rails Guide on Layouts and Rendering at http://guides.rubyonrails.org/layouts_and_rendering.html.

Rails implicit render in templates from multiple controllers

I have code like render #posts to render my posts collection in an index template which the PostsController renders.
Now I have an Admin::PostsController that also should render the collection but when my posts controller renders #posts it looks for the admin/posts/_post.html.erb partial. Do I now have to write the partial path explicity? Is this feature by design or a bug? It doesn't seem to make sense.
Yes, you need to supply the path explicitly. And yes, this is by design.
It actually makes sense because Rails is a MVC framework and if you create a controller under a different namespace one would expect separate views for that controller too. Think about convenience, if you wanted to quickly bootstrap an application with a few simple commands, an application where there's a public view of posts and an admin view where all of the admin goodies for editing are, you would EXPECT to have a different directory to store all that admin views.
render #posts is a shortcut for a longer method signature.
In case of PostsController, it is a short cut for render :partial => "post", :collection => #posts; the partial is _post.html.erb and it is expected to be in app/views/posts folder.
In case of Admin::PostsController, it is a short cut for render :partial => "admin#post/post", :collection => #posts; the partial is _post.html.erb, and it is expected to be in app/views/admin/posts folder.
If you want a different partial to be used, you should specify it explicitly.
See the Rendering Collections section of Rails Guides page on Layouts & Rendering for detailed explanation.

Multiple Level Nested Layout in Rails 3

I have an application with a global application layout file application.html.haml. I then have multiple "controller stacks": for our main site, our admin portal, and our business site. For each of these, controllers are within a module and all inherit from the same BaseController. Each stack has it's own layout file. Within the stack, some controllers have layout files as well.
I would like all views (unless otherwise specified) to render inside multiple levels of nested layouts : application, "stack", "controller".
For example, for the Site::BlogController#show action, I'd like rails to render:
/site/blog/show.html.haml inside /layouts/site/blog.html.haml inside /layouts/site.html.haml inside /layouts/application.html.haml
I am having difficulty understanding how to insert /layouts/site.html.haml into the stack. It appears as though automatically, rails will render the action inside the controller layout inside the application layout, however, I can't see how to "insert" layouts into the render stack.
Any help is greatly appreciated, however, I have read all the rails guides to no avail, so a link to http://guides.rubyonrails.org/layouts_and_rendering.html#using-nested-layouts will not really be helpful.
I reread the link i posted ( http://guides.rubyonrails.org/layouts_and_rendering.html#using-nested-layouts ) and realized I missed a key detail.
<%= render :file => 'layouts/application' %>
so, in Site::BaseController I have a call to layout 'site' and in /layouts/site.html.haml I have
= content_for :footer do
-#Content for footer
= render :file => 'layouts/application'
Then in Site::BlogController which extends Site::BaseController I have layout 'site/blog' and in /layouts/site/blog.html.haml I have
=content_for :header do
%h1 HELLO WORLD!
= render :file => 'layouts/site'
This then renders the layouts nested as described in the question. Sorry for missing this in my question. I should've read closer.
if you create a helper like this:
# renders a given haml block inside a layout
def inside_layout(layout = 'application', &block)
render :inline => capture_haml(&block), :layout => "layouts/#{layout}"
end
then you can define sublayout like this:
= inside_layout do
# nested layout html here
= yield
these layouts can be used like normal layouts.
more: http://www.requests.ch/blog/2013/10/30/combine-restful-rails-with-nested-layouts/
I've done similar, but only used 1 level of sublayouts. Can easily be tweaked to allow multiple levels.
In controllers/application_controller.rb:
def sub_layout
nil
end
In controller (for example blog_controller.rb):
def sub_layout
"blog"
end
In layouts/application.html.erb rather than <%=yield%>:
<%= controller.sub_layout ? (render :partial => "/layouts/#{controller.sub_layout}") : yield %>
Make a partial layouts/_blog.html.erb:
...code
<%=yield%>
...code
Repeat for other controller & sub layouts.
EDIT:
If you need to do this on a per-action basis:
def sub_layout
{
'index' => 'blog',
'new' => 'other_sub_layout',
'edit' => 'asdf'
}[action_name]
end
I guess the simplest way to do it is by adding this line of code in the parent of a nested layout:
((render "layouts/#{controller_name}" rescue nil)|| yield )
you could add as many nested layouts as you want by only changing the path directory of the next layout to be rendered.
note: make sure your nested layout is named _layoutname.whatever and that your nested layout has a yield inside
You can create a partial with a yield in it.
_my_sub_layout.html.erb:
<h3>I'm a sub layout and here's my content:</h3>
<%= yield %>
In some other view or even in your main layout application.html.erb render the partial as a layout:
<%= render layout: 'my_sub_layout' do %>
<p>I'm the sub layout's content</p>
<% end %>

Where to put partials shared by the whole application in Rails?

Where would I go about placing partial files shared by more than one model?
I have a page called crop.html.erb that is used for one model - Photo.
Now I would like to use it for another model called User as well.
I could copy and paste the code but that's not very DRY, so I figured I would move it into a partial.
Since it's shared between two models - where would I place that partial?
Thanks!
The Rails convention is to put shared partials in /app/views/shared.
Update
Layout inheritance is now in the guides under layout and rendering
Template inheritance works similarly.
Rails 3.1 and following versions implement template inheritance, so I think the correct place for shared partials is now /app/views/application/, say you are in products#index you can do the following:
-# products#index
= render #products.presence || 'empty'
-# /app/views/application/_empty.html.haml
There are no items
btw it's application because the connection is the controller inheritance, so this assumes ProductsController < ApplicationController
This way if you implement /app/views/products/_empty.html.haml that will be taken, the above is a fallback for all the missing partials, and I can't check right now, but I think even for the template itself...
Railscast: template inheritance!
TL;DR
Rails 3.1, Rails 4, Rails 5 and whatever comes next
app/views/application
The engine searches this path automatically if the view is not found in the controller path.
Rails 3 and prior
app/views/shared
The engine does NOT search this path automatically.
Long story
Rails 3 (and prior version) have no default location for storing shared views.
The unofficial convention is to store shared views in app/views/shared. Wherever you'd end up storing them though, you have to specify the path
# render app/views/shared/menu.html.erb
<%= render :partial => "shared/menu" %>
This suggestion was popularized by Agile Web Development with Rails.
Rails 3.1 introduces an official standard for where to store shared views:
app/views/application
Thanks to this standard, the engine now automatically looks for templates in app/views/application. As a result, you don't have to use the full path anymore.
Those curious can follow here the thought process behind this decision.
Old syntax
# render app/views/application/menu.html.erb
# unless menu.html.erb is found in appp/views/my_controller
<%= render :partial => "menu" %>
New syntax
# render app/views/application/menu.html.erb
# unless menu.html.erb is found in appp/views/my_controller
<%= render partial: "menu" %>
Of course, you can still place your shared views wherever you want and reference them by path
<%= render :partial => "my_own_special_shared_folder/menu" %>
Unless you have a very good reason to do this though, please stick to the new standard and store your shared views in app/views/application.
The Rails View uses app/views/layouts for shared partials like header and footer, but the Ruby on Rails Guide uses app/views/shared in an example. I guess it comes down to personal preference. I would use layouts for high-level stuff like a main nav or a footer, but shared for more narrow controller-level stuff like a form.
I general have a shared folder in my views that contains commonly used partials.
I arrived here in 2021 (rails 6) and got confused by the answers (many different ways).
I asked some senior rails developers what they'd do and they also gave me 2 different answers.
But TL;DR
Create a folder called 'shared' or 'application' inside your views folder (e.g. app/views/shared or app/views/application.
Then simply move the partial there, and access it with either
<%= render partial: 'shared/socials' %>
# or
<%= render partial: 'application/socials' %>
or even simpler
<%= render 'shared/socials' %>
# or
<%= render 'application/socials' %>
It doesn't matter where you put them. You can render any partial at any arbitrary location by providing the file's path to render - it doesn't need to be associated with the controller that's rendering it. I use a directory simply called partials under the view directory, and call partials in it like this:
render :partial => 'partials/mypartial'

Resources