Add a selected class to links depending on id - ruby-on-rails

My question is very similar to this one : Changing Current Tab in Rails
I am trying to add a 'selected' class to my link regarding the id of my portfolios controller’s show action
Here is what I've tried:
<ul>
<% for portfolio in #portfolios %>
<li class="<%= controller.class == PortfoliosController and controller.action_name == 'show' and controller.params[:id] == portfolio.id ? 'selected' : '' %>"><%= link_to portfolio.name, portfolio %></li>
<% end %>
</ul>
But it seems that the following:
controller.params[:id] == portfolio.id
doesn't match correctly and I don't understand why..
Thanks for your help!

Beware: params are always strings.
So :
controller.params[:id].to_i == portfolio.id
SideNote: extract this kind of logic in helpers, it's much cleaner.

You might be comparing string and numerical values, which in Ruby are not considered equivalent. A conversion of one of or the other might help. In fact, if you roll this up in a helper method, it might make it a lot easier to follow:
def class_for_porfolio_entry(portfolio)
controller.class == PortfoliosController and
controller.action_name == 'show' and
controller.params[:id].to_i == portfolio.id ?
'selected' :
''
end
You've got a whole lot going on there, so you might want to look at ways of reducing the complexity, for instance using params instead:
def class_for_porfolio_entry(portfolio)
params[:controller] == 'portfolios' and
params[:action] == 'show' and
params[:id].to_i == portfolio.id ?
'selected' :
''
end
This could be simplified further if you had a boolean flag set in your controller that is later used as required, avoiding hard-coding something like this:
def class_for_porfolio_entry(portfolio)
if (#show_selected_portfolio and #portfolio.id == portfolio.id)
'selected'
else
''
end
end
This presumes you have an instance variable #portfolio, which is usually the case in any controller's show method, and that you will set #show_selected_portfolio to true in any controller method where this logic applies.

Related

How can I trigger an action from a different controller for dynamic content?

Im having a dynamic header depending on the view and action of the controller and it works fine with the actions in "welcomes_controller". But Im not able to trigger a action from a different controller in this case posts_controller.
How can I trigger it correctly? Thanks in advance.
<% if params[:action] == 'index' %>
<%= image_tag("header_background.jpg", alt: "header background", :class => "header_background") %>
<% elsif params[:action] == 'trading' %>
<%= image_tag("trading_background.jpg", alt: "trading background", :class => "header_background") %>
<% elseif ... HOW TO TRIGGER A ACTION FROM A DIFFERENT CONTROLLER? %>
<% end %>
There are two helpers easily availalbe for this: controller_name and action_name. You can use a combo of these for conditional rendering.
That said, personally I feel this is a lot of clutter for the view - I can't help feeling this would be better set elsewhere. In a very simple sense, you could add the following in your controllers:
def index
#header_image = "header_background.jpg"
end
def trading
#header_image = "trading_background.jpg"
end
And then in the view:
image_tag(#header_image, alt: #header_image, :class => "header_background")
Alternatively, you could follow a convention for your images:
image_tag("#{controller_name}/#{action_name}.jpg", alt: action_name, :class => "header_background")
Then ensure your header images are stored in a folder named after the controller, named after the relevant action.
I'd strongly lean towards the latter.
Update: one final option would be to define a helper that handles this, something like, in you view:
= header_image_tag
And somewhere within your /helpers folder something akin to:
def header_image_tag
image_path = case controller_name
when "controller_one"
"header_background.jpg" if action_name == "index"
"trading_background.jpg" if action_name == "trading"
when "controller_two"
# ...
else
"default_image.jpg"
end
image_tag image_path, alt: # ...etc
end
I think the helper has access to controller_name and action_name, though if not you could pass these as args to header_image_tag, or pass the request as an arg and access request.controller_name and request.action_name.
Let me know what you think and how you get on.
For this I use this code. This should work for what you are trying to achieve.
<% if controller.action_name.to_s == "index" %>
Also keep in mind, if you need to be more granular with the specific controller you want to target you can also add the controller name to the check.
<% if controller.controller_name.to_s == "posts" && controller.action_name.to_s == "index" %>

Rails: set default 'current' css class for navigation?

It's a problem after using the solution here
Best way to add "current" class to nav in Rails 3
def nav_link(link_text, link_path)
class_name = current_page?(link_path) ? 'current' : ''
content_tag(:li, :class => class_name) do
link_to link_text, link_path
end
end
For example, I have localhost/action1, and localhost/action2, each with a nav button.
It works great when user is in either page. In this situation, one of the button would have a 'current' css class.
But, if I set root_path to one of them, let's say is the /action1, so when user visit localhost, the button for action1 won't have a current class
How can I solve add the missing current css class when setting it as the root_path?
You can query the router itself to give you the controller and the action for the current path and just compare it to the current values from params.
def nav_link(text, path)
recognized = Rails.application.routes.recognize_path(path)
klass = "current" if recognized[:controller] == params[:controller] &&
recognized[:action] == params[:action]
content_tag(:li, class: klass) do
link_to(text, path)
end
end
You may wish to highlight your nav menu the following way - I am pretty sure this works irrespective setting the root path:
<ul>
<li class="<%= "current" if params[:controller] == "home" %>">Home</li>
<li class="<%= "current" if params[:controller] == "action1" %>">Action 1</li>
<li class="<%= "current" if params[:controller] == "action2" %>">Action 2</li>
</ul>
You may wish to replace
params[:controller]
with
params[:action]
depending on the level you wish to highlight. I have used this setup in a recent project and it worked for me. Good luck !

How to use variable from link

I have a link which reads
Collection
and another which reads
Wantlist
They link to the same view but produce different lists.
On that view page I want to be able to alter the text depending on if it is a Collection or Wantlist page. Something like this:
<% if :status == 'Got' %>collection<% elsif :status == 'Want' %>wantlist<% end %>
Obviously that doesn't work but after much experimentation I can't work out how to query which status was passed in the link. Is this possible?
You should be doing it like this
<% if params[:status] == 'Got' %>Collection
<% elsif params[:status] == 'Want' %>Wantlist
<% end %>
The parameters you pass to link_to get put into the params hash. Here, params[:status] is how you'd access it, either in the view or - better - in the controller.
link_to_if might be alternate solution for your question.
link_to_if(params[:status] == 'got', "Collection", user_collections_path(#user)) do
link_to "Wantlist" user_collections_path(#user)
end

RAILS or in if statement

I'm not sure how to use the OR in a view IF statement.
This doesn't work:
<% if current_user.employee.emptype.typename == "ADMIN" or "TECH" %>
Thanks!
Write something like this :
<% if current_user.employee.emptype.typename == "ADMIN" || current_user.employee.emptype.typename == "TECH" %>
Or better
<% if ['TECH', 'ADMIN'].include?(current_user.employee.emptype.typename) %>
Be careful with OR and AND keywords, they don't have same operators priority than && and ||
You can do this one of two ways. I prefer the first method.
<% if current_user.employee.emptype.typename.in?(["ADMIN", "TECH"]) %>
...or...
<% if current_user.employee.emptype.typename == "ADMIN" || current_user.employee.emptype.typename == "TECH" %>
That won't work, and it has nothing to do with views. In Ruby, all strings evaluate to true in if statements.
You have to check both values against the type name, like so:
if current_user.employee.emptype.type_name == "ADMIN" || current_user.employee.emptype.type_name == "TECH"
or check if it's contained within an array of valid types:
if ["ADMIN", "TECH"].include?(current_user.employee.emptype.type_name)
Please also see this article for a comparison of || and or in Ruby.

Best way to create a simple menu in a rails application

I have a simple menu that looks like this:
<ul class="menu">
<li class="active">Home</li>
<li class=""><%= link_to 'Feeds' , feeds_path %></li>
<li class=""><%= link_to 'Accounts' , accounts_path %></li>
</ul>
Class "active" is the style to mark my current page.
I have two questions:
1. How do I "tell" the app what page I am on and ask it to "change" the class to active?
2. Is there a better way to create this menu (maybe driven by the controller or a db table)?
I realize this is a newbie question, but I have been thinking about this for a few days now, have read some tutorials, but none of them really click.
Thanks for your help.
I use the method current_page? to set my active link. It takes a path as its parameter. I create a hash of link texts and paths and iterate over it printing the links. That way I only have to call current_page? one time.
There are gems that can help you, though. Look through these: https://www.ruby-toolbox.com/categories/rails_menu_builders
I have done this recently in ApplicationHelper:
def nav_links
items = [home_link, about_me_link, contact_link]
content_tag :ul, :class => "nav" do
items.collect { |item| concat item}
end
end
def home_link
nav_item_active_if(!#article || #article.type.nil?) do
link_to "Home", root_path
end
end
def about_me_link
nav_item_active_if(#article && #article.type == "About") do
link_to "About Me", article_path(About.first)
end
end
def contact_link
nav_item_active_if(#article && #article.type == "Contact") do
link_to "Contact", article_path(Contact.first)
end
end
def nav_item_active_if(condition, attributes = {}, &block)
if condition
attributes["class"] = "active"
end
content_tag(:li, attributes, &block)
end
In your view you can simply call:
<%= nav_links %>
You can maybe use it as an example.
Not a perfect solution, but you could do the following.
create 3 variables:
#homeActive = ""
#feedsActive = ""
#accountsActive = ""
In the code you provided, set the class to each variable corresponding with name.
<li class=#homeActive>Home</li>
Now in your controller under the home method lets say, set #homeActive = "active", and the other two to "". Repeat for the other methods and this should work.
I used a bunch of 'if's and the current_page? method.
It's ugly but it worked, if someone has a better idea how to do this, I will be happy to learn about it.
if current_page? (root_path)
content_tag(:li , link_to('Home' , root_path), :class => "active")
else
content_tag(:li , link_to('Home' , root_path))
end

Resources