Can I get the name of the current controller in the view? - ruby-on-rails

Is there a way to figure out what the current controller is from within the view?
For an example of why I would want to know this: if several controllers share the same layout, I may have a part in the layout ERB file where I want to highlight the current page's menu item based on the controller.
Maybe that is a bad approach. If so, what is the more preferred way to do this?
I'm interested to know about getting the name of the current controller either way, though.
(Obviously I could put something like #controller_name = 'users' in each controller; but that seems like the sort of thing Rails would've already done behind the scenes. So I'm just wondering if there's a built-in way.)

controller_name holds the name of the controller used to serve the current view.

Use controller.controller_name
In the Rails Guides, it says:
The params hash will always contain the :controller and :action keys, but you should use the methods controller_name and action_name instead to access these values
ActionController Parameters
So let's say you have a CSS class active , that should be inserted in any link whose page is currently open (maybe so that you can style differently) . If you have a static_pages controller with an about action, you can then highlight the link like so in your view:
<li>
<a class='button <% if controller.controller_name == "static_pages" && controller.action_name == "about" %>active<%end%>' href="/about">
About Us
</a>
</li>

#to get controller name:
<%= controller.controller_name %>
#=> 'users'
#to get action name, it is the method:
<%= controller.action_name %>
#=> 'show'
#to get id information:
<%= ActionController::Routing::Routes.recognize_path(request.url)[:id] %>
#=> '23'
# or display nicely
<%= debug Rails.application.routes.recognize_path(request.url) %>
reference

controller_path holds the path of the controller used to serve the current view. (ie: admin/settings).
and
controller_name holds the name of the controller used to serve the current view. (ie: settings).

If you want to use all stylesheet in your app just adds this line in application.html.erb. Insert it inside <head> tag
<%= stylesheet_link_tag controller.controller_name , media: 'all', 'data-turbolinks-track': 'reload' %>
Also, to specify the same class CSS on a different controller
Add this line in the body of application.html.erb
<body class="<%= controller.controller_name %>-<%= controller.action_name %>">
So, now for example I would like to change the p tag in 'home' controller and 'index' action.
Inside index.scss file adds.
.nameOfController-nameOfAction <tag> { }
.home-index p {
color:red !important;
}

Related

Difference between using provide() and assigning a variable for page titles in Rails?

Could someone explain why it is preferred when embedding ruby for things like page titles to use
<% provide(:title, 'Help') %>
and then using
<%= yield :title %>
rather than jus using a variable:
<% title = 'Help' %>
<%= title %>
I'm assuming its to do with the fact that you can yield before you have called provide() but if that is the case why is it not possible to call the variable before defining it?
Thanks :)
If you want to simply render a variable in the view, the second method will do.
However, provide and yield offer a various ways to build the rendered content. For, example, you pass instance variable like #posts which you may already assign a variable after a complicated algorithm, which you will not do in a view template.
http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html
http://guides.rubyonrails.org/layouts_and_rendering.html#understanding-yield
provide (or content_for) are used to pass some elements from the view to the layout, so if you have layout:
<html>
<head>
<title><%= yield :title %></title>
</head>
<body>
<%= yield %>
</body>
</html>
Than in all the views, you can set the content for title with provide or content for. Local variables cannot do this, as they only live in a given view.
provide stores a block of markup in an identifier for later use. In this case, 'Help' in the symbol :title. The provide is enclosed in <% %> to indicate it is executing this code and not printing out in the view.
yield in this case just spits that block back out. The yield is enclosed in <%= %> to indicate it is being printed out into the view.
Think of it as setting a variable and printing out a variable.
See: http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#method-i-provide for more information. Note that provide is really a wrapper for content_for so that's where the good stuff is in that link.

Specifying url in rails 3

i am totally new to rails programming... i used the request.path to get the current url and display it in all my views by specifying it in applications.html.erb. It is returning the entire path and i want to display it as a link... so i use
link_to to specify it as url..now here is what i want to do.. the url returned will be in the format path1/path2/path3..... i want to display it as path1>path2>path3 and as a link such that when the user clicks path1, it should take him to path 1 and so on...
this is the code i gave in html.erb file
but i get an error that says undefined method.... what should i do to accomplish that??
You could split the request.path on / and then build up the various links, but that could get really cluttered for deeply nested paths. I think a better approach would be to use something like breadcrumbs_on_rails and declare your breadcrumbs explicitly and render them in a partial or helper method. I think you could also use some Rails filter magic to have action names breadcrumbed automatically, but making the breadcrumbs explicit forces you to think about your site and your users more than programmatically vomiting out a string of links of unknown length.
You can do like this:
<% path = request.path %>
<% links = path.split('/') %>
<% ll="/" %>
<% links.each do |l| %>
<% ll += (l+'/') %>
<%= link_to l,ll %> >
<% end %>

Loading a nav bar when in a specific controller rails

I am having a bit of trouble in rails.
What I want to do is to display some extra links in the application layout when a specific controller is in use. How do I do this?
I am loading the pages dynamically using jquery and I tried using <%if controller_name == "foo"%> then do some magic, without any success.
If somebody could point me in the right direction or even a jquery-rails rendering tutorial that would be great.
Thanks.
Check out the content_for magic provided by Rails. It allows you to specify something like this in your application layout:
<%= yield :header %>
And then in your individual templates do something like this:
<% content_for :header do %>
Content I want put in the header
<% end %>
Which basically results in the content inside the content_for block being captured and rendered at the point of the yield statement. So, you can specify that in the templates for your controller.

