Using Masonry in Rails - boxes not moving on window resize - ruby-on-rails

I have tried this using both the files from the Masonry website, plus the masonry-rails gem, but am getting the same problem.
Basically, when I resize the browser window, the boxes aren't moving to fit the new page size. Instead, I'm just getting scroll bars appearing in the browser.
I know that the files are loading fine, and picking up the right selectors, because if I e.g. change the column width in the masonry() parameters, the boxes do appear in a different place when I load the page.
Also, I'm using Bootstrap if that's relevant, but I've named the selectors so they don't clash with the ones reserved for bootstrap - e.g. using #masonry-container instead of #container.
Any help would be much appreciated, thanks!!
application.js:
//= require masonry/jquery.masonry
message_board/show:
<div id="show-message-board">
<%= render :partial => "show_message_board", :locals => { :messages => current_user.messages }, :remote => true %>
</div>
<script>
$(function(){
$('#masonry-container').masonry({
// options
itemSelector : '.item',
columnWidth : 50,
isAnimated: true
});
});
</script>
_show_message_board.html.erb:
<div id="masonry-container" class="transitions-enabled infinite-scroll clearfix">
<% messages.each do |message| %>
<div class="item">
<p class="message_from"><%= message.user.first_name %> <%= message.user.last_name %>:</p>
<p class="message_content"><%= message.content %></p>
</div>
<% end %>
EDIT:
I've tried using the following as suggested elsewhere, and that still doesn't work!:
$(function(){
var $container = $('#masonry-container');
$container.imagesLoaded( function(){
$container.masonry({
itemSelector : '.item'
});
});
});

