Problem with Array.shift - ruby-on-rails

From my controller I am passing two instance variables #events = Event.all and #images = Images.all. In the view I begin by iterating through #events.each do |event| and within this block is the line img = #images.shift yet when I try to access any method of img such as img.filename I get an error that img is nil but I have checked and am certain that #images is populated correctly. If I simply output img.class I receive the correct class, Image, but cannot access any of it's methods.
What am I doing wrong or why is this way of pulling instances from an array incorrect?
I know there are other ways of going about this but this specific problem confounds me and I would really like to understand why this doesn't work. Thanks.
#Structure of the model is
Image
-filename :string
-date :datetime
-caption :text
-source :string
#Controller
def index
#events = Event.all
#images = Image.all
end
#index.html.erb
<% #events.each do |event| %>
... code that works ...
<% if count==1%>
<% img = #images.shift %>
<div><%= img.filename %></div>
<% end %>
<% end %>
#For testing purposes I changed
<% img = #images.shift %>
<div><%= img.class %></div>
#output is Image

The problem might occur when there is more events then images. Because every time an iteration goes through #events array then the #images are shifted and is taken the next element from the array. So when you have for example 4 elements in #events and only 3 in #images then at 4th iteration there is taken 4th element from #images and this is nil

There are two cases when the return value of Array#shift becomes nil.
The leftmost element of the array is nil.
The array is empty (= []).
It is probably either of the cases.

Related

Rails: How to pass params of multiple checkbox to the model

i built this form that generate me some chebox with value like "U6", "U8" eccc
<%= form.label "Seleziona Categorie" %>
<% TeamCategory::NAMES.each do |category| %>
<%= check_box_tag 'categories_selected[]', category -%>
<% end %>
Now i have to pass the value of selected check_box to a method in my model.
Now is:
def create_tournament_team_categories
TeamCategory::NAMES.each do |name|
team_category = TeamCategory.where(name: name).first_or_create
self.tournament_team_categories << TournamentTeamCategory.create(team_category: team_category)
end
end
I would like to replace the TeamCategory::NAMES.each do with "selected check_box each do" and TeamCategory.where(name: name) with the value selected.
Thank you in advance
I am a newbie with Rails. What I see is that you took the part of the form to create the team, right?
For your code straight forward it could be:
<%= form.label "Seleziona Categorie" %>
<% TeamCategory::NAMES.each do |name| %> #you are looping through team category NAMES constant
<%= check_box_tag 'category_names_selected[]', name %>
<% end %>
Your form as is allows more than one category to be selected.
For the method:
def create_tournament_team_categories(category_names_selected)
category_names_selected.each do |name|
team_category = name
self.tournament_team_categories << TournamentTeamCategory.create(team_category: team_category)
end
end
you will probably use this method in your teams_controller.rb. In the controller, you should be able to retrieve from params a freshly created array of selected names with something along the lines with this.
#category_names_selected = params[:category_names_selected]
I do not know how complicated your app is so it might also be nested under ["team"][:category_names_selected] or ["team"]["category_names_selected"] in your params hash.
To see the exact structure of the params hash and adjust the equation above you can add for example require 'pry' at the top of your controller file and then but the binding.pry just after the part where your method is executed. When you restart the server and the app hits this part of the controller you should be able to see the exact structure of your params hash in the terminal.
You can then pass the array to the method that you can call in the controller. Do not forget to add :category_names_selected to the strong params in the controller. I hope this helps.
Controller on line 30
def create
#tournament = Tournament.new(tournament_params)
#tournament.sport_club = current_user.sport_club
#category_names_selected = params[:category_names_selected]
if #tournament.save
redirect_to tournaments_path, notice: 'Torneo creato con successo'
end
end
Method create_tournament_team_categories in the model
after_create :create_tournament_team_categories
def create_tournament_team_categories(category_names_selected)
#category_names_selected.each do |name|
team_category = name
self.tournament_team_categories << TournamentTeamCategory.create(team_category: team_category)
end
end

Getting the string from a rails pluck to display n

