I have a table "State", consisting of a few thousand records, and I'm printing each of their names on one page. Would adding a dynamic tooltip to each add noticeably to the load time of the page? In other words, would there be a significant performance difference between these two blocks of code?
<%= State.all.each do |state| %>
<%= state.name %>
<% end %>
or
<%= State.all.each do |state| %>
<%= link_to state.name, "#", title: "(" + state.weather + ")" %>
<% end %>
For the record, weather is a instance method calculated by adding two State attributes together:
def weather
self.snow + self.rain
end
If you want to know you can easily check the log, it shows you the active record time and the view rendering time
It would look something like this
Completed 200 OK in 539ms (Views: 486.9ms | ActiveRecord: 1.8ms)
The first 200 means that the request was a success, the 2nd number 539ms is the total request time, which in this case is '539 milliseconds', then there's a break down of that time, 486.9ms was spent in the view rendering, and 1.8ms is spent in the ActiveRecord queries
Test both cases, I don't think you'll find any huge difference but you should check
PS: you should move the query call to the controller, just for good convention
# controller
#states = State.all
#view
<%= #states.each do |state| %>
Related
This is a tricky one to express, I'll give it a shot though:
I have defined #model = Model.all which includes both depart_at and arrive_at. I now need to run through these, in groups of date. (Each is a datetime in the database).
I've tried a few things, but I can't seem to get anything to work here.
<% #departure_times.each do |departure_time| %>
<% end %>
is the current code. I can't seem to find anything in the Rails API about, what I can do to chunk up by the date of depart_at.
Edit:
The expected outcome is something alike:
**date** - 10:15, 11:15, 20:30
**date** - 11:15, 12:30, 14:15
etc - The meaning for this, is to group the output by the date of the timestamp.
One might prepare the chunked array in the controller:
#dt_grouped = #departure_times.group_by do |departure_time|
Date.parse(departure_time.depart_at.to_s).to_s
end
This will produce a Hash instance like:
{ '2016-03-08' => [dt1, dt2, dt3,...], ...}
and then in view:
<% #dt_grouped.each do |date, times| %>
<%= date %> — <%= times.join ', ' %>
<% end %>
I have a scenario where
a training Drill applies to a group of people playing sport at a
certain Grade (Elite, Adult, Junior),
and that Drill will develop them to Perform at a certain level (fundamental, advanced)
I am iterating through a Grades list and putting a dropdown list next to each Grade item so that the person creating the training drill can specify how that apply to developing them to perform at the level, as follows
<label>How will this drill improve performance?</label>
<% Grade.all.each do |g| %>
<% if g.activity_id == #drill.activity_id %>
<p>It will develop
<%= select(drill, :grade_ids, #performancelevels.map {|p| [p['development_title'], g.id.to_s + "-" + p.id.to_s] }) %>
performance for the <%= g.name %> level</p>
<% end %>
<% end %>
In my controller I am permitting
params.require(:drill).permit(... {:grade_ids => []} ...)
When the form submits I am only getting one value passed when I select several
Parameters: {... "grade_ids"=>"1-4"... "commit"=>"Create Drill"}
Any suggestions on the best way for me to collect up and send through these parameters?
Thanks for your help!!
Got this working. Attached javascript to onchange of the dropdown, added the values to a hidden field, then split the values out of the hidden field in the controller
One of the most common reasons my web application fails is because a user sometimes lacks a certain attribute that a view expects it to have. For instance, most users in my application have an education (school, degree, etc.) entry in our system, but some users do not. Assuming my view looks something like this:
<% #educations.each do |education| %>
<%= education.school %>
<%= education.degree %>
<% end %>
I want to avoid "Pokemon" exception handling and feel that there has to be a better way around dealing with a "undefined method `degree' for nil:NilClass" error in the case that a user does not have an education entry in our database. This just seems like an ugly/tedious fix:
<% #educations.each do |education| %>
<% if education.school %>
<%= education.school %>
<% end %>
<% if education.degree %>
<%= education.degree %>
<% end %>
<% end %>
Any input is appreciated. Thank you!
As long as you know the first object you're working on won't be nil, the easiest way is to just do this:
- #educations.each do |education|
= education.try :school
= education.try :degree
The #try method is pretty handy. You can also call .to_s on anything you think might be nil, Ie:
- #educations.each do |education|
= education.school.to_s
= education.degree.to_s
This will convert nils to an empty string. This isn't as useful in the view IMO, but comes in handy a lot of times if you have input that is expecting to be a string and might be empty. Ie a method like:
def put_in_parenthesis(string)
"(" + string.to_s + ")"
end
You have a couple of options here.
The easiest to implement is the try method. It is used like so:
<%= education.try( :degree ) %>
The problem is that try() is viewed as a bit of an anti-pattern. As the reference indicates, you can achieve similar functionality with something like:
<%= education && education.degree %>
This isn't really a lot different, intellectually, in my opinion. A popular way of handling this a little more cleanly is the Null Object pattern, which is basically an object with defined neutral ("null") behavior.
Using Rails 3.1.1 and Heroku.
I believe this should be a fairly easy fix but I cannot find (and easily verify) how to do this. I have a very slow controller (6 sec) Product#show, with lots of N+1 and other things I will have to solve.
The website is a two-column website (main-column and right-column) where the main content from Product#show is shown in one column and daily product are shown in the other, including a "Random Product from the Database".
What I want to do is to let the content in main-column that is created by Product#show be cached (and thus bypass the controller and win 6 seconds). I do, however, want the right column to be dynamic (and loaded for each page request).
If I use caches_page :show it will cache the entire website, including the right-column, which makes me have to expire the cache every day in order to be able to load a new Daily Product. Not a good solution.
If I use cache('product-show' + #product.slug) do it only caches the view (right?) and still have to go through the controller.
So, how can I solve this?
You can achieve this with fragment caching like below:
def show
if !fragment_exist?("main_content")
#products = Product.all
#users_count = User.count
end
#random_products = Product.order("RANDOM()").limit(10)
end
show.html.erb
<!--MAIN CONTENT-->
<% cache("main_content") do %>
<%= #users_count %>
<% #products.each do |product| %>
<%= product.name %>
<% end %>
<% end %>
<!--SIDE CONTENT-->
<% #random_products.each do %>
<%= product.name %>
<% end %>
Use fragment caching, and don't load things in the controller.
If you have a very complex query, let it live in the controller as a scope, and only evaluate it in the view.
If you have a complex process to do so the query must be executed, use a helper method.
If you manage to just load lazy queries in the controller, if the cache is hit none of them will be executed.
I have an object called #events containing about 50 records being pulled from a find condition of my model.
I'm currently displaying the results of the #object in my view like this....
<% for event in #events %>
<p><%= #event.name %></p>
<% end %>
Instead of displaying the entire 50 I would like shrink the set to about 10 records so it displays better on the page.
I cannot use :limit in the find condition since the object is being composed from a variety of loops where after each iteration it adds a few specific records.
So the issue is I have this object #events with 50 records, how can I change the object after its been composed so only the first 10 records remain?
First of all, if you'd like to have pagination, I strongly suggest taking a look at will_paginate
Alternatively, you can do the following to read the first 10 records only.
<% #events.first(10).each do |event| %>
<p><%= event.name %></p>
<% end %>
Or the last 10 records
<% #events.last(10).each do |event| %>
<p><%= event.name %></p>
<% end %>
I didn't test it but you get the point.
are you looking to completely do away with the other 40 or are you just wanting to pull off 10 per page for display purposes. if you are just doing this for display purposes i would look into the will_paginate gem. through its options you could set it so only 10 results per page are shown.
Take a look at will_paginate and kaminari. They both are designed to limit the records retrieved from the database, plus offer helpers for your views to provide the usual number of pages and current page lists.
Will_paginate has been around a while, and is pretty flexible. Kaminari is newer and looks like it has a cleaner interface.