Here's what I did to get Masonry to work in my Rails project. Perhaps this will help you...
I downloaded the "jquery.masonry.min.js" file from the site and placed it in my app\assets\javascripts directory.
I added
//= require jquery.masonry.min to my application.js file
I created a separate css file for masonry (just to keep things neat) called "masonry.css.scss" under my app\assets\stylesheets directory. This is the CSS I have (I'm using "box" instead of your "item"):
.box {
margin: 5px;
padding: 5px;
background: #D8D5D2;
font-size: 11px;
line-height: 1.4em;
float: left;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
display: inline;
width: 260px;
}
.box img {
width: 100%;
}
Since I'm using the code in my "home\index.html.erb" file, I created a "home.js" file under my app\assets\javascripts" directory. This is the js code I have:
jQuery(document).ready(function () {
var $container = $('#UserShoppingRequestsContainer');
$container.imagesLoaded(function () {
$container.masonry({
itemSelector:'.box',
isAnimated:true,
animationOptions:{
duration:750,
easing:'linear',
queue:false
}
});
});
})
Finally, in my "home\index.html.erb" file, I have something like this:
<div id="UserShoppingRequestsContainer">
<% #shopping_requests.each do |shopping_request| %>
<div class="box col3" id="<%= shopping_request.id.to_s %>">
<%= link_to image_tag(shopping_request.request_picture.url(:medium)), user_shopping_request_path(shopping_request.user, shopping_request) %>
<p class="serif1_no_padding"><%= shopping_request.category.name %></p>
</div>
<% end %>
</div>
I think that's it.

Related

data-autoscroll-block "start" position of turbo_frame option is misaligned

I would like to use the data-autoscroll-block attribute described in Turbo Reference to set the scroll position to TOP when screen transitions by turbo_frame, but it is not completely at the top position.
Since the navbar is sticky, I'm guessing that the height (specifically, 64px) will be shifted.
<%# Applicable index view %>
<%= turbo_frame_tag "entries", autoscroll: true, data: { autoscroll_block: "start" } do %>
contents
<% end %>
<%# navbar view %>
<header class="sticky top-0 z-10 bg-white w-full h-16....">
contents
</header>
Any advice on how to fix this would be appreciated.
You can try offsetting it with css. For some reason the snippet scrolls the actual page as well, just "Run code snippet" and go "Full page".
// fake the turbo frame navigation, ignore this part
document.querySelector("turbo-frame a").onclick = event => {
event.preventDefault();
var frame = event.target.closest("turbo-frame");
var data = frame.dataset;
frame.scrollIntoView({
behavior: data.autoscrollBehavior,
block: data.autoscrollBlock
});
}
.scroller {
scroll-snap-type: y;
scroll-padding-block-start: 64px;
}
header {
position: sticky;
top: 0px;
height: 64px;
border: 1px solid;
}
.spacer {height: 50px;}
.spacer-xl {height: 1600px;}
<html class="scroller">
<body>
<div class="spacer"></div>
<header>
HEADER. Why you scroll the actual page?! <br> Sorry, Stackoverflow.
</header>
<div class="spacer"></div>
<turbo-frame autoscroll="true" data-autoscroll-block="start" data-autoscroll-behavior="smooth">
inside the frame click me
</turbo-frame>
<div class="spacer-xl"></div>
</body>
</html>

How do I get Ruby on Rails to display data as a Bootstrap grid?

I am applying the Bootstrap 4 album template to a Ruby on Rails website I am developing. The original album template looks like this:
But mine is not displaying like that. It's displaying as a list, one beneath the other, similar to what a blog page would look like.
I believe the file where I need to make the necessary changes is here in app/views/products/index.hmtl.erb:
<div class="album text-muted">
<div class="container">
<div class="row">
<div class="card">
<%= render #products %>
<% #products.each do |product| %>
<%= product.image %>
<% end %>
<p class="card-text">
<% #products.each do |product| %>
<%= product.description %>
<% end %>
</p>
</div>
</div>
</div>
</div>
<%= paginate #products %>
<%= link_to 'New Product', new_product_path if logged_in?(:site_admin) %>
I am not missing any of the Bootstrap classes from the original template, so I am wondering if its my code that is causing it not to render appropriately.
Here is the stylesheets/products.scss file:
// Place all the styles related to the products controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
// Custom bootstrap variables must be set or imported *before* bootstrap.
#import "bootstrap";
#import "font-awesome";
body {
min-height: 75rem; /* Can be removed; just added for demo purposes */
}
.navbar {
margin-bottom: 0;
}
.jumbotron {
padding-top: 6rem;
padding-bottom: 6rem;
margin-bottom: 0;
background-color: #fff;
}
.jumbotron p:last-child {
margin-bottom: 0;
}
.jumbotron-heading {
font-weight: 300;
}
.jumbotron .container {
max-width: 40rem;
}
.album {
min-height: 50rem; /* Can be removed; just added for demo purposes */
padding-top: 3rem;
padding-bottom: 3rem;
background-color: #f7f7f7;
}
.card {
float: left;
width: 33.333%;
padding: .75rem;
margin-bottom: 2rem;
border: 0;
}
.card > img {
margin-bottom: .75rem;
}
.card-text {
font-size: 85%;
}
footer {
padding-top: 3rem;
padding-bottom: 3rem;
}
footer p {
margin-bottom: .25rem;
}
/*
* Custom styles
*/
.social-links li a {
font-size: 1.5em;
}
try this code for your index.html.erb:
<div class="album text-muted">
<div class="container">
<div class="row">
<% #products.each do |product| %>
<div class="card">
<%= image_tag("picture_holder")%>
<strong class="card-text"><%= product.summary %></strong>
<a href="<%= product_path(product) %>"><%= image_tag("picture_holder")%><a>
<p class="card-text"><%= product.price %></p>
<p class="card-text"><%= product.description %></p>
</div>
<% end %>
</div>
<div class="row">
<div class="col-md-12">
<%= paginate #products %>
</div>
</div>
</div>
</div>
it should work.
I'd like for you to try to output the image and the description in the same iteration.
<% #products.each do |product| %>
<div class="card">
<%= product.image %>
<p class="card-text">
<%= product.description %>
</p>
</div>
<% end %>
Note that here I can see they are displaying their images like so
<img data-src="holder.js/100px280/thumb"
alt="100%x280" style="height: 280px; width: 100%;
display: block;" src="some/path/" data-holder-rendered="true">
Notice the inline styles that are being applied here. Also, I'm not sure if product.image is a path to an image or an actual binary image. if it's the former you'll need to put it into the src= attribute of an img tag similar to the one bootstrap uses in their example.
<img scr='<%= product.image %>' />

Targeting dynamic class names in css/scss or JavaScript

In my rails application I have two models, Users and Goals. A User can have Many Goals, and a Goal belongs to a User. I have a page that lists all of a users Goals in the users show page. This is done using a .each loop, and in this loop I have created a dynamic class name that puts the goal_id into the class name.
I want to be able to target these individual classes in my css/scss folder so that I can, for example, have only the first goal be highlighted when I hover over it.
app/views/users/show.html.erb
<div class="user-goals-mouse-events">
<% #user.goals.each do |goal| %>
<%= link_to goal_path(goal), class: "user-goals-hover-#{goal.id}" do %>
<div class="row">
<div class="col-md-4">
<h2 class="color-light-blue"><%= goal.name %></h2>
</div>
<div class="col-md-8 user-goals-description">
<h4><%= goal.description %></h4>
</div>
</div>
<h6 class="hide-username-<%= goal.id %>"><%= #user.username %></h6>
<% end %>
<% end %>
The Scss is not working currently but it may help show what i'm attempting to do.
app/assets/stylesheets/custom.css.scss
.user-goals-mouse-events > a {
border-bottom-style: solid;
border-bottom-color: black;
border-bottom-width: 1px;
//background-color: black;
&:hover {
background-color: #26AEFF;
color: gold;
}
}
.user-goals-mouse-events > div > h6 {
opacity: 0;
}
.color-light-blue {
color: #26AEFF;
&:hover {
color: white;
}
}
If a better solution to this problem is done a different way (e.g. with javascript) then please let me know as I want to do it the most efficient way.
Try to use the attribute-value-begins-with selector:
a[class^=user-goals-hover] {
border-bottom-style: solid;
border-bottom-color: black;
border-bottom-width: 1px;
//background-color: black;
&:hover {
background-color: #26AEFF;
color: gold;
}
}
#hashrocket answer is good, but I'd advise to be more explicit on your classes. It is a code smell when you need a class both for styling and for targeting.
Yes, there is such a thing as code smell in CSS too! :)
I would have a constant class for styling and a dynamic one or even a completely different attribute for targeting:
<%= link_to goal_path(goal), class: "user-goals", data: {goal_id: goal.id} do %>
which would render as
<a href="/goals/42" class="user-goals" data-goal-id="42">
and the css would just be
.user-goals {
//...
&:hover {
//...
}
}

