Rails - Display menu when its main category is clicked - ruby-on-rails

I have a navbar where I display the MainCategory (Men, Women, Neutral)
(MainCategory is a model that have only one attribute :gender.)
I've definied the different genders like so:
enum gender: [:men, :women, :neutral]in my model.
Expected:
When I hover the link "Men" I want that the sub menu of "Men" shows up , same for "Women" and "Neutral".
Category is another model which has attributes :gender and a :title
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mx-auto">
<% MainCategory.order('gender ASC').all.each do |main_cat| %>
<li class="nav-link gender"><%= main_cat.gender %>
<div id="categories">
<ul class="navbar-nav mx-auto">
<% Category.where(gender: main_cat.gender).order('title ASC').each do |cat| %>
<% if cat.product_with_stock %>
<li class="nav-link"><%= link_to "#{cat.title} ", clients_category_path(cat), class: "nav-link" %></li>
<% end %>
<% end %>
</ul>
</div>
<% end %>
</li>
</ul>
</div>
</nav>
This the js file that show and hide the #category div.
$(document).on('turbolinks:load', function() {
$(".gender").mouseenter(function(){
$("#categories").slideDown();
})
$("body").click(function() {
$("#categories").slideUp();
});
$("#categories").click(function(e) {
e.stopPropagation();
});
});
With this code, I see the same submenu if I hover men or women, or neutral...
How should I improve this to have what expected?

You'll need to specify the related gender for each div and open it from your JS:
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mx-auto">
<% MainCategory.order('gender ASC').all.each do |main_cat| %>
<li class="nav-link gender" data-gender="<%= main_cat.gender %>"><%= main_cat.gender %>
<div class="categories" data-gender="<%= main_cat.gender %>">
<ul class="navbar-nav mx-auto">
<% Category.where(gender: main_cat.gender).order('title ASC').each do |cat| %>
<% if cat.product_with_stock %>
<li class="nav-link"><%= link_to "#{cat.title} ", clients_category_path(cat), class: "nav-link" %></li>
<% end %>
<% end %>
</ul>
</div>
<% end %>
</li>
</ul>
</div>
</nav>
JS:
$(document).on('turbolinks:load', function() {
$(".gender").mouseenter(function(){
var gender = $(this).data("gender")
$(".categories[data-gender=" + gender + "]").slideDown();
})
$("body").click(function() {
$(".categories").each(function() { $(this).slideUp() })
});
$(".categories").click(function(e) {
e.stopPropagation();
});
});
I can't test it, but this should work

Related

Rails 5, Bootstrap Carousel not rendering - setup

