Rails simple navigation, nested set - ruby-on-rails

I built navigation menu using simple navigation and built nested categories which i display in this menu.
navigation.rb code:
navigation.items do |primary|
Category.roots.map do |root|
primary.item ":root_#{root.id}", root.title, category_path(root) do |secondary|
root.descendants.map do |desc|
secondary.item ":desc_#{desc.id}", desc.title, category_path(desc)
end
end
end
end
The question is: how can i display all the levels of categories in my menu. That code does only with two level nesting.
Thank in advance

Please take a look at how refinery-cms does this.
The _menu.html.erb is close to what you have.
In addition to that it has another partial called _menu_branch.html.erb that renders the submenus of the menu recursively.
https://github.com/resolve/refinerycms/blob/master/core/app/views/refinery/_menu.html.erb
https://github.com/resolve/refinerycms/blob/master/core/app/views/refinery/_menu_branch.html.erb
Code cut from github:
_menu.html.erb
<nav id='<%= dom_id %>' class='<%= css %>'>
<ul>
<%= render :partial => '/refinery/menu_branch', :collection => roots,
:locals => {
:hide_children => hide_children,
:sibling_count => (roots.length - 1),
:apply_css => true #if you don't care about class='first' class='last' or class='selected' set apply_css to false for speed.
} -%>
</ul>
</nav>
_menu_branch.html.erb
<li<%= ['', css].compact.join(' ').gsub(/\ *$/, '').html_safe %>>
<%= link_to(menu_branch.title, main_app.url_for(menu_branch.url)) -%>
<% if (children = menu_branch.children unless hide_children).present? -%>
<ul class='clearfix'>
<%= render :partial => '/refinery/menu_branch', :collection => children,
:locals => {
:apply_css => local_assigns[:apply_css],
:hide_children => !!hide_children
} -%>
</ul>
<% end -%>
</li>

You will have to use recursive if this helps at all, you can see an example here: Recursive Rails Nested Resources

Related

Rails: How can I dynamically load from db into a bootstrap accordion only if it opens

