How do i add an active class to a dynamic link? - ruby-on-rails

I have a sidebar that holds a list of posts. I need the corresponding post on my sidebar to have an active class. What i have currently does not work so what is the best way to do this?
def is_active?(path)
current_page?(path) ? "active" : ""
end
<% #posts.each do |post| %>
<%= link_to post.title, post, class: is_active?(posts_path) %>
<% end %>

As I said in my comment, methods ending by ? should return a boolean value. If you decide to go against the convention this will make things harder for us.
I suggest you actually use an active_link_to like it is explained in that question.
However the main problem was that you didn't generate the URL properly for each post :
is_active?(posts_path)
The posts_path is the path to the index and not the individual post resource. You should use something like post_path(post)
You want to do something like this :
First your is_active? method, because it has a ? should return a boolean
def is_active?(path)
current_page?(path)
end
Then you can use it this way (you need to get the URL of the post using the post_path(post) helper)
<% #posts.each do |post| %>
<%= link_to post.title, post, class: ('active' if is_active?(post_path(post))) %>
<% end %>
EDIT : because is_active? does the same thing as current_page? you should simply replace the is_active? code by an alias declaration
alias :is_active? current_page?

I had to develop such a solution some years before. I implemented the following as helper methods to detect an active link. Be aware that this is not the best solution I think. I had to provide a full url. Fell free to edit the code to use a path or a parameter hash instead.
# Returns true or false if the page is displayed that belongs to the given url.
def link_selected?(url)
request_method = request.method.to_sym
begin
url_params = Revolution::Application.routes.recognize_path(
url, {:method=>request_method}
)
rescue Exception => e
{}
end
begin
request_params = Revolution::Application.routes.recognize_path(
request.url, {:method=>request_method}
)
rescue
{}
end
return true if url_params == request_params
return false
end
def is_active?(url)
return link_selected?(url) ? 'active' : nil
end

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" %>

how to pass a static string into a link_to as an argument in ruby on rails view

I have a modified string. Here is the code where I do the changes:
<% device=#devices.find(1) %>
<% #string ="" %>
<% device.attributes.keys.each do |attribute| %>
<% next if attribute == 'id' || attribute== 'token' || attribute =='carrier' || attribute =='segment' || attribute =='created_at' || attribute =='updated_at' %>
<% x=attribute.to_s %>
<%#string = #string + x +":device."+x +"," %>
<% end %>
<% #string %>
<% #arguments= #string.gsub(/\,$/, '') %>
<%= #arguments %>
It works and it is in the right format to put it in the link_to helper.
This is how I first wrote the link_to helper, and it worked.
<td><%= link_to 'Send notification', controller: "home", action: "send_notification", token: device.token, first_name: device.first_name, last_name: device.last_name %></td>
I tried to change it like this:
<td><%= link_to 'Send notification', controller: "home", action: "send_notification", token: device.token, #arguments %></td>
or #{arguments}
But it doesn't work. I even created another variable without # but it didn't work either.
How can I paste my arguments?
This is my arguments string btw:
"first_name:device.first_name,last_name:device.last_name,nickname:device.nickname"
What should I change?
Another simple newbie question; I feel like I am doing most of the coding in the wrong place. Is it right thatI write so many things in view?
What is the best approach in Ruby on Rails programming?
Thanks in advance
I'll answer your code question first and leave the string question for last.
First, some of your code is in the wrong places. Rails expects you to retrieve the database record in the controller and then pass it into the view. Something like:
devices_controller.rb
class DevicesController < InheritedResources::Base
def send_notification
#device = Device.find(id)
end
....
Then in your show view (app/views/devices/send_notification.html.erb) you can use the #device object and access its attributes like #device.first_name and #device.last_name and print them out or whatever.
Second, the link_to method needs a Hash of arguments, not a string. But either way, there is no use case in Rails that I can think of for passing the entire set of object attributes into the link_to method. It's just generating a link. You probably don't really want it to be littering your html elements with every one one of your record attributes.
All you need to do if you want access to that data when the user clicks the link is to pass the id in as a url element and then have the controller at the other end of the link (in your case Home?) catch the id and create an object out of it there.
I'd suggest taking a good look at: http://guides.rubyonrails.org/

Building a selectbox or filter in Rails

Hi maybe this is a fool question, but i really try to look couldnt find any relevant info, (maybe cause i dont know where exactly to start looking at) ..
I need to build a select box with options so the user can "filter" by the candidate.poisition value i have. at this moment the view has this code..
I was thingin on using :params, to post them in URL (i have always do php, im doing rails cause my task now is to insert a design, i achieve everything, just missing a selectbox filter)
Anyway.. here is the code.. wich is pretty simple
<% #candidates.each do |candidate| %>
<% if (candidate.active == true) && (candidate.position.present?) %>
All the html code with info.. like
<%= candidate.name %> : <%= candidate.position? ? t('generales.'+candidate.position) : t('activerecord.models.elite') %>
<% end %>
<% end %>
how can i make this , as im really a noob in Rails, im a regular user on PHP not even really good jaja, pls, i hope someone can give me a hand on this.
Can I use something like this : How to do a LIKE query in Arel and Rails?
Like candidates.where("position like '%?%'", params[:query]).to_sql
Also how can i build the Post as you do in PHP , no idea, to change the position that you want to filter.
Model Candidate.rb just have this inside :S
class Candidate < ActiveRecord::Base
end
Basically you're right. Here is improved code:
<% #candidates.each do |candidate| %>
<% if candidate.active && candidate.position.present? %>
<%= candidate.name %> : <%= t("generales.#{candidate.position}") %>
<% end %>
<% end %>
Update per request in comments:
Use code like this in controller:
if params[:position] == 'red'
#candidates = #candidates.where(position: 'red')
elsif params[:position] == 'blue'
#candidates = #candidates.where(position: 'blue')
else
#candidates = Candidate.all
end
and build html form that will pass parameter position.
or you can use https://github.com/activerecord-hackery/ransack