Dynamic body id

How can I set ID for body tag in Rails?
<body id="login">
I don't find any of the solutions particularly elegant or flexible. Add a body_class method to application_helper.rb:
def body_class
[controller_name, action_name].join('-')
end
..in layout:
<body class="<%= body_class %>">
#e.g output: <body class="articles-show">
You can then refine the above helper to dynamically inject other identifiers such as modules.
You should use content_for tag here.
In your application layout:
<html>
...
<%= yield :body || "<body>" %>
...
</body>
</html>
And then from any view you can call this:
<% content_for :body do %>
<body id='login'>
<% end %>
That's it :)
You can set a variable #body_id in your action inside a controller or in your view and you can use it in your layout.
So for example if you have an action index you can add this code in your controller:
def index
#body_id = "myid"
end
or in your view index.html.erb as:
<% #body_id = "myid" %>
Then in your layout, I suppose application.html.erb you can add:
<body<%= " id=#{#body_id}" if #body_id %>> # no quotes around #{} are needed ;)
Be careful! The following will not work in rails 3.1
<%= yield :body || "<body>" %>
It might look like it works but if you view source you'll notice your body tag is missing unless you override it. Most browsers will work around a missing body tag.
The correct way to do is as follows
<%= content_for?(:body) ? yield(:body) : raw("<body>") %>
Be careful, you shouldn't be setting view data in your controllers, as some of the above posts have recommended. It breaks the MVC pattern, and creates needless objects that won't be used anywhere but HTML versions of your pages.
Another thing to be aware of is increased risk when you assign your body tag inside a logic block - why risk the page not outputting your body tag (breaking the page) if you don't have to? The example above:
<%= yield :body || "<body>" %>
Someone may not entirely understand your meaning in a child partial, and you're just increasing the duplication of the body tag, meaning you have more places to look if somebody doesn't terminate the tag, etc. There's no need for this risk. A more sensible solution is to yield just the class. HAML will allow you to supply optional class elements, eg:
%body{ id: yield(:body_id), class: yield(:body_class) }
And then set those values in your view:
- content_for(:body_class) { 'dashboard business' }
I'd love a solution that allows for multiple partials to add classes to the one yield block, but haven't found a non-hacky way to do this yet.
<body id="<%= #bodyid %>">
and in your controller, you can set this
#bodyid = "login"
U didnt really explain what exactly u need to do then, my first guess is:
<body id="<%= #body_id %>">

Instance variables in layout

I am fairly new to rails so I apologize if I am using the wrong terminology.
I have a model Menuitem that I would like to display the contents of in a layout. How does one go about passing an instance variable into a layout?
I was looking for a layout helper of some sort but I was unable to find anything. I was also looking at defining the instance variable in the application controller to access it in the layout, would this work? If so what is the best way to go about doing it?
Thanks!
The usual way of passing variables up from the view into the parent layout is to use the content_for method. (This answer is a copy + paste from a similar answer I posted at this question)
The normal view content gets rendered automatically into the yield call without an argument in the layout. But you can also put other placeholder content in by using yield with a symbol argument, and specifying that content from the view with content_for.
app/views/layouts/posts_layout.html.erb
<html>
<head>
<title>My awesome site</title>
</head>
<body>
<div id="someMenuStructureHere">
<%= yield(:menu_items) %> <!-- display content passed from view for menu_items -->
</div>
<%= yield %> <!-- display main view content -->
</body>
</html>
app/views/posts/index.html.erb
<%= content_for :menu_items, some_helper_to_generate_menu %>
<h1>Here is you page content</h1>
Two things I would note. First, you probably don't want to be doing this query every time you render any page in your application. You definitely want to cache your MenuItems. Second, it might be helpful to put a convenience method on MenuItems class to cache this value. So, if I define a method
def MenuItem.all_for_menu
##all_for_menu ||= MenuItem.find(:all) #returns value if exists, or initializes it
end
I can call MenuItem.all_for_menu in my layout and get all the menu items. When ever you add a new one or edit one, you'd have to invalidate that.
Another caching approach would be to put the data in a partial and cache that fragment using the standard caching call:
<% cache(:controller => "menu_items",
:action => "list",
:action_suffix => "all_menu_items") do %>
<%= render :partial => "menu", :collection => MenuItem.all_for_menu %>
<% end %>
You can then expire that fragment by calling:
expire_fragment(:controller => "menu_items", :action => "list", :action_suffix => "all_menu_items")
Any instance variables defined in the controllers are auto-magically available in your views. If you are expecting an instance variable in your layout for all actions, you may want to consider defining the instance variable in a before_filter or encapsulating it in a controller method and using helper_method to make it accessible in your views.
It really depends on what you want to do with the model. I'll just guess, and you tell me what you need different to understand better how to do this. This code would work only if your MenuItem model has a field named name.
In the controller:
# Use whatever action you are currently displaying
def index
#menu_items = MenuItem.all
end
In the index.html.erb view file:
<ul id="menu">
<% #menu_items.each do |menu_item| %>
<%= h menu_item.name %>
<% end %>
</ul>
Obviously if this was a real menu, there would be hyperlinks there too :)
items_controller.rb (or something)
def show
#menu_item = MenuItem.find(params[:id])
end
In the view show.html.erb:
<%= #menu_item.name %>

Resources