I am using the
Awesome Nested Set gem to create a hierarchy now I want to display this hierarchy.
I have an index page with a typical controller action
klasses_controller.rb
def index
#klasses = Klass.where(depth: 0).order('lft ASC')
end
klasses/index.rb
<div id="accordion" role="tablist" aria-multiselectable="true">
<% #klasses.each do |klass| %>
<%= render :partial => "klass", locals: {klass: klass} %>
<% end %>
</div>
in my index action I am calling a partial
klasses/_klass.html.erb
<div class="klass">
<div class="klass-header" role="tab" id="heading-<%=klass.id%>">
<h5 class="mb-0">
<a data-toggle="collapse"
data-parent="#accordion"
href="#collapse-<%=klass.id%>"
aria-expanded="false"
aria-controls="collapse-<%=klass.id%>">
<%= klass.symbol + " : " + klass.title%>
</a>
</h5>
</div>
<div id="collapse-<%=klass.id%>"
class="collapse"
role="tabpanel"
aria-labelledby="heading-<%=klass.id%>">
<div class="klass-block">
<Here is where I want to render partial for each child>
</div>
</div>
</div>
This is standard accordion and is working as is. Here is the problem I have a very big db and I don't want to render anything unnecessarily. I want to wait until the header is clicked and then asynchronously retrieve the children of the class i clicked and render each using the same partial.
How can I achieve this? Is there a way using a route/controller action combination or should I start writing coffee/java-script? I am not trying to reinvent the wheel so if anyone knows of an example that would be welcome.
This was a tricky problem only because there were a lot of moving parts. It was a real headscratcher but in hindsight it is pretty straight forward.
First I wanted to use a custom controller action so I added a route for my "children" method which is set up to receive an ajax call.
routes.rb
get 'klasses/:id/children', to: 'klasses#children', as: 'children_of'
klasses_controller.rb
def index
#klasses = Klass.where(depth: 0).order('lft ASC')
end
def children
respond_to do |format|
format.js {render 'children', :klass => #klass }
end
end
This respond block is expecting to have a children.js.erb to call for.
children.js.erb
$("#collapse-<%=#klass.id%>").html("<%= escape_javascript(render :partial => 'klasses/children', locals: { :klass => #klass })%>");
This is where we specify the div that we are going to insert the new content into and we call another partial.
_children.html.erb
<div class="child-block">
<% children = #klass.children %>
<% children.each do |child| %>
<%= render :partial => 'klasses/klass', locals: { :klass => child } %>
<% end %>
</div>
Finally I rewrote my _klass.html.erb partial so It has a link in the heading that will both trigger bootstrap's accordion js and call our new controller action.
_klass.html.erb
<div class="klass">
<div class="klass-header" role="tab" id="heading-<%=klass.id%>">
<h5 class="mb-0">
<%= link_to klass.symbol + " : " + klass.title,
children_of_path(klass.id),
remote: true,
:data => { :toggle => "collapse",
:parent => "#accordion",
:target => "#collapse-#{klass.id}"
},
:aria => { :expanded => "false",
:controls => "collapse-#{klass.id}"
}%>
</h5>
</div>
<div id="collapse-<%=klass.id%>"
class="collapse"
role="tabpanel"
aria-labelledby="heading-<%=klass.id%>">
</div>
</div>
That's pretty much it. Add some padding to the child-block and you have yourself a nice indented Hierarchy that dynamically loads content.
I did have to disable cross site Request forgery for my custom action in my controller
protect_from_forgery :except => :children
If anyone knows a way around that let me know.

Does this rails code belong in Application Controller?

I have some code (that is working), but I just want to make sure I am putting it in the right place per rails conventions/best practices. The purpose of the code, is to generate a set of subheading navigation links if '#facility' is defined (which could be done in one of several controllers). Right now, I have the following bits of code spread out as identified below.
My issue: this doesn't feel right, particularly the bit of logic at the beginning of the html template. I will also want to define a few other similar helpers to define these subhead links based on different models. Should this logic (of setting #subhead_links) be in the application controller? As a method in each model (so I would set #subhead_links = #facility.subhead_links)?
I've looked some for answers, but this type of philosophical question isn't as readily google-able as an error code.
in application helper
# build subhead
def subhead_links(facility)
links = [
{ :label => "Configure Facility", :path => facility_path(facility) },
{ :label => "Waitlists", :path => waitlist_tiers_path(:id => facility.id) },
{ :label => "Applications", :path => sponsors_path(:id => facility.id) }
return links
end
in a partial included in application.html.erb template
<% if #facility %>
<% #subhead_links = subhead_links(#facility) %>
<% end %>
<% if #subhead_links %>
<nav class="subnav">
<ul>
<% #subhead_links.each do |link| %>
<li><%= link_to link[:label], link[:path] %></li>
<% end %>
</ul>
</nav>
<% end %>
in various other controllers...
#facility = Facility.find(params[:id])
I never rely on instance variables in partials and try to put as much logic as possible in helpers.
Here this would result in the following:
application_layout:
<%= render_subhead_links(#facility) %>
application_helper:
def render_subhead_links(facility)
if facility
links = [
{ :label => "Configure Facility", :path => facility_path(facility) },
{ :label => "Waitlists", :path => waitlist_tiers_path(:id => facility.id) },
{ :label => "Applications", :path => sponsors_path(:id => facility.id) }
render :partial_name, :links => links
end
end
partial:
<nav class="subnav">
<ul>
<% links.each do |link| %>
<li><%= link_to link[:label], link[:path] %></li>
<% end %>
</ul>
</nav>

Rails generate extra <li> tags automatically

this is the code :
<ul >
<% items.each do |item|%>
<%= render :partial => "somepartial", :locals => { :title => item.title} %>
test_text
<% end %>
</ul>
the partial:
<li><a><%= title %></a></li>
and the out put is :
<ul >
<li><a>item1</a></li>
<li>test_text</li>
<li><a>item2</a></li>
<li>test_text</li>
<li><a>item3</a></li>
<li>test_text</li>
</ul>
< li > tags around the test_text is extra. Partial and the model is not related, so do not suggest me to use collection method. When partial is rendered inside the each loop, rails does not put li tags around it, but the anything except the partial gets li tags around them.
The question is not entirely clear to me, so maybe i should refrain from answering.
But, i would propose to use haml, which gives you much cleaner views.
Your main view would become:
%ul
= render :partial => "items/item", :collection => items
and your partial items\_item.html.haml would look like this
%li
%a
= item.title
I don't see a real link inside your li-item, so maybe you want something like:
%li
= link_to item.title, item_path(item)
Instead of this:
<% items.each do |item|%>
<%= render :partial => "items/item", :locals => { :title => item.title} %>
<% end %>
Try this:
<%= render :partial => "items/item", :collection => items %>

Render partial in Ruby on rails a collection is multiplying items

I want to display a list of items in a page in Ruby-on-Rails. I use partials
in my index.html.erb file I have:
<%= #lista = News.find(:all, :order => Document::COL_DATE + ' DESC, id DESC')
render :partial => "newsitem",
:layout => "list_news",
:spacer_template => "spacer",
:collection => #lista
%>
in _list_news.html.erb I have:
<div class="news">
<%= yield %>
</div>
in _spacer.html.erb I have <hr/>
in _newsitem.html.erb I have
<%= newsitem_counter + 1 %>
<!-- Code to print details for one item -->
The problem is that it prints the list multiple times:
If the list has 3 items, it shows them 3 times: 1,2,3,1,2,3,1,2,3.
If it has 7 items, those items are printed 7 times.
What is wrong in my code?
The :layout option is usually used with :action or a single :partial, not with :collection's. The problem: yield is being called for every item in the list.
You'd have to look at the sources to figure out why :layout and :collection are acting this way; but suffice it to say your code should probably just be rewritten so that it doesn't rely on :layout and :collection working together.
Here's one way you could do so, with the assumption that reusing this code in other views is a high priority. Unless you're using lots of caching, rendering each partial tends to be fairly slow, especially if your news_feed has many items, so I've consolidated it into one.
controller/news_controller.rb
class NewsController < ApplicationController
def index
#news_feed = News.find(:all,
:order => Document::COL_DATE + ' DESC, id DESC')
end
end
views/news/index.html.erb
<%= render :partial => "news_feed",
:locals => { :news_feed => #news_feed} %>
views/news/_news_feed.html.erb
<ul class="news">
<% news_feed.each_with_index do |news_item, news_item_counter| %>
<li>
<%= newsitem_counter + 1 %>
<%# Code to print details for one item %>
</li>
<% end %>
</ul>
If rendering a whole bunch of partials is okay for you running-time wise, you might find this implementation of views/news/_news_feed.html.erb nicer:
<div class="news">
<%= render :partial => 'news_item', :collection => news_feed, :spacer_template => "horizontal_break" %>
</div>
views/news/_news_item.html.erb
<%= newsitem_counter + 1 %>
<%# Code to print details for one item %>
views/news/_horizontal_break.html.erb
<hr />
So instead of rendering :layout, you render one big partial which wraps the collection.
This is a known problem in Rails 2.3.8 and Rails 3! https://rails.lighthouseapp.com/projects/8994/tickets/2279-render-layout-with-block-and-multiple-yields

Rendering Partial onclick in Rails

I am trying to render a partial onclick to save on page loading time.
<ul id="pop_twitter">
<% #topic_count.each do |k,v| %>
<% #k = k %>
<!-- make a link that onclick renders a partial below -->
<li><% link_to_remote k, ?????? %></li>
<ul id="twitter_<%= k %>" style="display:none;">
<!-- where the partial should load -->
</ul>
<% end %>
</ul>
I need to load the partial 't_tweets' and it also need the variable 'k' in from the .each loop.
here's a rough start:
link_to_remote("Show", :url => {:action => 'show_tweets', :k => k})
EDIT: i guess since you're only showing a partial, it would make sense to also pass :method => :get, since link_to_remote defaults to :post.
and in your controller
def show_tweets
render :update do |page|
page.insert_html :bottom, 'pop_twitter', :partial => 't_tweets', :locals => params[:k]
page["tweet_#{params[:k]}"].visual_effect :highlight #using scriptaculous
end
and your partial
<div id="<%= "tweet_#{k}" %>">
<%= tweet.body %>
</div>

Resources