Show banner and menu navigation bar on all pages

I am new to Rails. I am using Aptana Studio 3 to write a small application.
In the Views folder, I added a new .html.erb page and added a jQuery navigation menu bar. This page also has a banner. I want to keep this as a base page (like Master Page in .NET) for all the other pages.
I want all the other pages to automatically show the banner and menu bar on top.
How to do this? I am using Rails 3.2.
Edited
Code of application.html.erb:
<!DOCTYPE html>
<html>
<head>
<title></title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
<script type="text/javascript" src="..\Libraries\jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('li.headlink').hover(
function() { $('ul', this).css('display', 'block'); },
function() { $('ul', this).css('display', 'none'); });
});
</script>
<style type="text/css" rel="stylesheet">
/* General */
#cssdropdown, #cssdropdown ul { list-style: none; }
#cssdropdown, #cssdropdown * { padding: 0; margin: 0; }
/* Head links */
#cssdropdown li.headlink { width: 220px; float: left; margin-left: -1px; border: 1px black solid; background-color: #e9e9e9; text-align: center; }
#cssdropdown li.headlink a { display: block; padding: 15px; }
/* Child lists and links */
#cssdropdown li.headlink ul { display: none; border-top: 1px black solid; text-align: left; }
#cssdropdown li.headlink:hover ul { display: block; }
#cssdropdown li.headlink ul li a { padding: 5px; height: 17px; }
#cssdropdown li.headlink ul li a:hover { background-color: LightBlue; color:Black }
/* Pretty styling */
body { font-family: verdana, arial, sans-serif; font-size: 0.8em;}
#cssdropdown a { color: white; } #cssdropdown ul li a:hover { text-decoration: none; }
#cssdropdown li.headlink { background-color: Blue;}
#cssdropdown li.headlink ul { background-position: bottom; padding-bottom: 10px; }
</style>
</head>
<body>
<%= yield %>
<div id="divMain">
<div id="divHeader">
<img src="..\Images\W.png">
</div>
<div id="divMenu">
<ul id="cssdropdown">
<li class="headlink">
Task
<ul>
<li>Add New</li>
</ul>
</li>
<li class="headlink">
Reports
<ul>
<li>Report</li>
</ul>
</li>
</ul>
</div>
</div>
<div id="content"><%= content_for?(:content) ? yield(:content) : yield %></div>
</body>
</html>
Code of Content.html.erb
<% content_for :stylesheets do %>
<div id="divLogin">
</div>
<% end %>
<% content_for :MainContent do %>
<div id="divMain">
</div>
<% end %>
<%= render :partial => "layouts\application.html.erb" %>
Rails uses layouts as master templates. As default will you have one master layout template called application, which you can find in app/views/layouts/application.html.erb. If you look at this file will you see something like:
# app/views/layouts/application.html.erb
<html>
<head>
...
</head>
<body>
...
<div id="content">
# Your page content will be inserted here:
<%= yield %>
</div>
...
</body>
</html>
As default will this be rendered for all pages, and the content of each page (fx your new.html.erb) would be rendered in the yield block.
This means that application.html.erb is the right place to but generel layout stuff, like menus and banners that should appear on all pages.
If you want to have something that varies a bit for each page (fx different banners) can you add a special <%= yield(:banner) if content_for?(:banner) %> in your application.html.erb file. You will then be able to add a block in each of your pages for a banner like this:
# app/views/some_resource/some_page.html.erb
<% content_for(:banner) do %>
# insert page specifik banner here
<% end %>
# normal content for page
...
I hope this answers your question?
You can also read more about layouts (fx how to use more then one layout) on http://guides.rubyonrails.org/layouts_and_rendering.html
Edit: correct way to implement content.html.erb
The content of content.html.erb should be:
# What is this? This has nothing to do with stylesheets?
<% content_for :stylesheets do %>
<div id="divLogin">
</div>
<% end %>
<div id="divMain">
</div>
So no content_for :MainContent block and don't render the ´application.html.erb´ layout template (it's not even a partial, so you can't do this).
You can use nested layouts as described here.
Watch from 5:18,
from what I've read I think thats kind of what you may be looking for.
Hope it helps.
Railscast #328
Also here is a link to Twitter's bootstrap navbar which you may want to look into. It will show a banner and navigation bar on all pages and is fairly easy to set up.
http://twitter.github.io/bootstrap/components.html#navbar
One of the best sources for this topic is the beginning of the book The Rails View. Here is the link: The Rails View
This really helps with the content_for helper method, which will become your friend instantly once you know how to use it.

