Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In what order is code in Embedded Ruby executed?

I've done a little bit of Ruby on Rails magic today which somehow works but I don't know how.

I'm writing an application which is supposed to have a navigation bar on top of every page, so I've written a partial which I render in my default layout:

views/layouts/application.html.erb:

...
<%= render 'shared/navbar' %>
<%= yield %>
...

But I wanted the link to the currently selected section to be highlighted. I decided that a series of if statements in every link would be ugly so I wrote a helper class or two which manage the links displayed on the navbar. I'll spare you details how they work, because they're trivial and irrelevant right now, but they're used like this:

views/shared/_navbar.html.erb:

...
<% navbar_manager.each_entry do |entry, active| %>
  <li <% if active %>class="active"<%end%>>
    <%= link_to entry.label, entry.url %>
  </li>
<% end %>
...

Now I only needed to let the navbar_manager know which entry is active. Manipulating the navigation bar is closely linked to the view so I decided against putting an appropriate code in the controller and to do it in a view file instead, like this:

views/foo/index.html.erb

<% navbar_manager.set_active_entry(:home) %>
...

A big surprise: it works. But now that I think of it: render 'shared/navbar' appears in the layout file before yield. So how does it happen that navbar_manager.set_active_entry is called before navbar_manager.each_entry? More generally: in what order is Embedded Ruby processed?

And in case that I'm simply lucky: is there a way to ensure the order I want?

I'm using Ruby 1.9.3 and Rails 3.2

like image 385
kamilk Avatar asked Dec 06 '25 02:12

kamilk


1 Answers

Sequence of code execution:

  1. On invoking foo#index, the corresponding view content is prepared from the views/foo/index.html.erbfile.

  2. The appropriate layout is processed. In this case, the views/layouts/application.html.erb file is picked up for processing.

  3. <%= render 'shared/navbar' %> statement in the layout makes it process the navbar partial. At this point, the view content to be displayed is already available (as part of step 1 above, so the navbar_manager marks the appropriate section for highlighting.

  4. <%= yield %> statement in the layout inserts the view content (processed in step 1 & step 3).

  5. The result of the complete processing is displayed.

log/development.log is a good resource to see how the various views & partials were executed.

Here is an example from one of my apps:

Started GET "/" for 127.0.0.1 at 2012-10-13 14:42:23 -0600
Processing by DashboardController#welcome as HTML   
User Load (0.8ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1  User Load (0.8ms)  SELECT `users`.* FROM `users`
Rendered dashboard/welcome.html.erb within layouts/application (2.6ms)
Rendered layouts/_navigation.html.erb (1.5ms)
Rendered layouts/_messages.html.erb (0.2ms)
SQL (1.4ms)  UPDATE `users` SET `updated_at` = '2012-10-13 20:42:23' WHERE `users`.`id` = 1
Completed 200 OK in 104ms (Views: 88.6ms | ActiveRecord: 3.1ms)

In this example, on invoking dashboard#welcome, the dashboard/welcome.html.erb view is processed first, and rendered within layouts/application; the layout also calls on navigation and messages partials before completing the rendering process.

like image 54
Prakash Murthy Avatar answered Dec 08 '25 16:12

Prakash Murthy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!