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
Related
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])
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
I've been struggling with string interpolation inside an HTML accordion. It's more a logic issue that I can't seem to figure out (fairly new to rails). The problem I have is that while the layout is fine, when I click to collapse any of the 3 collapsible panels they all collapse. (Because I only have 1 #collapse).
Outermost ERB
<div class="container-fluid">
<div class="row">
<div class="col-md-2 col-sm-3">
<h2>Categorias</h2>
<div class="panel-group" id="accordion">
<%= render partial: "categories/catalog", collection: #categories, as: :c %>
</div>
</div>
_catalog Partial
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapse1">
<%= c.name %>
<span class="badge">4</span>
</a>
</h4>
</div>
<div id="collapse1" class="panel-collapse collapse in">
<% c.subcategories.each do |sc| %>
<div class="panel-body">
<a href="#">
<%= sc.name %>
</a>
</div>
<% end %>
</div>
</div>
Controller
def catalogo
#categories = Category.where("parent_id IS NULL")
unless params[:cat_id].blank?
#products = Product.where(category_id: params[:cat_id]).paginate(:page => params[:page], :per_page => 50)
else
#products = Product.all.paginate(:page => params[:page], :per_page => 50)
end
#categorieswparent = Category.where("parent_id IS NOT NULL")
end
Your IDs need to be unique. Instead of hard-coding id="collapse1", use the ID of the record:
id="collapse<%= sc.id %>"
Perform the same interpolation for the href of the <a> tag responsible for collapsing and expanding the accordion.
Use category id id="#collapse<%= c.id %>" to interpolate with element id in _catalog Partial.
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapse<%= c.id %>">
<%= c.name %>
<span class="badge">4</span>
</a>
</h4>
</div>
<div id="collapse<%= c.id %>" class="panel-collapse collapse in">
<% c.subcategories.each do |sc| %>
<div class="panel-body">
<a href="#">
<%= sc.name %>
</a>
</div>
<% end %>
</div>
</div>
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) }
Suppose there is a form page for Project, which has name and description. Take a look at the render :partial.
<div class="page-header">
<h2>{{project.id ? 'Edit ' : 'Add new'}} project</h2>
</div>
<div class="row">
<div class="col-xs-6 col-xs-offset-2">
<form class="form-horizontal">
<%= render :partial => 'templates/forms/text', :object => 'name', :locals => {:model => 'project'} %>
<%= render :partial => 'templates/forms/text', :object => 'description', :locals => {:model => 'project'} %>
<div class="form-group">
<div class="col-xs-offset-3 col-xs-9">
<button ng-click="saveProject()" type="submit" class="btn btn-success">Submit</button>
<a ng-href="{{ path('UserIndexCtrl') }}" class="btn btn-default">Back</a>
</div>
</div>
</form>
</div>
</div>
And here is a partial being used.
<div class="form-group" ng-class="{'has-error': errors.<%= text.underscore %>}">
<label for="<%= model %>.<%= text %>" class="col-xs-3 control-label"><%= text.titleize.humanize %></label>
<div class="col-xs-9">
<input id="<%= model %>.<%= text %>" name="<%= model %>.<%= text %>" type="<%= local_assigns[:type] || 'text' %>" class="form-control" ng-class="{'text-danger': true}" ng-model="<%= model %>.<%= text %>">
<span class="help-block" ng-show="errors.<%= text.underscore %>"><%= text.titleize.humanize %> {{errors.<%= text.underscore %>.join(', ')}}</span>
</div>
</div>
I am not sure this is the proper way to do a partial rendering in Rails + AngularJs combo. Wonder if there's a more angular-ish way? Thanks!
I would use a Helper to generate the input instead of writing directly in the HTML, something like:
def input_for_model(model_name, text, options = { }) # I actually have no idea what is doing your input, you can probably find a better name
options = { id: "#{model_name}.#{text}", name: "#{model_name}.#{text}",
type: 'text', class: 'form-control',
ng-class: "{'text-danger': true}",
ng-model: "#{model_name}.#{text}"
}.merge(options)
tag(:input, options)
end
And use it like this:
<div class="form-group" ng-class="{'has-error': errors.<%= text.underscore %>}">
<label for="<%= model %>.<%= text %>" class="col-xs-3 control-label"><%= text.titleize.humanize %></label>
<div class="col-xs-9">
<%= input_for_model(model, text, type: local_assigns[:type] || 'text') %>
<span class="help-block" ng-show="errors.<%= text.underscore %>"><%= text.titleize.humanize %> {{errors.<%= text.underscore %>.join(', ')}}</span>
</div>
</div>