I have a Ruby on Rails app that allows a user to save up to 6 images that can then be viewed in a carousel.
The images are saved as strings as image, image_2, image_3, image_4, image_5, image_6.
I want to be able to write a 'for' loop to display all of the images in my carousel.
What is the best method of combining all of these image strings into an array so that they can then be looped through and outputted by the carousel?
Further Details
I am currently calling the images like below which works but isn't particularly DRY.
<div style="position:relative">
<div id="home-carousel" class="carousel">
<div class="carousel-inner">
<div class="item active">
<%= image_tag #place.image %>
</div>
<% if #place.image_2.present? %>
<div class="item">
<%= image_tag #place.image_2 %>
</div>
<% end %>
<% if #place.image_3.present? %>
<div class="item">
<%= image_tag #place.image_3 %>
</div>
<% end %>
<% if #place.image_4.present? %>
<div class="item">
<%= image_tag #place.image_4 %>
</div>
<% end %>
<% if #place.image_5.present? %>
<div class="item">
<%= image_tag #place.image_5 %>
</div>
<% end %>
<% if #place.image_6.present? %>
<div class="item">
<%= image_tag #place.image_6 %>
</div>
<% end %>
</div>
</div>
</div>
I would like to be able to turn what I have below into a simple for loop that will go through each of the 6 image objects and return the ones that are there. Something more like this:
<div style="position:relative">
<div id="home-carousel" class="carousel">
<div class="carousel-inner">
<% #place.images.each do |image| %>
<div class="item">
<%= image_tag image %>
</div>
<% end %>
</div>
</div>
</div>
The simple solution is to add a helper. So in helpers/places_helper.rb write
module PlacesHelper
def get_carrousel_images(place)
[
#place.image_1,
#place.image_2,
#place.image_3,
#place.image_4,
#place.image_5,
#place.image_6
].select {|img| img.present? }
end
and then you can write the following in your view:
<div style="position:relative">
<div id="home-carousel" class="carousel">
<div class="carousel-inner">
<% get_carrousel_images(#place).each do |image| %>
<div class="item">
<%= image_tag image %>
</div>
<% end %>
</div>
</div>
</div>
Now having the 6 image_x fields for place looks a bit smelly, so I would prefer a nested model instead as Rich Peck proposes, although I understand having the 6 fields is easier to start with.
Images
It will all depend on how you've set up the images in the db, and how you'd like to show them in the view
If you have the images in the User model, you could call them like this:
app/controllers/users_controller.rb
Class UsersController < ApplicationController
def show
#user = User.find params[:id]
#images = #user.images
end
end
This is obviously very generalised - I would recommend you post some context to your question, so we know what you're asking specifically
--
Paperclip
If you're using Paperclip or Carrierwave, you'll basically have the images attached to various objects in your database. For example, you'll have the following:
#app/models/image.rb
Class Image < ActiveRecord::Base
has_attached_file :attachment
end
This allows you to call:
#images = Image.all
#images.each do |image|
image.attachment.url #-> image URL
end
This is the standard way to handle images / attachments in Rails, as it ties directly into ActiveRecord. Returning an array of image paths would therefore be a case of calling Model.all or Model.where
Related
I'm making a sports app to learn Rails. I've figured out how to call the API and display it how I want, but right now, I'm putting the full array in my view every time I want to call any key.
For instance, I want to make a page that shows the starting line-ups for teams using the JSON from the API, and right now I have it displaying, but the code within the view itself is pretty big and ugly.
My view:
<%= stylesheet_link_tag 'lineups' %>
<div id="lineupcontainter">
<div id= "team1lineup">
<div id= "player1"><%= #schedule["data"][0]["lineup"]["data"][0]["player_name"] %>
<div id= "playerphotos"> <%= image_tag #schedule["data"][0]["lineup"]["data"][0]["player"]["data"]["image_path"] %> </div> </div>
<div id= "player1"><%= #schedule["data"][0]["lineup"]["data"][1]["player_name"] %>
<div id= "playerphotos"> <%= image_tag #schedule["data"][0]["lineup"]["data"][1]["player"]["data"]["image_path"] %> </div> </div>
<div id= "player1"><%= #schedule["data"][0]["lineup"]["data"][2]["player_name"] %>
<div id= "playerphotos"> <%= image_tag #schedule["data"][0]["lineup"]["data"][2]["player"]["data"]["image_path"] %> </div> </div>
<div id= "player1"><%= #schedule["data"][0]["lineup"]["data"][3]["player_name"] %>
<div id= "playerphotos"> <%= image_tag #schedule["data"][0]["lineup"]["data"][3]["player"]["data"]["image_path"] %> </div> </div>
<div id= "player1"><%= #schedule["data"][0]["lineup"]["data"][4]["player_name"] %>
<div id= "playerphotos"> <%= image_tag #schedule["data"][0]["lineup"]["data"][4]["player"]["data"]["image_path"] %> </div> </div>
<div id= "player1"><%= #schedule["data"][0]["lineup"]["data"][5]["player_name"] %>
<div id= "playerphotos"> <%= image_tag #schedule["data"][0]["lineup"]["data"][5]["player"]["data"]["image_path"] %> </div> </div>
<div id= "player1"><%= #schedule["data"][0]["lineup"]["data"][6]["player_name"] %>
<div id= "playerphotos"> <%= image_tag #schedule["data"][0]["lineup"]["data"][6]["player"]["data"]["image_path"] %> </div> </div>
<div id= "player1"><%= #schedule["data"][0]["lineup"]["data"][7]["player_name"] %>
<div id= "playerphotos"> <%= image_tag #schedule["data"][0]["lineup"]["data"][7]["player"]["data"]["image_path"] %> </div> </div>
<div id= "player1"><%= #schedule["data"][0]["lineup"]["data"][8]["player_name"] %>
<div id= "playerphotos"> <%= image_tag #schedule["data"][0]["lineup"]["data"][8]["player"]["data"]["image_path"] %> </div> </div>
</div>
My controller
def game1
#response = RestClient.get "https://soccer.sportmonks.com/api/v2.0/fixtures/between/2022-02-01/2022-02-04/62?api_token=____&include=lineup.player,"
{content_type: :json, accept: :json, "user_key": "____"}
#schedule = JSON.parse(#response)
render JSON: #schedule
end
What can I do to create something where I don't have to call the entire array every time I want to put something in views?
Something like this should work:
<div id="lineupcontainter">
<div id= "team1lineup">
<% #schedule["data"][0]["lineup"]["data"].each do |cur_schedule|%>
<div id= "player1">
<%= cur_schedule["player_name"] %>
<div id= "playerphotos">
<%= image_tag cur_schedule.dig("player", "data", "image_path") %>
</div>
</div>
<% end %>
</div>
Also, your controller has some redundant logic. You are parsing a JSON string and turning it into a ruby hash, then you take that hash and render it as a JSON string. You should be able to render the json directly.
If you want to reduce the lines of code in your template, you can iterate over the instance variable in the .erb file. This bit of code should work if you put it in your erb file:
<div id="lineupcontainter">
<div id="team1lineup">
<!-- iterating on team 1 -->
<%= #schedule["data"][0]["lineup"]["data"].map.with_index do |data, index| %>
<!-- index will increase by 1 each iteration, starts at 0 -->
<div id="player1"><%= data[index]["player_name"] %>
<div id="playerphotos"> <%= image_tag data[index]["player"]["data"]["image_path"] %></div>
</div>
<% end %>
</div>
</div>
I would recommend parsing that data in your controller before sending it to the template, something like this:
def game1
#response = RestClient.get "https://soccer.sportmonks.com/api/v2.0/fixtures/between/2022-02-01/2022-02-04/62?api_token=____&include=lineup.player,"
{content_type: :json, accept: :json, "user_key": "____"}
schedule = JSON.parse(#response)
# in the ERB, replace schedule["data"][0]["lineup"]["data"] with #lineup_data
#lineup_data = schedule["data"][0]["lineup"]["data"]
render JSON: #lineup_data
end
Another note: you do not need to call render json: #schedule in your controller. That will call .to_json on the instance variable and it's unnecessary when rendering data in an ERB template. The Rails MVC design allows the template to access instance variables defined in controllers. See section 2.2.8 Rendering JSON for documentation.
def game1
#response = RestClient.get "https://soccer.sportmonks.com/api/v2.0/fixtures/between/2022-02-01/2022-02-04/62?api_token=____&include=lineup.player,"
{content_type: :json, accept: :json, "user_key": "____"}
schedule = JSON.parse(#response)
#lineup_data = schedule["data"][0]["lineup"]["data"]
end
As Rookie Rails, i am able to get all images to display on the html.erb as using model as has_many_attached :images
but i have tried many different way like this code below
<div class="row">
<div class="col-md-12">
<% if #tool.images.attached? %>
<% #tool.images.each do |image| %>
<div class="img-fluid <%= 'active' if image.id == #images[0].id %>">
<%= link_to image_tag(image), image %>
</div>
<% end %>
<% end %>
</div>
</div>
but didn't show one image but only a few images as I am trying to fix this
image.id == #images[0].id
this code is dont display one image, do you know where i can use this code into this as i have tried many way but all failed
if i use this code
<!-- Image -->
<div class="row">
<div class="col-md-12">
<% if #tool.images.attached? %>
<% #tool.images.each do |image| %>
<%= link_to image_tag(image, class:"tools-gallery"), image %>
<% end %>
<% end %>
</div>
</div>
<br/>
it show fine and able to get displayed
but I don't want two images or more, it ok for the gallery but not this pages as it need show one image.
and the controller.rb
def show
#images = #tool.images
end
<div class="row">
<div class="col-md-12">
<%= image_tag #tool.images.first if #tool.images.attached? %>
</div>
</div>
So, I have an app that is trying render 2 (or maybe more if needed) columns using a loop. It does one column and looks pretty good, but I want the option of 2 or even more. I know about "in_groups.of()", but I can't quite figure it out to work with my
<% #vendors.each do |vendor| %>
<%= link_to vendor do %>
<div class="row">
<div class="col-md-6">
<div class="card-container">
<div class="col-md-6">
<div class="card">
<%= image_tag attachment_url(vendor, :background_image), class: 'card-img-top' %>
<div class="card-block">
<h4 class="card-title"><%= vendor.Company %>. </h4>
<p class="card-text"><%= vendor.Description.html_safe.first(25) %></p>
<div class="card-standing"><strong><%= vendor.FinancialStanding %></strong></div>
</div>
</div>
</div>
</div>
</div>
</div>
<% end %>
<% end %>
Not sure why you needed this, because everything can be managed with css and html. But you can make changes like this:
<% #vendors.to_a.in_groups_of(2).each do |vendor| %> # #vendors.to_a cover AR to array
<% vendor.each do |v| %> # becuase vendor is array here.
..........your code..............
<% end %>
<% end %>
On my user profile, I want to add 4 of the latest photos uploaded by that user. Originally, I had <%- #user.photos.last(4).each do |photo| %>. This code works, but it doesn't work with my layout. So I need one row that displays the last 2 photos, while the second row displays the last 3-4 photos.
Here is what I came up with and the line <%- #user.photos.last(3,4).each do |photo| %> does not work. I've also tried (3-4)
<div class="photo-box">
<%- #user.photos.last(2).each do |photo| %>
<a href="<%= user_photo_path(#user.username, photo.id) %>" class="photo-thumbnail">
<div class="photo-mini">
<%= image_tag photo.url %>
</div>
</a>
<% end %>
</div>
<div class="photo-box">
<%- #user.photos.last(3,4).each do |photo| %>
<a href="<%= user_photo_path(#user.username, photo.id) %>" class="photo-thumbnail">
<div class="photo-mini">
<%= image_tag photo.url %>
</div>
</a>
<% end %>
</div>
You can use the [] method on the photos array.
-1 gets the last element, -2 gets the 2nd to last, and so on.
#user.photos[-2..-1].each #=> return the last two pictures
Of course, you can simply use the #user.photos.last(2).each in this case.
#user.photos[-4..-3].each #=> return the last 3-4 pictures.
This will throw an error unless #user.photos has a length of at least 4, otherwise, you will be trying to access values that does not exist. So, to check for that, you can wrap the div in an if statement.
<% if #user.photos.length >= 2 %>
<div class="photo-box">
<% #user.photos.last(2).each do |photo| %>
...
<% end %>
</div>
<% end %>
<% if #user.photos.length >= 4 %>
<div class="photo-box">
<% #user.photos[-4..-3].each do |photo| %>
...
<% end %>
</div>
<% end %>
I would get the last four in an array, and then divide them into two sets of two using #in_groups_of.
You can then iterate through the two arrays of two photos each to create the divs. This methods easily extends to n groups of m photos.
Something like:
<%- #user.photos.last(4).in_groups_of(2, false).each do |photo_group| %>
<div class="photo-box">
<%- photo_group.each do |photo| %>
<a href="<%= user_photo_path(#user.username, photo.id) %>" class="photo-thumbnail">
<div class="photo-mini">
<%= image_tag photo.url %>
</div>
</a>
<% end %>
</div>
I'm trying to display a simple collapsible set from a rails app. It works perfectly the first time, giving me the output below.
However, when I go back to the page (via the "Save changes" form submit), additional labels are appearing, and I can't work out why:
My index.html.erb file is as follows:
<div data-role="page" data-url="<%= request.path %>">
<div data-role="header">
<h1> CB </h1>
</div>
<div data-role="content">
<div data-role="collapsible-set">
<% #gr.each do |g| %>
<div id=" <%= g %>" data-role="collapsible">
<h3> <%= g %> </h3>
<p>
<%=form_tag "/checkboxen", method: :get do %>
<% #gr2.each do |g2| %>
<%= check_box_tag "#{g}_#{g2}" %>
<%= label_tag "#{g}_#{g2}",g2 %>
<% end %>
<%= submit_tag %>
<% end %>
</p>
</div>
<% end %>
</div>
</div>
While my (very simple) checkboxen_controller.rb is this:
class CheckboxenController < ApplicationController
def index
#gr=["one","two","three"]
#gr2=["a","b","c"]
end
end
As you can probably guess, I'm a newbie to this, and can't work out why it's happening (if it matters, I've turned turbolinks off, and have no unusual javascript in the system).
I've found a work-around: instead of using <%= label_tag %> I explicitly enclosed the check_box_tag in a <label> ... </label>. Why the original didn't work is something I still haven't figured out.