ActiveAdmin -- How to access instance variables from partials? - ruby-on-rails

I can't seem to access instance objects in partials. Example:
In controller I have:
ActiveAdmin.register Store do
sidebar "Aliases", :only => :edit do
#aliases = Alias.where("store_id = ?", params[:id])
render :partial => "store_aliases"
end
end
Then in the _store_aliases.html.erb partial I have:
<% #aliases.each do |alias| %>
<li><%= alias.name %></li>
<% end %>
This doesn't work. The only thing that does work (which is horrible to do as I'm putting logic in a view is this:
<% #aliases = Alias.where("store_id = ?", params[:id]) %>
<% #aliases.each do |alias| %>
<li><%= alias.name %></li>
<% end %>

When rendering a partial you need to actively define the variables that are given to that partial. Change your line
render :partial => "store_aliases"
to
render :partial => "store_aliases", :locals => {:aliases => #aliases }
Inside your partial the variables is then accessible as a local variable (not an instance variable!). You need to adjust your logic inside the partial by removing the #.
<% aliases.each do |alias| %>
<li><%= alias.name %></li>
<% end %>
For further reading have a look at the API documentation (specifically the section "3.3.4 Passing Local Variables").

You have to pass your instance variable to your partial in order to use it there:
ActiveAdmin.register Store do
sidebar "Aliases", :only => :edit do
#aliases = Alias.where("store_id = ?", params[:id])
render :partial => "store_aliases", :locals => { :aliases => #aliases }
end
end
Then in your partial you will be able to use it as local variable
<% aliases.each do |alias| %>
<li><%= alias.name %></li>
<% end %>

Related

Rails partial looping through local_assigns

I'm populating a partial with many instance variables in the locals hash. Is there a way to pull multiple instance variables from local_assigns in the partial?
<%= render 'tabs', :locals => {:tab1 => #news, :tab2 => #people, :tab3 => #tags} %>
In the partial I'd like to create a dynamic set of tabs based on the number of instance variables I populate the locals with.
<% local_assigns.each do |local_assign| %>
<% local_assign.each do |tabs| %>
<!-- Grab tab class name -->
<li class="tab"><%= tabs[:class] %></li>
<% end %>
<% end %>
Why don't you just pass it as an array
render 'tabs', :locals => {:tabs => [#news, #people, #tags]} %>
in your view
<% tabs.each do |tab| %>
<!-- Grab tab class name -->
<li class="tab"><%= tab[:class] %></li>
<% end %>
Thanks Vimsha I ended up using collection instead of locals and created the instance variable in the controller.
http://guides.rubyonrails.org/layouts_and_rendering.html
Controller
#tabs = [#news, #people]
View
<%= render 'tabs', :collection => #tabs %>

Passing instance variables in nested partials in Rails?

I am having difficulty passing instance variables in nested partials. Here is what I have done.
In controller Own:
def home
#item = "some values"
#ref = "some other values"
end
Then I have a home page "home.html.erb", in which I rendered "_product_table.html.erb":
<%= render "own/product_table", :item => #items, :ref => #ref %>
Then, in "_product_table.html.erb", I have to render "_product.html.erb":
<% #items.each do |item|%>
<%= render "own/product", :item => item, :ref => #ref %>
<% end %>
I can't understand why the ref variable is not available in the "_product.html.erb" partial.
You are passing ref as argument to the partial in home.html.erb, so in _product_table.html.erb you should use it similarly to item, not as instance variable:
<% #items.each do |item|%>
<%= render "own/product", :item => item, :ref => ref %>
<% end %>

How can I re-render more than 2 partials at once using Ajax

I have a rails app, which is constructed by three parts such as navigation above, main content, and side menu.
I already implemented follow un-follow button in my main content.
It's working with Ajax perfectly so far.
basically if I press follow button, follow action in users_controller.rb will be called and changes follow flag, and then it calls follow.js to re-render follow button as partial.
Beside that, in side menu, it has the number of people whom current_user is following.
This number also should be refreshed right after follow action was executed.
To refresh more than 2 partials at once. How can I archive this?
controllers/users_controller.rb
....
def follow
#user = User.find(params[:id])
current_user.follow(#user)
respond_to do |format|
format.js {render :action=>"follow.js"}
end
end
def unfollow
#user = User.find(params[:id])
current_user.stop_following(#user)
respond_to do |format|
format.js {render :action=>"unfollow.js"}
end
end
...
views/users/follow.js.erb
$('.follow_user[data-user-id="<%=#user.id%>"]').html('<%= escape_javascript(render :partial => "users/follow_user", :locals => {:user => #user}) %>');
views/users/unfollow.js.erb
$('.follow_user[data-user-id="<%=#user.id%>"]').html('<%= escape_javascript(render :partial => "users/follow_user", :locals => {:user => #user}) %>');
views/layouts/_menu.html.erb
<% if user_signed_in? %>
<li><%= link_to(following_user_path(current_user.username)) do %>
<i class="icon-heart"></i>Following
<%= '(' + current_user.all_following.count.to_s + ')' if current_user.all_following.count > 0 %>
<% end %>
</li>
<li><%= link_to(followed_user_path(current_user.username)) do %>
<i class="icon-heart"></i>Followed by
<%= '(' + current_user.followers.count.to_s + ')' if current_user.followers.count > 0 %>
<% end %>
</li>
<% else %>
<li><%= link_to sanitize('<i class="icon-heart"></i> ') + "Following", following_user_path %></li>
<li><%= link_to sanitize('<i class="icon-heart"></i> ') + "Followed by", followed_user_path %></li>
<% end %>
# dedicate partial _following_number.html.erb
<span id="following_number">
<% if user.followers.count > 0 %>
<%= '(' + user.followers.count.to_s + ')' %>
<% end %>
</span>
# update layout with partial:
<li><%= link_to(followed_user_path(current_user.username)) do %>
<i class="icon-heart"></i>Followed by
<%= render :partial => "following_number", :user => current_user %>
<% end %>
# follow.js.erb && unfollow.js.erb:
...
$(document).find("#following_number").replaceWith('<%= escape_javascript(render("following_number", :user => #user, :formats => [:html])) %>')
More elegant with helper:
def following_number(user)
user.followers.count > 0 ? "(#{user.followers.count})" : nil
end
# then put spans to layout:
<span id="following_number"><%= following_number(current_user) %></span>
# and js:
$(document).find("#following_number").html('<%= escape_javascript(following_number(#user)) %>')
You could create a new action that render_to_string both of those partials and format them into a json object:
{
div_id_1: "<ul....." ,
div_id_2: "<div...."
}
One simple way of doing this is to return a .js from rails and have your view execute this script, which will have the actions to update/replace your view.
For example this simply renders three partials and later using jQuery replaces the content in your view. Lets say the action is my_action so you will place the following code in your my_action.js.erb:
$("#content_1").html("<%= escape_javascript(render('partial_1'))%>");
$("#content_2").html("<%= escape_javascript(render('partial_2'))%>");
$("#content_3").html("<%= escape_javascript(render('partial_3'))%>");
This example can be extended the way you want or need. You can also render json for your models and call a function to update them in the view.

Blank page when rendering a partial with ajax in rails 3

I have a nav menu with 2 tabs/links in the show.html.erb file, in UsersController.rb, I would like to use ajax to render different partial for the tabs.
In the show.html.erb I have a div named profile-data where I want to show the content.
So I do something like this:
The link structure:
<li><%= link_to "College friends", college_friends_path, :remote => true %></li>
<li><%= link_to "Highschool friends", highschool_friends_path, :remote => true %></li>
I define the routes:
match "college_friends" => "users#college_friends", :as => "college_friends"
match "highschool_friends" => "users#highschool_friends, :as => "highschool_friends"
And I define in my UserController.rb the necessary methods:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def college_friends
respond_to do |format|
format.js
end
end
def highschool_friends
respond_to do |format|
format.js
end
end
end
Last thing we have the JS files:
*college_friends.js.erb*
$('#profile-data').html("<%= escape_javascript(render(:partial => 'college_friends')) %>");
*highschool_friends.js.erb*
$('#profile-data').html("<%= escape_javascript(render(:partial => 'highschool_friends')) %>");
The partial code: _college_friends.html.erb
<% groups = #user.friends.group_by(&:college_name) %>
<% sorted_groups = groups.sort_by{|key, values| values.count}.reverse %>
<% sorted_groups.each do |collegename, friends| %>
<% next if collegename.blank? %>
<div class="contentbox">
<div class="box-header">
<h3><%= collegename %></h3>
<div class="meta-info">
<p><i class="icon-map-marker"></i> Malmö</p>
<p><i class="icon-user"></i><span class="count"> <%= friends.count %></span> vänner</p>
</div>
</div>
<ul class="friends-list">
<% friends.map do |friend| %>
<li><%= image_tag(friend.image) %>
<% end %>
</ul>
</div>
<% end %>
So I solve this problem but checking the source in and out. And I notice that the js files was not loaded in the app.
So I changed this:
<%= javascript_include_tag :defaults %>
To this:
<%= javascript_include_tag "application" %>
And it loaded all the necessary js files.
But then I get this error:
ActionView::Template::Error (undefined method `friends' for nil:NilClass):
You are getting
ActionView::Template::Error (undefined method `friends' for nil:NilClass):
Because
<% groups = #user.friends.group_by(&:college_name) %>
requires #user to be set.
As Brandon suggested, try
def college_friends
#user = User.find(params[:id])
respond_to do |format|
format.js
end
end
BUT
To achieve this, you need to change your link routes to include user id, similar to this
match "college_friends/:id" => "users#college_friends", :as => "college_friends"
and in your links
<li><%= link_to "College friends", college_friends_path(#user), :remote => true %></li>
As suggested in the comments above, you should have two partials named _college_friends.html.erb and _highschool_friends.html.erb
These will contain your HTML, which is what you're wanting to load via $('#profile-data').html()
Template Error:
You are not defining #user in college_friends and highschool_friends. So your view is requesting #user from that action, which isn't there.

Why is rails running a partial twice?

I am calling a partial in one of my views like so:
<%= render :partial => 'events/attendees', :collection => #attendees %>
the partial however is running twice for some reason...here is the partial:
<% #attendees.each do |user| %>
<li><%= link_to user.name, user %></li>
<% end %>
and i verified that rails is in fact running this partial twice because the output shows each item from #attendees twice
That's because one "loop" is from Rails (:collection means that Rails will render the partial for each item in the collection, in this case #attendees) and one loop via your own partial.
Change the partial to below (not sure about the relation between attendee/user, but here is a sample):
<li><%= link_to attendee.name, attendee.user %></li>
Or, change the call of the partial to:
<%= render :partial => 'events/attendees' %>

Resources