Shuffling an array in ruby on rails [duplicate] - ruby-on-rails

This question already has answers here:
How do I pick randomly from an array?
(7 answers)
Closed 6 years ago.
I have an array of images that I want to shuffle and only show the first ten results. I am having trouble figuring out how to do that.
Here is my code
<% #images.each.shuffle do |image| %>
<tr>
<td><%= image.name %></td>
<td> <%= image_tag image.picture.url %></td>
<td><%= image.likes %></td>
<td><%= link_to 'Show', image %></td>
<td><%= link_to 'Edit', edit_image_path(image) %></td>
<td><%= link_to 'Destroy', image, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>

You can use sample function in the Array class.
<% #images.to_a.sample(10) do |image| %>

If #images an AR proxy object or the result of some other DB query, you might want to adjust your query so that it does the shuffle-and-limit DB-side:
#images = Image.where(...).order("rand()").limit(10)
Note that sorting by random can't use indexes, but it's better than loading the whole table into RAM app-side. Something like this:
#images = Image.where(...)
#images.to_a.sample(10)
will load the results of the entire query into RAM in the Rails app, which will be quite slow.
This has the added benefit of keeping logic out of your views, which is a Rails best practice.
(Posted as an answer per asker's request)

Related

Rails 5 Ruby 2.5.3 If statements based on ranges of months

so I'm working on a personal project.
I'm a truck driver and i am building a simple app to track and calculate revenue ect..
What I am trying to do (and there may be a much better way to do it) is highlight what my current active fuel surcharge is based only on a range of months.
In this case its April 1 to Oct 31 and Nov 1 to March 31 this can change as contract requirements dictate ect.
I have an activeDate and endDate column in my database and this is what I have come up with (but doesn't seem to work).
**<<index.html.erb>>**
<tbody>
<% #fscs.each do |fsc| %>
<% if Date.today === (fsc.activeDate..fsc.endDate) %>
<tr>
<td class="fsc_active"><%= fsc.name %></td>
<td class="fsc_active"><%= fsc.rate %></td>
<td class="fsc_active"><%= fsc.activeDate %></td>
<td class="fsc_active"><%= fsc.endDate %></td>
<td><%= link_to 'View', fsc %></td>
<td><%= link_to 'Edit', edit_fsc_path(fsc) %></td>
<td><%= link_to 'Delete', fsc, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% else %>
<tr>
<td class="fsc_inactive"><%= fsc.name %></td>
<td class="fsc_inactive"><%= fsc.rate %></td>
<td class="fsc_inactive"><%= fsc.activeDate %></td>
<td class="fsc_inactive"><%= fsc.endDate %></td>
<td><%= link_to 'View', fsc %></td>
<td><%= link_to 'Edit', edit_fsc_path(fsc) %></td>
<td><%= link_to 'Delete', fsc, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
<% end %>
</tbody>
Any advice on where I'm going wrong or pointers on how to make this better would be greatly appreciated! please let me know if more information is needed.
EDIT 1: Sorry Only the month matters in this case not the year or day. my apologies for not mentioning this.
(fsc.activeDate..fsc.endDate).cover?(Date.today)
Instead of using include?, use cover?. It’s substantially more efficient. include? will create a whole array of all possible values to see if the value is in the list. cover? just uses the min and max values with a >= and <= to see if the value is within the range. There are instances where cover? is not an applicable replacement for include?, but this is a good time to use cover?.
https://ruby-doc.org/core-2.5.3/Range.html#method-i-cover-3F
I would also recommend that you store Date.today in a variable right before the start of your loop and use that in your comparison, instead of checking the current time on the server for every element in #fscs.
Also, it would be wise to use Date.current instead of Date.today. Date.current is a Rails method that’s time zone aware to give you today in the currently configured Time.zone.
Here’s an article I found helpful to learn about what methods to use and what methods to avoid, when dealing with all the fun that comes with time zones. https://thoughtbot.com/blog/its-about-time-zones
Try doing something like this:
(fsc.activeDate..fsc.endDate).include?(Date.today)
You are trying to equate todays date with a range of dates whereas you want to check if the today's date is present in the date range.
You still might use triple-equal aka case-equal FWIW. Just swap the arguments to #===: you need the one declared on Range, not the opposite one:
- Date.today === (fsc.activeDate..fsc.endDate)
+ (fsc.activeDate..fsc.endDate) === Date.today

Rails link_to not working correctly

I am trying to put in a link_to on my table to go to the show action but it is putting the URL as /admin/vulnerabilities.object_id instead of /admin/vulnerabilities/object_id
my index view is:
...
<% #vulnerabilities.each do |vulnerability| %>
<tr>
<td><%=link_to vulnerability.id, admin_vulnerabilities_path(vulnerability) %></td>
<td><%= vulnerability.type %></td>
<td><%=h truncate(vulnerability.description, :length => 80) %></td>
<td><%= vulnerability.published %></td>
<td><%= vulnerability.modified %></td>
<td><%= link_to vulnerability.href, vulnerability.href , target: :_blank %></td>
</tr>
<% end %>
...
I have a show.html.erb template setup and my show action is as follows:
def show
#vulnerabilities = Vulnerability.find(params[:id])
end
From what I can see, this should work but when clicking the links it just redirects to the index page, effectively refreshing it and not using my show page at all.
It would be helpful if you added the relevant parts of your routes.rb file to your question, but I speculate that the problem is that admin_vulnerabilities_path(vulnerability) should be admin_vulnerability_path(vulnerability).
Also, as noted in the comments, it is probably better to use #vulnerability as your instance name since find will return a single record.

Ruby on Rails - Unable to Display Associated Item From Database (#<Comment:0x44f9ec8>)

I followed the "Getting Started" tutorial at http://guides.rubyonrails.org/getting_started.html, and wanted to change what is output on the articles index page.
rather than showing the text of the article in the main table, I want to see the most recent comment made on that article.
Here is the code for the index:
<tr>
<td><%= article.title %></td>
<td><%= article.comments.select(:body).last %></td>
<td><%= link_to 'Show', article_path(article) %></td>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<td><%= link_to 'Destroy', article_path(article),
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
</tr>
Where 'article.comments.select(:body).last' is meant to show the body of the latest comment made on the article in question (this table iterates for every article).
Instead of seeing the text from the comment however, I see this:
{Comment:0x44f9ec8} (with sharp brackets instead of curly - wont let me post the sharp ones.... <>)
I also tried editing comment.create in the comments_controller with:
#article.text = #comment.body
After setting the index table field to 'article.text' (which works fine), but with no effect.
Anyone have any idea what I'm doing wrong??
Any help is much appreciated.
article.comments.select(:body).last does not do what you expect
the select part uses this select which alters the SQL command you use. It forces selecting only the body field from comments and returns a comment object.
so you need to change your code to article.comments.select(:body).last.body
If you need to have all the body fields and just use one, I suggest that you use pluck if you are on rails > 3.2
article.comments.pluck(:body).last

How to display paperclip's uploads.

Im currently building a blog. While the paperclip photos pop up inside the individual blog posts they don't seem to pop up in the index, where all the blog posts are displayed.
13th line seems to be the problem.
this is my index.html.erb for my posts
10 <% #posts.each do |post| %>
11 <tr>
12 <td><%= link_to post.title, post_path(post) %></td>
13 <td><%= image_tag #post.picture(:medium) %></td>
14 <td><%= post.text %></td>
15 <td><%= link_to 'Show', action: :show, id: post.id %></td>
16 <td><%= link_to 'Edit', action: :edit, id: post.id %></td>
17 <td><%= link_to 'Destroy', { action: :destroy, id: post.id },
18 method: :delete, data: { confirm: 'Are you sure?' } %></td>
it throws me a no method error.
Please let me know if I can give you extra files if you need more information
Thank you in advance!
You're not passing the URL for the image to the image_tag helper.
You need to display your image like this:
<%= image_tag post.picture.url(:medium) %>
You're trying to access the #post instance variable, but that instance variable doesn't exist. Rather, within your loop, you should access your post local variable as such:
<%= image_tag post.picture.url(:medium) %>
Note also that, from the documentation, the correct syntax to access variations of a Picture instance involves passing the variation name to the url attribute:
post.picture(:medium) # Invalid
post.picture.url(:medium) # Valid!
As mentioned by Jon, you need to use the .url method on your picture object (official documentation):
<%= image_tag post.picture.url(:medium) %>
Paperclip
The reason for this is Paperclip actually creates its own picture object & attaches several methods to that (url being one of them). This means you have to call url each time you show the post's image to get it to load
Normally, you'd be able to call methods on your instance or local variables, but as Paperclip actually creates its own object, you have to use its in-built methods to get it to work correctly

Only displaying certain entries from a log based on id

I have a log in my webapp where you can input hours, and when you input your hours it automatically takes the account you are logged into(built using devise and cancan), and finds what your user_id is and tacks it on to an hour log.
Now what I cant seem to find out is how I can go about making it so that it only displays logs with your user_id. Is there a way to do this in the model or controller instead of the view?
This is the view code as of now.
<% #time_sheets.each do |time_sheet| %>
<tr>
<td><%= time_sheet.user_id %></td>
<td><%= time_sheet.day %></td>
<td><%= time_sheet.hours_worked %></td>
<td><%= time_sheet.minutes_worked %></td>
<td><%= link_to 'Show', time_sheet %></td>
<td><%= link_to 'Edit', edit_time_sheet_path(time_sheet) %></td>
<td><%= link_to 'Destroy', time_sheet, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
It shows the logs of everyone in the system instead of just that user.
Devise gives you a helper method named current_user. In your controller you can filter by user ID using the current_user.id. Like so:
#time_sheets = TimeSheet.where(:user_id => current_user.id).all
And that will give you only the currently logged in user's time sheets.

Resources