got a super quick question. I'm still new to rails and tried following these two questions but they didn't work for me:Why does Array.to_s return brackets? and ruby 1.9 how to convert array to string without brackets.
I'm trying to show the last message and the date in which it was sent out in my chatroom application. I am able to get the results using this code, but it has brackets around it and I would like to have those brackets removed. Any help here would be amazing, I've attached a screenshot as well. Thank you so much!
Show.html.erb
For the Date:
<%= chatroom.messages.last(1).pluck(:created_at) %>
For the Last Message in Chatroom:
<%= chatroom.messages.last(1).pluck(:body) %>
DirectMessages Controller
class DirectMessagesController < ApplicationController
before_action :authenticate_user!
def show
users = [current_user, User.find(params[:id])]
#messageduser = User.find(params[:id])
#chatroom = Chatroom.direct_message_for_users(users)
#chatroomall = current_user.chatrooms
#messages = #chatroom.messages.order(created_at: :desc).limit(100).reverse
#messagelast = #chatroom.messages.last(1)
last_message = #chatroom.messages.last
render "chatrooms/show"
end
private
def chatroomuserlocator
#chatroomlocator = Chatroom.find(params[:chatroom_id])
end
end
Try this:
<%= chatroom.messages.last.created_at %>
And this:
<%= chatroom.messages.last.body %>
Keep in mind that pluck returns an array, so that would explain your brackets.
I don't think you need pluck here since you are just accessing an attribute on a single item.
If you're not too worried about memory usage, you can fetch the whole object and only access the fields you want.
<%= chatroom.messages.last.created_at %>
<%= chatroom.messages.last.body %>
You can assign the lookup to a value, so it doesn't run twice:
last_message = chatroom.messages.last
Then you can access the attributes efficiently:
last_message.created_at
last_message.body
If you are interested in limiting the attributes or last_message, use select:
last_message = chatroom.messages.select(:created_at, :body).last
Putting it all together:
<% last_message = chatroom.messages.select(:created_at, :body).last %>
<%= last_message.created_at %>
<%= last_message.body %>

How to query two tables from database in one controller

I have two tables which are one to many (1 challenge to many entry)
I want to get the last entry for all challenges but I also want to get the title of the challenge for that last entry.
So far I have:
def index
#discovers = Challenge.all.map{|c| c.entries.last}
end
How to I also add the fact I want the Challenge.title?
def index
#challenges = Challenge.all
end
Then inside your view
<% #challenges.each do |challenge| %>
<%= challenge.title %> # will give you challenge title
<%= challenge.entries.last %> # will give you last entry for the challnge
<% end %>

Pagination with Kaminari

All the examples of Kaminari I have seen only have 1 variable in the controller action.
But here is my example:
def index
#draft_item = #account.draft_item # only ever one
#in_force_item = #account.in_force_item # only ever one
#historical_items = #account.lo_items.historical # many of these
respond_to do |format|
format.html
end
end
These are all displayed in a table on the view, which I want to paginate. Do I need to combine these into 1 array first in the index action?
My loop on the view is like this:
<% [#in_force_item, #draft_item, #historical_items].compact.flatten.each do |lo_item| %>
then I have code like:
<% if lo_item == #draft_item %>
Is this possible and still be able to call the line above>?
Thanks to the answer below, I was able to do it like this:
#total_items = Kaminari.paginate_array([#draft_item, #in_force_item, #historical_items].compact.flatten).page(params[:page]).per(10)
It all had to be on one line for it to work, unlike the answer below which had it split across two lines.
It is. Kaminari has paginate_array
#draft_item = #account.draft_item # only ever one
#in_force_item = #account.in_force_item # only ever one
#historical_items = #account.lo_items.historical
#total_items = [#in_force_item, #draft_item, #historical_items].compact.flatten
Kaminari.paginate_array(#total_items).page(params[:page]).per(10)
Then
<% #total_items.each do |lo_item| %>
<% end %>
<%= paginate #total_items %>

Switching an app from displaying one quote at random to all in a grid

I previously built an app (my first rails app) designed to display a single quote from the db at random on screen (and a different one on each refresh). I'm now aiming to refactor that app to display all of the quotes (paginated, I guess) in a grid format.
The catch is that I'm uncertain how to pull all of the quotes to display on the page instead of just one at random. In the controller, I previously had:
def index
#quote = Quote.order("RANDOM()").first
end
Would it be something like this?
def index
Quote.each do
#quote = Quote.order("RANDOM()")
end
end
Type this in your controller:
def index
#quotes = Quote.order("RAND()").all
end
In your view type this:
<% #quotes.each do |quote| %>
<%= quote.id
<%= quote.X <---------REPLACE X for the column to show
<%= quote.X <---------REPLACE X for the column to show
<% end%>
In your controller
def index
#quotes = Quote.order("RANDOM()")
end
Then in your view
-#quotes.each do
That should do the trick

Resources