Rendering rails partial with dynamic variables

I'm trying to render a partial based on the taxon the user is inside. In my application.html.erb layout I have the following line of code:
<%= render 'spree/shared/women_subnav' if #enable_women %>
In the taxons controller, inside the show method, I have:
#taxon_id = params[:id].split('/').first
And in taxons#show I have:
<% if #taxon_id == params[:id].split('/').first %>
<%= "#enable_#{#taxon_id}" = true %>
<% end %>
When I run this I get a SyntaxError. But in taxons#show If I just enter:
<% if #taxon_id == params[:id].split('/').first %>
<%= "#enable_#{#taxon_id}" %>
<% end %>
without the '= true' then the page renders, outputting '#enable_women'. So I know it's getting the correct variable, I just need that variable to be set to true. What am I missing?
Thanks so much.
First of all I would like to give you some heads-up:
calling first on a user submittable input is not a great idea (what if I submit ?id=, it would return nil) also non utf-8 encoding will crash your app such as: ?id=Ж
Controllers are beast! I see you are setting the value of a true/false instance_variable in the view, please use controllers do define the logic before rendering its output. especially when parameter dependant.
so for a solution:
in your controller as params[:id] should suggest an INT(11) value:
def action
# returning a Taxon should be a good idea here
#taxon = Taxon.find(params[:id])
# as I would give a Taxon class an has_many relation to a User
#users = #taxon.users
end
and in your action's view
<%= render :partial => "taxons/users", collection: #users %>
of course you would have the great ability to scope the users returned and render the wanted partial accordingly.
if you want more info about "The Rails way" please read:
http://guides.rubyonrails.org/
Have fun!
use instance_variable_set
instance_variable_set "#enable_#{#taxon_id}", true
just a reminder that it's better to do these things inside a controller.

Yield and default case || do not output default case

I have a simple yield use case and for some unknown reason the default case is never shown:
In my super_admin layout I have:
<%= yield :body_id || 'super_admin_main' %>
My controller
class Superadmin::GolfsController < ApplicationController
layout "super_admin"
def show
end
end
My show view
With or without
<% content_for(:body_id) do %>sadmin_golfs<% end %>
With: sadmin_golfs is shown.
without: empty string is shown instead of super_admin_main
Can anyone reproduce the same behavior ?
Try <%= yield(:title).presence || 'My Default Title' %>
Object#presence is equivalent to object.present? ? object : nil (AS 3 rc docs), and essentially allows the traditional syntax with the titles.
Use parentheses:
<%= (yield :body_id) || 'super_admin_main' %>
Or
<%= yield(:body_id) || 'super_admin_main' %>
Without them it is assuming yield (:body_id || 'super_admin_main')
EDIT: Rails 3 uses ActiveSupport::SafeBuffer instead of string/nil (Rails 2), so the output is not nil even if there is no content_for provided. So try:
<%= yield(:body_id).empty? ? 'super_admin_main' : yield(:body_id)%>
Why no test if there are a content_for or not define in view compilation.
In the content_for code we can see :
def content_for(name, content = nil, &block)
ivar = "#content_for_#{name}"
content = capture(&block) if block_given?
instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}".html_safe)
nil
end
So in your case, the #content_for_body_id is define if a content_for is in your view.
You can made :
<%= instance_variable_defined?('#content_for_body_id') ? yield(:body_id) : 'super_admin_main' %>
If you prefere you can generate an helper after
def yield_or(part, result)
instance_variable_defined?("#content_for_#{part}") ? instance_variable_get("#content_for_#{part}") : result
end
and call it in your view by
<%= yield_or(:body_id, 'super_admin_main') %>
It's works only with Rails 2.3.x
In Rails 3 :
there are this method content_for?
In rails 3
raises undefined method `present'
I know this is an old question but I have a solution for Rails 2.3.
I've extended shingara's yield_or helper method above so it can now accept a block:
module ApplicationHelper
def yield_or(name, content = nil, &block)
ivar = "#content_for_#{name}"
if instance_variable_defined?(ivar)
content = instance_variable_get(ivar)
else
content = block_given? ? capture(&block) : content
end
block_given? ? concat(content) : content
end
end
and this can be used in your templates:
<% yield_or :something do %>
<p>something else</p>
<% end %>
or
<%= yield_or :something, 'something else' %>
<div class= <%= (yield :content_with_bunners).present? ? yield(:content_with_bunners) : "col-md-10"%>>
You can use content_for?(:body_id), the code will be like.
<%= content_for?(:body_id) ? yield(:body_id) : 'super_admin_main' %>

Resources