Mobile resizing for rails kaminari pagination with bootstrap theme - ruby-on-rails

I am using kaminari to paginate the index pages of some of my models, and it works quite well. I'm using it with the bootstrap4 theme, and while it looks great, it does not resize well on mobile devices. More specifically, I mean that these links don't resize at all (or if they do, it's minimal), and they extend well beyond the screen to the right, which is annoying. I've tried putting these links inside a bootstrap container, but that didn't cause them to properly resize.
How do I resize kaminari pagination for mobile devices?
Here is the relevant view code:
<div class="container">
<h1>All Leagues</h1>
<hr />
<% #leagues.each do |league| %>
<p><%= link_to league.name, league %></p>
<% end %>
<hr />
<div class="container">
<%= paginate #leagues %>
<%= page_entries_info #leagues %>
</div>
</div>
Thank you!

Try with adding this into your section:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
if this doesn't help then try this:
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>All Leagues</h1>
<hr />
<% #leagues.each do |league| %>
<p><%= link_to league.name, league %></p>
<% end %>
<hr />
<%= paginate #leagues %>
<%= page_entries_info #leagues %>
</div>
</div>
</div>

Related

Row, col-md-4 adding a new post

I started learing ruby and i wanted to create an album page when you can add posts with images. I came across a problem when I add a post it is not aligned, like on bootstrap album example: https://getbootstrap.com/docs/4.5/examples/album/
Look at what i've done https://iv.pl/image/bootstrap.Gt2w3RT
<!DOCTYPE html>
<html>
<head>
<title>AlbumSite</title>
<%= csrf_meta_tags %>
<link rel="canonical" href="https://getbootstrap.com/docs/4.5/examples/album/">
<%= stylesheet_link_tag 'https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css' %>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_include_tag 'application' %>
</head>
<body>
<section class="jumbotron text-center">
<div class="container">
<h1>Simple album</h1>
<p class="lead text-muted">Something short and leading about the collection below—its contents, the creator, etc. Make it short and sweet, but not too short so folks don’t simply skip over it entirely.</p>
<p>
Add a new album
The first page
</p>
</div>
</section>
<div class="postsSection bg-light">
<div class="container col-md-4" >
<div class="postBox">
<%= yield %>
</div>
</div>
</div>
</main>
<footer class="text-muted">
<div class="container">
<p class="float-right">
Back to top
</p>
<p>Album example is © Bootstrap, but please download and customize it for yourself!</p>
<p>New to Bootstrap? Visit the homepage or read our getting started guide.</p>
</div>
</footer>
</body>
</html>
<% #posts.each do |post| %> <!-- no %= because this isn an output, tylko przy pokazywaniu zmiennych tego sie uzywa -->
<div class="row">
<div class="card mb-4 shadow-p">
<svg class="bd-placeholder-img card-img-top" width="100%" height="225" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice" focusable="false" role="img" aria-label="Placeholder: Thumbnail"><title>Placeholder</title><rect width="100%" height="100%" fill="#55595c"/><text x="50%" y="50%" fill="#eceeef" dy=".3em">Thumbnail</text></svg>
<div class="card-body">
<p class="card-text"><h3><%= post.title %> </h3> <%= post.body %></p>
<div class="btn-group">
<div>
<%= link_to "View", post_path(post), :class =>'btn btn-md btn-outline-secondary' %>
</div>
<div class="btn-group">
<div>
<%= link_to "Edit", edit_post_path(post), :class =>'btn btn-md btn-outline-secondary' %>
</div>
</div>
</div>
</div>
</div>
<% end %>
The row has to go before you go through each post
<div class="row">
<% #posts.each do |post| %>
<div class="col-md-4">
<div class="card">
<div class="card-title">
<%= post.title %>
</div>
</div>
</div>
<% end %>
</div>

Is there a conflict with this code and FancyBox3?

Can anyone tell me whats wrong with this section of code? I recently got this to work, but found out soon after the functionality for the Fancybox gallery stopped working. The a link element is only a sliver compared to the over all element. Im not sure if thats it. I know the most recent edit I made was to fix the surrounding row from .row-fluid to .row since that broke my layout. Below is the code:
<body id="portfolio">
<div class="container-fluid" id="particles-js"></div>
<%= render 'layouts/altmenu_gallery' %>
<h1>Portfolio</h1>
<div id="gallery" class="container-fluid">
<% #photos.each_slice(4) do |group| %>
<div class="row ">
<% group.compact.each do |photo| %>
<div class= "col-md-3">
<a class="fancybox" data-fancybox="gallery" href="<%=image_path photo.file_url %>" data-caption="<%= photo.description %>">
<%= image_tag photo.file_url, class:' img-fluid img-thumbnail' if photo.file.present? %>
</a>
</div>
<% end %>
</div>
<% end %>
<br class="clear">
</div>
<%= link_to 'New Photo', new_photo_path %>
</body>
Sorry, but it is not possible to tell without seeing the actual html code or, preferably, live demo. Maybe this issue arises because you have not escaped photo.description and that breaks html code, but, as I said, I can not be sure.

Passing Local Variable in Rails 5 Best Practice

I am trying to dry up my code and decided to use a partial for my page title and pass a local variable into it. It works, but I want to know if I am conforming to the Rails best practice.
partials/_page-header.html.erb
<section class="hero is-primary">
<div class="hero-body">
<div class="container">
<h1 class="title">
<%= title %>
</h1>
<h2 class="subtitle">
Hero subtitle
</h2>
</div>
</div>
</section>
static_pages/home.html.erb
I would add this to the top of all my views
<% provide(:title, 'Home') %>
...
application.html.rb
<!doctype html>
<html lang="en">
<head>
<%= render 'partials/head' %>
<%= render 'partials/head-scripts' %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'partials/nav' %>
<%= render 'partials/page-header', title: yield(:title) %>
<section class="section">
<div class="container">
<div class="content">
<%= yield %>
</div>
</div>
</section>
<%= render 'partials/footer' %>
<%= render 'partials/footer-scripts' %>
</body>
</html>

Google maps autocomplete js is working on localhost but not on heroku

I'm a junior ruby on rails developer. I developed a web app that uses Google maps javascript API and I use the autocomplete function on a form input.
The autocomplete works fine on localhost but does not work anymore after deploying on heroku.
Here is my html.erb below. For your perfect information, the form is in the page footer. This form is partially hidden and the only visible part corresponds to a button used to upload a video file. Once this button has been clicked and the video file has been chosen, I display a modal containing the rest of the form. That's where the 'text_field_tag' (with the id = "user_input_autocomplete_address") is displayed and where the autocomplete should work.
<% if user_signed_in? %>
<div class="footer-check hidden-md hidden-lg">
<div class="container text-right">
<div class="row">
<div class="flexbox">
<div class="footer-home active">
<%= link_to root_path do %>
<i class="fa fa-home" aria-hidden="true"></i>
<% end %>
</div>
<div class="footer-search">
<!-- later put link_to reviews_path -->
<%= link_to search_path do %>
<i class="fa fa-search" aria-hidden="true"></i>
<% end %>
</div>
<div class="footer-button">
<%= simple_form_for(Review.new) do |f| %>
<div id="add_video_image_btn">
<label for="review_video", class="add_video_image"><%= image_tag "plus.png" %></label>
<%= f.input :video, label: false, input_html: { accept: ".mp4, .mov, .m4v, .wmv, .webm, .avi", class: 'hidden'} %>
<%= f.input :video_cache, as: :hidden, class: "add_video_image file required" %>
</div>
</div>
<div class="footer-likes">
<%= link_to dashboard_users_path do %>
<i class="fa fa-heart" aria-hidden="true"></i>
<% end %>
</div>
<div class="footer-user">
<%= link_to user_path(current_user) do %>
<i class="fa fa-user" aria-hidden="true"></i>
<% end %>
</div>
</div>
</div>
</div>
</div>
<!--Beginning Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<div id="add_video_form_step2">
<%= f.error_notification %>
<fieldset class="form-group" style="margin-bottom:0;">
<div class="section">
Place
</div>
<div class="inner-wrap">
<div id="">
<%= text_field_tag :place, nil, class: 'form-control', id: 'user_input_autocomplete_address', placeholder: 'Start typing...', size: 80 %>
</div>
</div>
<div class="section">
Comment
</div>
<div class="inner-wrap">
<%= text_field_tag :comment, nil, class:'form-control', placeholder: 'Food is good but the place is a bit noisy', size: 80 %>
</div>
<div class="inner-wrap" style="padding:15px;">
<div class="emoji-toggle emoji-happy">
<input type="checkbox" id="toggle1" class="toggle" name="review[mood]" value="false">
<div class="emoji"></div>
<label for="toggle1" class="well"></label>
</div>
</div>
<div class="">
<%= f.button :submit, class: "btn btn-primary form-control", id: "click-trigger" %>
</div>
<%= hidden_field_tag :name, id: 'name' %>
<%= hidden_field_tag :street_number, id: 'street_number' %>
<%= hidden_field_tag :route, id: 'route' %>
<%= hidden_field_tag :locality, id: 'locality' %>
<%= hidden_field_tag :administrative_area_level_1, id: 'administrative_area_level_1' %>
<%= hidden_field_tag :postal_code, id: 'category_0' %>
<%= hidden_field_tag :country, id: 'country' %>
<%= hidden_field_tag :formatted_address, id: 'formatted_address' %>
<%= hidden_field_tag :phone_number, id: 'phone_number' %>
<%= hidden_field_tag :website, id: 'website' %>
<%= hidden_field_tag :gplace_id, id: 'gplace_id' %>
<%= hidden_field_tag :category_0, id: 'category_0' %>
<%= hidden_field_tag :category_1, id: 'category_1' %>
<%= hidden_field_tag :category_2, id: 'category_2' %>
<%= hidden_field_tag :category_3, id: 'category_3' %>
<%= hidden_field_tag :category_4, id: 'category_4' %>
<%= hidden_field_tag :category_5, id: 'category_5' %>
<%= hidden_field_tag :hours_open_day_0, id: 'hours_open_day_0' %>
<%= hidden_field_tag :hours_open_day_1, id: 'hours_open_day_1' %>
<%= hidden_field_tag :hours_open_day_2, id: 'hours_open_day_2' %>
<%= hidden_field_tag :hours_open_day_3, id: 'hours_open_day_3' %>
<%= hidden_field_tag :hours_open_day_4, id: 'hours_open_day_4' %>
<%= hidden_field_tag :hours_open_day_5, id: 'hours_open_day_5' %>
<%= hidden_field_tag :hours_open_day_6, id: 'hours_open_day_6' %>
</fieldset>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<% end %>
<% end %>
<!--End Modal -->
<!-- Start of js to display the modal -->
<!-- NB: the autocomplete module is in assets/javascript/autocomplete.js -->
<%= content_for :after_js do %>
<script>
$('#review_video').change(function(){
$('#myModal').modal('show');
});
</script>
<% end %>
<!-- End of js to display the modal -->
The footer (gathering the modal and the form) is called within a layouts/application.html.erb view, which is below. You'll see that I use Google API key in there (hidden in application.yml)
<!DOCTYPE html>
<html>
<head>
<title><%= meta_title %></title>
<%= csrf_meta_tags %>
<!-- Start Favicon -->
<%= favicon_link_tag '_/app/assets/images/favicon.ico' %>
<link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="<%= image_path 'ms-icon-144x144.png' %>">
<meta name="theme-color" content="#ffffff">
<!-- end Favicon -->
<meta name="description" content="<%= meta_description %>">
<!-- Facebook Open Graph data -->
<meta property="og:title" content="<%= meta_title %>" />
<meta property="og:type" content="website" />
<meta property="og:url" content="<%= request.original_url %>" />
<meta property="og:image" content="<%= meta_image %>" />
<meta property="og:description" content="<%= meta_description %>" />
<meta property="og:site_name" content="<%= meta_title %>" />
<!-- Twitter Card data -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="<%= DEFAULT_META["twitter_account"] %>">
<meta name="twitter:title" content="<%= meta_title %>">
<meta name="twitter:description" content="<%= meta_description %>">
<meta name="twitter:creator" content="<%= DEFAULT_META["twitter_account"] %>">
<meta name="twitter:image:src" content="<%= meta_image %>">
<!-- Google+ Schema.org markup -->
<meta itemprop="name" content="<%= meta_title %>">
<meta itemprop="description" content="<%= meta_description %>">
<meta itemprop="image" content="<%= meta_image %>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
<%= stylesheet_link_tag 'application', media: 'all' %>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!-- start Mixpanel -->
<script type="text/javascript">(function(e,b){if(!b.__SV){var a,f,i,g;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b,h){var a=h.split(".");2==a.length&&(b=b[a[0]],h=a[1]);b[h]=function(){b.push([h].concat(Array.prototype.slice.call(arguments,0)))}}var c=b;"undefined"!==typeof d?c=b[d]=[]:d="mixpanel";c.people=c.people||[];c.toString=function(b){var a="mixpanel";"mixpanel"!==d&&(a+="."+d);b||(a+=" (stub)");return a};c.people.toString=function(){return c.toString(1)+".people (stub)"};i="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config reset people.set people.set_once people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" ");
for(g=0;g<i.length;g++)f(c,i[g]);b._i.push([a,e,d])};b.__SV=1.2;a=e.createElement("script");a.type="text/javascript";a.async=!0;a.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:"file:"===e.location.protocol&&"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//)?"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";f=e.getElementsByTagName("script")[0];f.parentNode.insertBefore(a,f)}})(document,window.mixpanel||[]);
mixpanel.init("ENV['MIXPANEL_TOKEN']");
</script>
<!-- end Mixpanel -->
</head>
<body>
<%= render 'shared/flashes' %>
<%= yield %>
<%= render 'shared/footer' %>
<%= javascript_include_tag "http://maps.google.com/maps/api/js?libraries=places&key=#{ENV['GMAP_BROWSER_KEY']}" %>
<%= javascript_include_tag "http://cdn.rawgit.com/mahnunchik/markerclustererplus/master/dist/markerclusterer.min.js" %>
<%= javascript_include_tag 'application' %>
<%= yield :after_js %>
</body>
</html>
Last, the javascript code allowing the autocomplete on the input (having "user_input_autocomplete_address" as id) is in assets/javascript/autocomplete.js and is the following :
function initializeAutocomplete(id) {
var element = document.getElementById(id);
console.log('coucou');
if (element) {
var autocomplete = new google.maps.places.Autocomplete(element, { types: ['geocode', 'establishment'] });
google.maps.event.addListener(autocomplete, 'place_changed', onPlaceChanged);
}
}
function onPlaceChanged() {
var place = this.getPlace();
console.log(place); // Uncomment this line to view the full object returned by Google API.
for (var i in place.address_components) {
var component = place.address_components[i];
// console.log(component.types);
for (var j in component.types) { // Some types are ["country", "political"]
var type_element = document.getElementById(component.types[j]); // Returns the div with their differents ids or null if the id doesnt exist
// console.log(document.getElementById(component.types[j]));
if (type_element) {
type_element.value = component.long_name;
}
}
}
var formatted_address = document.getElementById('formatted_address');
// console.log(international_phone_number);
if (formatted_address) {
formatted_address.value = place.formatted_address;
}
for (var i in place.types) {
// console.log(place.types);
// console.log(i);
// console.log(place.types[i]);
var type_content = document.getElementById('category_' + i); // Returns the div with their differents ids or null if the id doesnt exist
// console.log(document.getElementById(component.types[j]));
if (type_content) {
console.log(place.types[i]);
type_content.value = place.types[i];
}
}
var international_phone_number = document.getElementById('phone_number');
// console.log(international_phone_number);
if (international_phone_number) {
international_phone_number.value = place.international_phone_number;
}
var name = document.getElementById('name');
if (name) {
name.value = place.name;
}
var gplace_id = document.getElementById('gplace_id');
if (gplace_id) {
gplace_id.value = place.place_id;
}
var website = document.getElementById('website');
if (website) {
website.value = place.website;
}
for (var i in place.opening_hours.weekday_text) {
var hours_open_in_db = place.opening_hours.weekday_text[i];
var hours_open_in_form = document.getElementById('hours_open_day_' + i);
if (hours_open_in_form) {
hours_open_in_form.value = hours_open_in_db;
}
}
}
google.maps.event.addDomListener(window, 'load', function() {
initializeAutocomplete('user_input_autocomplete_address');
});
In order to deploy all this on heroku, I already did the following :
"heroku run db:migrate" in the terminal (because I had some pending
migrations);
"figaro heroku:set -e production" in the terminal, in order to push all my API keys to heroku (I also checked that these keys are indeed in heroku's config vars).
in Google's developer console, within my project and within Google map javascript API, I ensured that my browser key is allowed for both my locahost and my domain name. In order to be very precise, I am using the same key for my locahost and my domain name. Until now, the only thing I have not managed to do yet, in Google's console, is to prove that I own my domain name.
I checked I have not reached any of my API quotas yet.
Within my autocomplete.js file, I used some console.log in order to find out, in my browser's inspector, what parts of the code are working. It seems that everything works except the console.logs that are in the 'OnPlaceChange' callback, since Gmap's autocomplete suggestions are not shown... ;
I know that not seeing the autocomplete suggestions is not a problem of z-index associated to the .pac-container css element, since I already had to fix this and since Gmaps suggestions cannot be reached thanks to my keyboard arrows.
I read this post about geocomplete (geocomplete for rails 4 not working in Heroku) and tried to precompile my assets. That did not lead to any change.
In my browser inspector (in the 'network' section), when I write something in my form input, every new letter pressed on the keyboard triggers a new request. These requests names are 'AutocompletionService.GetPredictions.....'. In the "headers" section, I can see they are https requests to googleapis, with get methods and 200 status code. In the "response" section, I can see there seems to be a error with my API keys since the message is :
/**/_xdc_._ty4oqn && _xdc_._ty4oqn( [3,null,null,"This API project is not authorized to use this API. Please ensure that this API is activated in the APIs Console: https://console.developers.google.com/apis/library?project=_ Please ensure this API is activated in the Google Developers Console: https://console.developers.google.com/apis/api/places_backend?project=_ For more information on authentication and Google Maps Javascript API services please see: https://developers.google.com/maps/documentation/javascript/get-api-key"] )
I followed the link in the error message, leading me to Google's console, and I get back to my project and API keys, which are settled both server-side and browser-side. Once again, the only thing i did not managed to do in Google's console was to prove I own my domain name.
Is this last point the origin of the issue (and in this case I guess I need some help from my hosting services) or do you guys see another mistake?
I has same issue too.
just goto google console, enable the "Google Places API Web Service", then it will solved the problem.
Enable "Google Places API Web Service" on Google API Console. It solved my problem when the website worked on localhost, but don't at Locaweb server.

How can I display every 4th product with different markup?

I'm just starting out with Ruby from a java background. I'm trying to code a particular loop but can't figure out the right syntax:
Could someone help me troubleshoot this please? I'm trying to write a loop but use different css classes to change the style of each block.
Realise this is probably easy, but help is appreciated....
<%= #products.each do |product, i| %>
<% if i % 1 %>
<div class="items-row clearfix">
<div class="one_fourth">
<div class="item-thumb">
<img src="<%= image_path "thumb.png" %>" alt="" class="thumb" width="162" height="230" />
</div>
<p><%= product.name %></p>
<p class="bold">$79.95 AUD</p>
<p class="color-wrap">
<span class="color" style="background:#ddd;"></span>
<span class="color" style="background:#f9f9f9;"></span>
<span class="color" style="background:green;"></span>
<span class="color" style="background:red;"></span>
</p>
</div>
<% elsif i % 4 %>
<div class="one_fourth last">
<div class="item-thumb">
<img src="<%= image_path "thumb.png" %>" alt="" class="thumb" width="162" height="230" />
</div>
<p><%= product.name %></p>
<p class="bold">$79.95 AUD</p>
</div>
</div><!-- end row -->
<% else %>
<div class="one_fourth">
<div class="item-thumb">
<img src="<%= image_path "thumb.png" %>" alt="" class="thumb" width="162" height="230" />
</div>
<p>Item Name</p>
<p class="bold">$79.95 AUD</p>
</div>
<% end %>
<% end %>
You can do something like this using cycle:
<% products.each_slice(4) do |slice| %>
<div class="items-row clearfix">
<% slice.each_with_index do |product,i| %>
<div class="one_fourth <%= cycle("first", "second", "third", "fourth") %>">
<%= render product %>
<% if i != 3 %>
<p class="color-wrap">
<span class="color" style="background:#ddd;"></span>
<span class="color" style="background:#f9f9f9;"></span>
<span class="color" style="background:green;"></span>
<span class="color" style="background:red;"></span>
</p>
<% end %>
</div>
<% end %>
</div>
<% end %>
_product.html.erb:
<div class="item-thumb">
<img src="<%= image_path "thumb.png" %>" alt="" class="thumb" width="162" height="230" />
</div>
<p><%= product.name %></p>
<p class="bold">$79.95 AUD</p>
Rather than if/else statements and CSS markup in your views, you should probably externalize your CSS, make a few partials, and make use of ActionView::Helpers::TextHelper#cycle. For example:
<%= #products.each do |product| %>
<div class="<%= cycle('first', 'second', 'third', 'fourth') -%>">
<!-- 1. let the CSS class handle display differences -->
<!-- 2. render a partial based on #current_cycle -->
<%= render :partial => current_cycle %>
</div>
<% end %>
I'd say the mod's are your problem. It's never going to go into the first block as n%1 will always return 0. Try your logic out using irb to get you going.
You may want to try jQuery nth-child
I got part of the answer. Slight change of syntax to use "each_with_index" instead of just each.
Still trying to work out there's a lot of variations of when a product can be the last tile and require closing, first on row, first in set, last in a row.....
Thanks guys, I think I've answered my own question.

Resources