I'm new to Ruby and I try to render an array which is in a separate file called database.rb:
Data = [
{
title: "First",
content: "Lorem ipsum...",
photo: "image1"
},
{
title: "Second",
content: "Eventually ...",
photo: "image2"
},
{
title: "Third",
content: "also to Kim’s ....",
photo: "image3"
}
]
I now want to render this array in a view.
In my app.rb I have this code:
require "sinatra"
require "sinatra/activerecord"
require_relative "database"
["/", "/articles"].each do |path|
get path do
#database = Data
erb :index
end
end
In my view index:
<% #database.each do |article| %>
<!-- Blog Post -->
<div class="card mb-4">
<img class="card-img-top" src="<%= article.photo %>" alt="">
<div class="card-body">
<h2 class="card-title oink"><%= article.title %></h2>
<p class="card-text oink"><%= article.content %></p>
</div>
<div class="card-footer text-muted">
</div>
</div>
<% end %>
How to get this to work? Because it seems that properties title, content and photo are not recognized.
What I should do? creating a model? but how?
Your array is made of hash items. If you want to stick with hashes, this is the way to access values (by key)
<!-- Blog Post -->
<div class="card mb-4">
<img class="card-img-top" src="<%= article[:photo] %>" alt="">
<div class="card-body">
<h2 class="card-title oink"><%= article[:title] %></h2>
<p class="card-text oink"><%= article[:content] %></p>
</div>
<div class="card-footer text-muted">
</div>
</div>
Otherwise, if you want to have methods, you might use Ruby Struct
Article = Struct.new(:title, :content, :photo)
Data = [
Article.new("First", "Lorem ipsum...", "image1"),
Article.new("Second", "Eventually ...", "image2"),
Article.new("Third", "also to Kim’s ....", "image3")
]
Now you can do it like in your snippet
Related
I have an hash in the format:
#meals = [
{
name: 'Roasted Chicken A La Ratatouille',
description: '',
tags: ['chicken'],
type: ['program'],
image_url: ''
},
{
name: 'Turkey Nuggets with Buffalo Cauliflower & Spinach',
description: '',
tags: ['turkey'],
type: ['program', 'veggies'],
image_url: ''
}
]
and I'd like to be able to unpack the meal type as class names for the element:
<% meals.shuffle.each do |meal| %>
<!-- Line in question -->
<div class="item col-3 p-2 a b <%= meal[:type].each {|t| t } %>">
<!-- End line in question -->
<div class="card">
<img class="card-img-top" src="<%= meal[:image_url] %>">
<div class="card-body">
<h5 class="card-title font-medium"><%= meal[:name] %></h5>
</div>
<div class="card-footer text-muted justify-content-center row">
<% meal[:tags].each do |tag| %>
<span style="margin: 2px;" class="badge bg-info-gradiant pointer"><%= tag %></span>
<% end -%>
</div>
</div>
</div>
<% end %>
But when the view renders, it displays as:
<div class="item col-3 p-2 a b ["program"]" style="position: absolute; left: 295px; top: 0px;">
<div class="card" style="height: 399px;">
...
</div>
</div>
Where program is displayed within the brackets. Is there a different way to accomplish this so that the values within the array are applied as class names?
You can use Array#join to explicitly convert the array of classes into a string of space-separated class names:
<div class="item col-3 p-2 a b <%= meal[:type].join(' ') %>">
How it works:
> meal[:type]
=> ["program", "veggies"]
> meal[:type].join(' ')
=> "program veggies"
Note that meal[:type].each does not do what you think it does. It calls the block for each element in the meal[:type] array with the expectation that the block performs a side effect (e.g. logging something or saving something), and then it returns the unmodified meal[:type] array. If you wanted to get a new array, you would have to use Array#map instead:
> meal[:type].each { |t| t.reverse }
=> ["program", "veggies"] # the block doesn’t affect the return value
> meal[:type].map { |t| t.reverse }
=> ["margorp", "seiggev"] # the block affects each returned element
Im stuck in a very simple problem. I am receiving an array of parameters in my view and want to iterate over the values.
This is the print of my params:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"dfOQVuXlQriII3akiGCSuMIf4i2B8c1/OX02nd6Dhy0ZKzHkhiXxlcXKCJAMFHw0vhtNKKVYuLHFo22LGsy6UQ==", "album"=>{"name"=>"asdasd", "photos_media"=>["[{\"id\":\"a245b724845f447eb63dfbaa3fba173669b55fcdf7fb55fb634707ff0c1c\",\"filename\":\"BWT_eUmU.jfif\",\"content_type\":\"image/jpeg\",\"size\":56060},{\"id\":\"1bfb4188a126079f5069c5204f8df1c7169d0464f488385ef1f8d081fcda\",\"filename\":\"drafts.png\",\"content_type\":\"image/png\",\"size\":6029}]"]}, "commit"=>"Save Album"}
My album_params are like this:
def album_params
params.require(:album).permit(:name, photos_media: [])
end
And my form:
<%= form_for #album do |f| %>
<div class="col-9">
<div class="form-group row" >
<div class="col-6">
<label for="">Name:</label>
<%= f.text_field :name %>
</div>
</div>
</div>
<div class="col-9">
<div class="form-group row" >
<div>
<div class="progress" id='progress-bar' style='display:none;'>
<div class="progress-bar progress-bar-striped active" role="progressbar" style="width: 0%"><h6>Loading...</h6>
<span class="sr-only" id='progress-bar-text'></span>
</div>
</div>
</div>
<div class="col-6">
<label for="">Add or drag photos here:</label>
<%= f.attachment_field :photos_media, multiple: true, direct: true, presigned: true %>
</div>
</div>
</div>
How can I iterate over photos_media? If I do a print on it like this:
logger.debug("******SIZE*** #{album_params[:photos_media].size} ")
It says the size is 1. Like a big string.
What im doing wrong?
As Vailisa says, photo_media contains an Array with one element that is a string:
"photos_media"=>["[{\"id\":\"a245b724845f447eb63dfbaa3fba173669b55fcdf7fb55fb634707ff0c1c\",\"filename\":\"BWT_eUmU.jfif\",\"content_type\":\"image/jpeg\",\"size\":56060},{\"id\":\"1bfb4188a126079f5069c5204f8df1c7169d0464f488385ef1f8d081fcda\",\"filename\":\"drafts.png\",\"content_type\":\"image/png\",\"size\":6029}]"]
Specifically, that string is a JSON string.
To parse that on the backend, you can try:
#photo_media_ary = JSON.parse(album_params[:album][:photos_media][0])
Currently, I have my data displayed like this (and it works fine)
<div class="container-fluid">
<% #entries.reverse.each do |entry| %>
<div class="card">
<div class="card-block">
<p class="card-title"><b><%= entry.title %></b></p>
<p class="card-text"><%= entry.link %></p>
</div>
</div>
<% end %>
</div>
Trying to change the layout to display the data in series of three cards like here: https://v4-alpha.getbootstrap.com/components/card/#card-decks
This is how I rewrote it:
<div class="card-deck">
<% #entries.each_slice(3) do |entry| %>
<div class="card">
<img class="card-img-top" src="..." alt="Card image cap">
<div class="card-block">
<h4 class="card-title"><%= entry.title %></h4>
<p class="card-text"><%= entry.link %></p>
</div>
<div class="card-footer">
<small class="text-muted">Last updated 3 mins ago</small>
</div>
<% end %>
</div>
<% #entries.each_slice(3) do |entry| %>
<div class="card">
<img class="card-img-top" src="..." alt="Card image cap">
<div class="card-block">
<h4 class="card-title"><%= entry.title %></h4>
<p class="card-text"><%= entry.link %></p>
</div>
<div class="card-footer">
<small class="text-muted">Last updated 3 mins ago</small>
</div>
<% end %>
</div>
<% #entries.each_slice(3) do |entry| %>
<div class="card">
<img class="card-img-top" src="..." alt="Card image cap">
<div class="card-block">
<h4 class="card-title"><%= entry.title %></h4>
<p class="card-text"><%= entry.link %></p>
</div>
<div class="card-footer">
<small class="text-muted">Last updated 3 mins ago</small>
</div>
<% end %>
</div>
</div>
This is the error I receive when I try to display the page now:
NoMethodError in Entries#index
undefined method `title' for #<Array:0x007fa6dab11a10>
Why am I receiving this error?
Thank you for your help. Please let me know if this question needs further clarification and/or more information.
Further information:
require 'open-uri'
module RedditScrapper
def self.scrape
doc = Nokogiri::HTML(open("https://www.reddit.com/"))
entries = doc.css('.entry')
entries.each do |entry|
title = entry.css('p.title > a').text
link = entry.css('p.title > a')[0]['href']
category = entry.css('p.tagline > a')[0]['href']
Entry.create!(title: title, link: link, category: category )
end
end
end
<div class="card-columns">
<% #entries.reverse.each do |entry| %>
<div class="card">
<div class="card-block">
<p class="card-title"><b><%= entry.title %></b></p>
<p class="card-text"><%= entry.link %></p>
</div>
</div>
<% end %>
</div>
Scss:
.card-columns {
#include media-breakpoint-only(lg) {
column-count: 3;
}
#include media-breakpoint-only(xl) {
column-count: 3;
}
}
each_slice returns an array, and trying to access title or link on an array will return this error. To access the data, you would have to grab by index in the sliced arrays.
I'm new to Rails so my code is probably ugly..
I have a loop which give me the 3 latest articles on my index page.
I added a condition to say "if there is no image in my article, give me a image from unsplash".
The issue is : that's apply the condition on the 3 images even if 2 of 3 images exists. I want that only the image which is nil get the unsplash image.
How can I do that ?
<% #articles.last(3).in_groups_of(3, false).each do |group| %>
<div class="row">
<% group.each do |article| %>
<% if article.image.exists? %>
<div class="col-xs-12 col-sm-4">
<div class="card">
<style media>
.card { background: linear-gradient(-225deg, rgba(30,30,30,0.6) 30%, rgba(46,46,46,0.5) 80%), url("<%= article.image.url(:medium) %>"); }
</style>
<img src="<%= article.user.image.url(:thumb) %>" alt="" class="avatar-small card-user">
<div class="card-description">
<h3><%= article.title %></h3>
<p><%= truncate(article.subtitle, length: 45, escape: false) %></p>
</div>
</div>
</div>
<% else %>
<div class="col-xs-12 col-sm-4">
<div class="card">
<style media>
.card { background: linear-gradient(-225deg, rgba(30,30,30,0.6) 30%, rgba(46,46,46,0.5) 80%), url("http://unsplash.it/1280/500/?random"); }
</style>
<img src="<%= article.user.image.url(:thumb) %>" alt="" class="avatar-small card-user">
<div class="card-description">
<h3><%= article.title %></h3>
<p><%= truncate(article.subtitle, length: 45, escape: false) %></p>
</div>
</div>
</div>
<% end %>
<% end %>
</div>
<% end %>
my controller :
class PagesController < ApplicationController
def index
#articles = Article.last(3)
end
end
Thanks a lot for your help !
I finally find the error.
It was <style media> which was the issue.
I finally do this :
<% #articles.last(3).in_groups_of(3, false).each do |group| %>
<div class="row">
<% group.each do |article| %>
<div class="col-xs-12 col-sm-4">
<a href="<%= articles_path(article.slug) %>"><div style="background: linear-gradient(-225deg, rgba(30,30,30,0.6) 30%, rgba(46,46,46,0.5) 80%), url('<%= article.image.url(:thumb) %>');" class="card">
<img src="<%= article.user.image.url(:thumb) %>" alt="" class="avatar-small card-user">
<div class="card-description">
<h3><%= article.title %></h3>
<p><%= truncate(article.soustitre, length: 45, escape: false) %></p>
</div>
</div>
</div></a>
<% end %>
</div>
<% end %>
Now the 3 latest articles are displayed on my index page.
I add a default image with paperclip and withdrawed the condition if else.
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