customising the look of f.file.field in rails

<div id="photo_attachment_container">
<%= f.file_field :photo %>
</div>
Currently this just looks like a button, how can I add some css and customise the look (e.g dimensions background etc) of this button? Thanks
The HTML file field has been, and remains, one of the most least customizable of the HTML form controls. The other problem is that it is rendered so differently between browsers and OSes. The best way to style these controls is to render the file control as a transparent element on top of another button or set of elements that is styled the way you want. The file control does not need to be visible to be activated with a user click, but it does need to be on the top most layer (sending it click or focus events doesn't work in my tests).
Here's some example HTML:
<div id="test">
<div class="wrapper">
<input type="file" />
</div>
<button>Select a file</button>
</div>
The CSS renders the wrapper div and button as absolutely positioned elements. The button is visible and styled while the wrapper which contains the file field is transparent. I've set the wrapper field to reduce transparency when you hover over it to illustrate its positioning relative to the styled button underneath.
#test {
position: relative;
}
#test .wrapper {
opacity: 0;
cursor: pointer;
position: absolute;
top: 0;
z-index: 2;
}
#test .wrapper:hover {
opacity: 0.5;
}
#test button {
background-color: #ccc;
border: none;
color: #666;
padding: 3px 5px;
border-radius: 5px;
position: relative;
top: 0;
z-index: 1;
}
Example on JS fiddle.
http://jsfiddle.net/JgDuh/
EDIT:
To answer the question you asked in your comment, you would structure the above answer in your Rails view template like this:
<div id="photo_attachment_container">
<div class="wrapper">
<%= f.file_field :photo %>
</div>
</div>
This would render as (Note that I used user as the substitute for whatever model you passed in form_for):
<div id="photo_attachment_container">
<div class="wrapper">
<input type="file" id="user_photo" name="user[photo]" />
</div>
</div>

Resources