Im trying to use an image carousel in my Rails 5 app. I'm trying to follow the approach in this article: https://www.toptal.com/ruby-on-rails/rails-helper-bootstrap-carousel
I have an models for proposal and image. The associations are:
Proposal
has_many :images, as: :imageable
accepts_nested_attributes_for :images, reject_if: :all_blank, allow_destroy: true
Image
belongs_to :imageable, :polymorphic => true, optional: true
My view partial has:
<!-- GALLERY -->
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<!-- <div class="carousel-inner" role="listbox"> -->
<% #images.each do |gallery| %>
<% if gallery == #images.order(created_at: :asc).first%>
<div class="item active">
<%= carousel_for(gallery) %>
<%= image_tag(gallery.picture.url, :class => "carousel_image", :style => "text-align: center" ) %>
<div class="carousel_caption">
<p style="text-align: center"><%= gallery.comment.humanize %></p>
<p style="text-align: center"><%= gallery.credit %></p>
</div>
</div>
<% else %>
<div class="item">
<%= carousel_for(gallery) %>
<%= image_tag(gallery.picture, :class => "carousel_image") %>
<div class="carousel_caption">
<p style="text-align: center"><%= gallery.comment.humanize %></p>
<p style="text-align: center"><%= gallery.credit %></p>
</div>
</div>
<% end %>
<% end %>
<!-- </div> -->
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
<!-- /GALLERY -->
Helper has:
module CarouselHelper
def carousel_for(images)
Carousel.new(self, images).html
end
class Carousel
def initialize(view, images)
#view, #images = view, images
#uid = SecureRandom.hex(6)
end
def html
content = safe_join([indicators, slides, controls])
content_tag(:div, content, id: uid, class: 'carousel slide')
end
private
attr_accessor :view, :images, :uid
delegate :link_to, :content_tag, :image_tag, :safe_join, to: :view
def indicators
items = images.count.times.map { |index| indicator_tag(index) }
content_tag(:ol, safe_join(items), class: 'carousel-indicators')
end
def indicator_tag(index)
options = {
class: (index.zero? ? 'active' : ''),
data: {
target: uid,
slide_to: index
}
}
content_tag(:li, '', options)
end
def slides
items = images.map.with_index { |image, index| slide_tag(image, index.zero?) }
content_tag(:div, safe_join(items), class: 'carousel-inner')
end
def slide_tag(image, is_active)
options = {
class: (is_active ? 'item active' : 'item'),
}
content_tag(:div, image_tag(image), options)
end
def controls
safe_join([control_tag('left'), control_tag('right')])
end
def control_tag(direction)
options = {
class: "#{direction} carousel-control",
data: { slide: direction == 'left' ? 'prev' : 'next' }
}
icon = content_tag(:i, '', class: "glyphicon glyphicon-chevron-#{direction}")
control = link_to(icon, "##{uid}", options)
end
end
end
My application.js has:
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require jquery-fileupload/vendor/jquery.ui.widget
//= require jquery-fileupload/jquery.iframe-transport
//= require jquery-fileupload/jquery.fileupload
//= require bootstrap-sprockets
//= require moment
//= require bootstrap-datetimepicker
//= require pickers
//= require underscore
//= require gmaps/google
//= require markerclusterer
//= require cocoon
//= require_tree .
When I try this, I get an error that says:
undefined method `count' for #<Image:0x007fb10c88bea8>
It highlights this line of the carousel (indicators method):
items = images.count.times.map { |index| indicator_tag(index) }
ARUN'S SUGGESTION
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<!-- <div class="carousel-inner" role="listbox"> -->
<%# #images.each do |gallery| %>
<%# if gallery == #images.order(created_at: :asc).first%>
<div class="item active">
<%= carousel_for(#images) %>
<%= image_tag(#image.picture.url, :class => "carousel_image", :style => "text-align: center" ) %>
<div class="carousel_caption">
<p style="text-align: center"><%= #image.comment.humanize %></p>
<p style="text-align: center"><%= #image.credit %></p>
</div>
</div>
<%# else %>
<div class="item">
<%= carousel_for(#images) %>
<%= image_tag(#image.picture, :class => "carousel_image") %>
<div class="carousel_caption">
<p style="text-align: center"><%= #image.comment.humanize %></p>
<p style="text-align: center"><%= #image.credit %></p>
</div>
</div>
<%# end %>
<%# end %>
<!-- </div> -->
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
<!-- /GALLERY -->
ERROR SAYS: undefined method `picture' for nil:NilClass
2nd attempt at Arun's suggestion
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<div class="item active">
<%= carousel_for(#images) %>
<%= image_tag(#image.picture.url, :class => "carousel_image", :style => "text-align: center" ) %>
<div class="carousel_caption">
<p style="text-align: center"><%= #image.comment.humanize %></p>
<p style="text-align: center"><%= #image.credit %></p>
</div>
</div>
<div class="item">
<%= carousel_for(#images) %>
<%= image_tag(#image.picture.url, :class => "carousel_image") %>
<div class="carousel_caption">
<p style="text-align: center"><%= #image.comment.humanize %></p>
<p style="text-align: center"><%= #image.credit %></p>
</div>
</div>
<!-- </div> -->
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
<!-- /GALLERY -->
Error says: undefined method `picture' for nil:NilClass
Arun's revised suggestion
Taking Arun's revised suggestion, I try replacing the entire gallery view, with:
<%= carousel_for(Image.all.map(&:picture_url)) %>
When i try to render the page, the first image is rendered. I can see from the chrome inspector, that the second image is recognised, although the carousel doesnt work. The chevrons don't move the images along. There are no js issues showing in the console.
You need to execute your javascript and jquery for this carousel to work properly.
In the end of your html file, add this code (it can be before the /body):
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script>
$( document ).ready(function(){
$('#mycarousel').carousel();
});
</script>
You can also create a partial with this code and call it on the end of your application layout.
The problem is with the way you're calling carousel_for method. You should be passing an array of images but you're passing a single instance of Image type as you're iterating over #images.
ie. images inside the Carousel class is not an ActiveRecord Relation. So, you can't call the count method. The error message clearly says that you're trying to invoke the count on an image instance.
So, you should pass #images to carousel_for. Your view should only contain
carousel_for(#images)
EDIT
You should actually pass the array of image URLs to the carousel_for method.
<%= carousel_for(Image.all.pluck(&:picture_url)) %>

Bootstrap Accordion collapse with Ruby hash

Collapse is only working on the first button, and I know it's because only the first div id is being set for all buttons. How do I iterate and make new div id's for each element when using hash.each?
Here's my erb:
<% #contacts.each do |category, hash| %>
<div class="panel-group" id=accordion">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><%= category %></h3>
</div>
<div class="panel-body">
<ul class="list-group">
<% hash.each do |contact| %>
<li class="list-group-item" style="border: none">
<button type="button" class="btn btn-info" data-toggle="collapse" data-parent="#accordion" data-target="#demo"><%= contact['name'] %></button>
<div id="demo" class="panel-collapse collapse">
<div class="panel-body"><%= contact['email'] %></br><%= contact['ext'] %>
</div>
</div>
</li>
<% end %>
</ul>
</div>
</div>
</div>
<% end %>
Here's the corresponding code from my .rb:
get '/contact' do
contact = Contacts.new
#contacts = contact.getContacts
#contacts.each { |s| puts "get /contact found contact #{s.last.first['name']}" }
erb :contact
try
<% hash.each_with_index do |contact, index| %>
<li class="list-group-item" style="border: none">
<button type="button" class="btn btn-info" data-toggle="collapse" data-parent="#accordion" data-target="#collapse<%= index %>"><%= contact['name'] %></button>
<div id="collapse<%= index %>" class="panel-collapse collapse">
<div class="panel-body"><%= contact['email'] %></br><%= contact['ext'] %>
</div>
</div>
</li>
<% end %>

To iterate by block in rails

I used Ruby on Rails and I have created more of 40 hiraganas flashcards. In my index view, I do an iteration like this.
Some of Hiraganas cards have different I want to create different columns which host different color cards.
I want to iterate on letter A = green, E = red, I = Pink, etc
enter image description here
I only do that
<% #hiraganas.each do |hiragana| %>
<li>
<%= render 'allhiraganas', hiragana: hiragana %>
</li>
<% end %>
Do you know how to select only few elements to iterate. I see some tutos but I try .select
here is the render flashcards code
<div class="row">
<ul class="list-inline text-center card-frame">
<li>
<div class="card">
<div class="front">
<% if current_user.try(:admin?) %>
<%= link_to hiragana_path(hiragana), class:'trash-hiragana', data: { confirm: 'Are you sure?' }, method: :delete do %>
<%= image_tag("delete-btn.png") %>
<% end %>
<% end %>
<!-- PARAMETRER LE RESPONSIVE BOOTSTRAP -->
<!-- <div class="col-sm- col-xs-4 col-md-3"> -->
<span class="card-question popover-word" data-content="<h4 class='text-center letter-uppercase'><%= hiragana.bigletter.upcase %></h4><p class='text-center'><b><%= hiragana.midletter %></b> comme dans <b><%= hiragana.transcription %></b></p>">
<i class="fa fa-eye fa-lg"></i>
</span>
<!-- son de l'hiragana -->
<span class="audioclick popover-word" data-content="<p class='text-center'><b>le son arrive prochainement !</b></p>">
<i class="fa fa-volume-up fa-lg"></i>
</span>
<!-- image mnémotechnique -->
<span class="idea popover-word" data-content="<p class='text-center'><b>l'image est bientôt prête !</b><%= hiragana.upload %></p>">
<i class="fa fa-lightbulb-o fa-lg"></i>
</span>
<!-- <div class="prononciation">
<i class="fa fa-comment"></i>
</div> -->
<div class="card-hiragana hiragana-<%=hiragana.bigletter.downcase.last%>">
<h1><b><%= hiragana.ideo1 %></b></h1>
</div>
<div class="card-katakana">
<p><%= hiragana.ideo2 %></p>
</div>
<div id="favorite_<%=hiragana.id%>">
<%= render 'favs/favorites', hiragana: hiragana %>
</div>
</div>
<div class="back">
<div class="col-sm-3 col-xs-4 col-md-3 containerbackcards-<%=hiragana.bigletter.downcase.last%>">
<div class="backcard-hiragana">
<h1><b><%= hiragana.ideo1 %></b></h1>
</div>
<div class="card-bigletter">
<h4><%= hiragana.bigletter.upcase %></h4>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
Thank you for your answer
which ones do you want? what's the logic for which you'd like to choose? If you simply wanted the first 3 you could say
#hiriganas = Hirigana.first(3)
if you have a condition you'd like to choose them by select is a good choice.
#hiriganas = #hiriganas.select{ |hir| # criteria for selection }
It depends: If you have the color saved in the hiragana model, then you just need to:
greenhiriganas = Hirigana.where(color: "green")
If you just know in your head, which letters have which colors, then for each section you need to write an array containing all the names
#if for example A, Ka and Shi are green
green = [:a, :ka, :shi]
#then select via include?-method
greenhiriganas = Hirigana.select{ |hiri| green.include?(hiri.name) }

Rails will_paginate and tabs

I have a problem with working my tab along with will_pagination. When i press Tab 2, it will show the correct content, but when i press on the pagination link, example page 2. It will bring me back to my Tab 1 view. After this, when i press back Tab 2, it will appear page 2 content of Tab 2. The problem here is why does it bring my back to my Tab 1 view when i press on the pagination link in Tab 2.
My View Code
<div>
<ul class="nav nav-tabs" id="TabLength">
<% #biscuit.each_index do |i| %>
<% if i == 0 %>
<li class="active"><a data-toggle="tab" href="#<%= #biscuit[i] %>"><%= #biscuit[i] %></a></li>
<% else %>
<li><a data-toggle="tab" href="#<%= #biscuit[i] %>"><%= #biscuit[i] %></a></li>
<% end %>
<% end %>
</ul>
<div class="tab-content">
<% #biscuit.each_index do |i| %>
<% if i == 0 %>
<div class="tab-pane fade in active" id="<%= #biscuit[i] %>">
<div class="row" id="PictureSetting">
<% #testpage.each do |i| %>
<div class="col-md-4" id="ProductPic">
<%= image_tag(i.name , class:"img-thumbnail", size:"180x180") %>
</div>
<% end %>
</div>
<%= will_paginate #testpage, :param_name => 'user_page' %>
</div>
<% elsif i == 1 %>
<div class="tab-pane fade" id="<%= #biscuit[i] %>">
<div class="row" id="PictureSetting">
<% #memberpage.each do |i| %>
<div class="col-md-4" id="ProductPic">
<%= image_tag(i.name , class:"img-thumbnail", size:"180x180") %>
</div>
<% end %>
</div>
<%= will_paginate #memberpage, :param_name => 'choco_page' %>
</div>
<% else %>
<div class="tab-pane fade" id="<%= #biscuit[i] %>">
<div class="row" id="PictureSetting">
<h1>hello</h1>
</div>
</div>
<% end %>
<% end %>
</div>
</div>
Thanks
Based on answer from here, you can design the following code for the problem:
<script>
// open tab on click
$('#TabLength a').click(function (e) {
e.preventDefault();
$(this).tab('show');
// getting tab id
var id = $(e.target).attr("href").substr(1);
// change hash value for all pages
$('ul.pagination > li > a').each(function(i, pageAnchor) {
pageAnchor.hash = id;
});
});
// assign tab id to location hash
$("ul.nav-tabs > li > a").on("shown.bs.tab", function (e) {
var id = $(e.target).attr("href").substr(1);
window.location.hash = id;
});
// open initial hash
var hash = window.location.hash;
$('#TabLength a[href="' + hash + '"]').tab('show');
// UPDATE
$('ul.pagination > li > a').each(function(i, pageAnchor) {
pageAnchor.hash = hash;
});
</script>
It saves currently selected tab into location.hash. and selects it when you navigate to a new page.

favouriting users profiles in rails

so I've created a web app that has user profiles, where users can search for fellow users based on interests etc.. How might I add a feature where users can favorite a persons profile? I.e. User A finds User B and likes what they see, and can click a 'Favorite this profile' button and perhaps it's starred, and stored? What would the code look like for this? Just an idea, but I'm open to all ideas.
user_profile.html.erb
<%= render "shared/header" %>
<div id="landing_welcome_page">
<div class="container">
<div class="row">
<%#= Profile image upload %>
<div class="span4">
<%= user_avatar(current_user) %>
<%#= Space w line %>
<div class="name"></div><br>
<%#= Please bare in mind these are strickly temporary placeholders i.e whitespace %>
<%= render 'social' %>
</div>
<div class="span8">
<%# User name %>
<span class="name1">
<% if current_user.first_name.blank? %>
<%= current_user.first_name.present? ? current_user.first_name : link_to('Finish your profile', edit_account_path)%>
<% else %>
<%= current_user.first_name %> <%= current_user.last_name %>
<% end %>
</span>
<span class="side-buttons">
<div class="name"></div>
</span>
</span>
</div>
<div class="row">
<br />
<div class="span6">
<%# User occupation %>
<i class="fa fa-usd"></i>:
<%= best_in_place current_user, :occupation, nil: 'Add occupation' %>
</div>
<div class="addy">
<div class="span2">
<%# User address %>
<i class="fa fa-home"></i>:
<%= current_user.address.present? ? current_user.address : link_to('Add Address', edit_account_path) %>
</div>
</div>
<div class="span6">
<%# User gender %>
<br />
<% if current_user.gender == "M" || "male" %>
<i class="fa fa-male"></i> Male
<% else %>
<i class="fa fa-female"></i> Female
<% end %>
</div>
<div class="span2">
<!-- Code to calculate age by user birthday -->
<br />
Age: <%= user_birthday %>
</div>
<div class="span8"></div>
<div class="span8"><div class="name"></div></div>
<div class="span8">
<div class="tabbable"> <!-- Only required for left/right tabs -->
<ul class="nav nav-tabs">
<li class="active">About me</li>
<li>Photos</li>
<li>Personality</li>
</ul>
<div class="tab-content">
<div class="tab-pane in active" id="tab1">
<% #questions_for_about.each_with_index do |question, index| %>
<div class="question">
<h4 class="user_questions">
<%= index + 1 %>. <%= question.question %>
<%= link_to ("<i class='icon-edit'></i>".html_safe),
edit_user_question_path(current_user, question),
remote: true, class: "edit_link_#{question.id}" %>
</h4>
<div class="answer" id="answer_<%= question.id %>">
<%= answer_for(question) %>
</div>
</div>
<% end %>
</div>
<div class="tab-pane" id="tab2">
<div class="page-header">
<%= form_for Photo.new do |f| %>
<span class="btn btn-success fileinput-button">
<i class="icon-plus icon-white"></i>
<span>Add photos...</span>
<%= f.file_field :file, multiple: true, name: "photo[file]" %>
</span>
<% end %>
<div class="clearfix"></div>
</div>
<div class="photos_cont">
<div class="col-sm-6 col-md-3">
<span class="gallery"><%= render current_user.photos %></span>
</div>
</div>
</div>
<div class="tab-pane" id="tab3">
<% #questions_for_personality.each_with_index do |question, index| %>
<div class="question">
<h4 class="user_questions">
<%= index + 1 %>. <%= question.question %>
<%= link_to ("<i class='icon-edit'></i>".html_safe),
edit_user_question_path(current_user, question),
remote: true, class: "edit_link_#{question.id}" %>
</h4>
<div class="answer" id="answer_<%= question.id %>">
<%= answer_for(question) %>
</div>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
<%= render '/shared/footer' %>
</div>
</div>
<script id="template-upload" type="text/x-tmpl">
<div class="upload">
{%=o.name%}
<div class="progress"><div class="bar" style="width: 0%;"></div></div>
</div>
</script>
<script>
var fb_param = {};
fb_param.pixel_id = '6009056882201';
fb_param.value = '0.00';
(function(){
var fpw = document.createElement('script');
fpw.async = true;
fpw.src = '//connect.facebook.net/en_US/fp.js';
var ref = document.getElementsByTagName('script')[0];
ref.parentNode.insertBefore(fpw, ref);
})();
</script>
<noscript>
<img height="1" src="https://www.facebook.com/offsite_event.php?id=6009056882201&value=0" style="display:none;" width="1"/>
</noscript>
<script type="text/javascript">
// remove default datepicker event
jQuery(document).off('best_in_place:datepicker');
jQuery(document).on('best_in_place:datepicker', function(event, bip, element) {
// Display the jQuery UI datepicker popup
jQuery(element).find('input')
.datepicker({
format: element.data('date-format')
})
.on('hide', function(){
bip.update();
})
.on('changeDate', function(){
$(this).datepicker('hide');
})
.datepicker('show');
});
</script>
Create a Favorite model with a has_and_belongs_to_many relationship with User
Once you create the Favorite model and set up the relationship, you can do things like:
#user.favorites = [ user1, user2, user3 ]
#user.favorites << user4
to assign favorites to a user, or display them with something like:
<%= #user.favorites.map(&:name).to_sentence %>
You'll find everything you need to know on how to do this here: http://guides.rubyonrails.org/association_basics.html

Resources