I'm on Rails 4 using SQLite, and I have a database of 75,000 quotes. I would like to grab a random record (quote) from this database and display it for users to see. I've looked around but no method I have searched around here has worked yet. Here's code that grabs the first record and displays it:
<% Quote.limit(1).all.each do |quote| %>
<%= quote.quote %> :: <%= quote.author %> :: <%= quote.genre %>
I have also tried the following method, but this returns a long alphanumeric value rather than the quote.
offset = rand(Quote.count)
rand_record = Quote.offset(offset).first
Thanks!
Do not order by random() in your SQL call. It's extremely inefficient as your database has to call the random function for each row, assign it a value, then sort on it. As the number of rows grows this becomes very slow.
Your second method should work and is a much better solution. I tried it with my own database and it works. rand_record will be a Quote object -- not the quote string itself. I would do this:
In your controller action:
random_offset = rand(Quote.count - 1)
#random_quote = Quote.offset(random_offset).first
In your view:
<%= #random_quote.quote %> :: <%= #random_quote.author %> :: <%= #random_quote.genre %>
The reason we subtract one from the count is that if we choose an offset that is the same as the number of Quote records then our call to fetch will be nil as the query's offset is one too many.
Related
I am calculating an ROI value that averages over a category.
<% #categories.each do |category| %>
<h3><strong><%= category.name %><strong></h3>
<% #category_products = category.products_by_warehouse_id(params[:id]) %>
<!-- add map/reject below -->
<%#ROI = (#category_products.reduce(0.0) {|acc, item| acc + (item.heritable_sale_price.to_f * item.product_selections.length) / item.purchase_price.to_f }) %>
<p> Category ROI: <%= number_with_precision((#ROI / #category_products.length.to_f), precision:2) %></p>
.....(close tags)......
The value throws NaN when financial data is missing. For individual values, this is fine; however, it does the same for averages with missing data as well.
How can I add map/reject into my call to throw out nil values, and get the average of what's available?
#category_products.length.to_f would also have to skip over empty elements in the array if I go this route as well, to keep the sum and length consistent. Something like .where(purchase_price: [!nil, ""]).size may work.
So, in order to make sure, that none of the methods being accessed within the reduce block, to the item object are going to return nil, which hence, would throw a NoMethodError, you could firstly check them at the moment of creating your query. A where.not would do that. But keeping in mind that it'll leave aside each record in the database which doesn't satisfy the query criteria.
For that, then:
where.not(
heritable_sale_price: nil,
product_selections: nil,
purchase_price: nil
)
For that, you can analyze the option on setting a default value for each of those columns, so this helps you avoiding the previous query, and having to rescue on each case where there's no value for them. You can see the Rails Migration docs.
Having a challenge to calculate sum for dynamically built request.
I'm using each method to get value for each element and it work seamless.
<% params[:car].map{|n| n.first}.each do |p|%>
<%= #salon.price.send("price_" + p) %>
<% end %>
But then I'm trying to get sum for the same dynamically ("price_" + p) built queries it's failing.
<%= #salon.price.where("price_" + params[:car].map{|n| n.first}.to_s).all %>
Tried multiple solutions and no luck
You have where but haven't given it an actual where-like clause do you mean #salon.price.sum() instead? Otherwise what are you trying to filter on (where is for filtering, sum is for summation).
So what you seem to want to do is:
for all the prices for a given salon
sum up the columns price_0..price_n
right?
Now it'd be easy to construct a query to sum up the values for a single column
For that you'd try something like this:
<%= #salon.price.sum("price_0") %>
This uses the Rails sum method that works on any Active Record association.
And if you had a single price object and wanted to sum up all the price_X columns for that single price, you'd use something like this:
<%= params[:car].map{|n| price.send("price_" + n.first.to_s) }.sum %>
This turns the numbers in params[:car] into an array of the column-values for the given price-object... then sums them at the end using the sum method that comes from the Array class (AKA Array#sum)
so to combine those two, you'd probably need something like this:
<%= #salon.prices.all.sum{|price| params[:car].map{|n| price.send("price_" + n.first.to_s) }.sum } %>
Yes, that's a block inside a block.
Now it's possible that the Active Record version of sum can interfere with Array#sum and not like the above (which looks more like how you'd do the Array#sum). Rails' sum expects you to pass it the name of a single column like in the first example, rather than a block, like in the second example. So sometimes you then need to use map (which turns your set of values into an array) and then you can use Array#sum at the end like this:
<%= #salon.prices.all.map{|price| params[:car].map{|n| price.send("price_" + n.first.to_s) }.sum }.sum %>
So that's a block (whose values are summed) inside another block (whose values are summed)
EDIT:
after discussion it seems you only have a single price record... and multiple columns on that single record... this changes things and makes them much simpler. You can just use this:
<%= params[:car].map{|n| #salon.price.send("price_" + n.first.to_s) }.sum %>
You use sum method for the array
sum = params[:car].map{|n| n.first}.sum
I'm guessing you're trying to get the sum of columns named price_n in the Price table where n is the value of params[:car].map(:&first). So I think the simple solution is:
<% params[:car].map(&first).each do |n| %>
<% sum += #salon.price.send("price_#{n.to_s") %>
<% end %>
<%= sum %>
But seeing the logic in the view is not a rails best practice, so it's better if we move the entire logic in your helper method. So in the view, just display this code:
<%= total_of_all_prices(params[:car], #salon.price) %>
Then in your helper method add this method
def total_of_all_prices(car_params, price_object)
sum = 0
car_params.map(&:first).each do |n|
sum += price_object.send("price_#{n.to_s}")
end
sum
end
In my method via some calculations a get data, then i need to view it in view, but if write
#ar.each do |a|
when i have only one record i get error, also when i have one error each is bad idea. So how to do this this?
So i have such code in method:
non_original = []
#articles.each do |a|
non_original << get_non_tecdoc("LA44", 1, "KNECHT")
end
#non_original = non_original
get_non_tecdoc returns object, or nothing...
So in view i have:
-#non_original.each do |no|
=no.brand
=no.description
=no.price
=no.quantity
But what to do if #non_original has one record, then #non_original.each gives error. So how to do check in view? If #non_original has one record, than simple #non_original.brand etc, but if more than one, than use each loop?
This will work with #ar as a single value as well as an array:
Array(#ar).each do |a|
p a
end
This Array is a method on Kernel.
<%= debug #ar %>
This will give you a nice YAML format to look at in your view (assuming ERB).
EDIT: I believe this is what you want, since you're not interested in debugging.
In your controller, use the splat operator to convert a singleton element to an array (it doesn't modify arrays):
#ar = *#ar
Then #ar.each will work as expected in your view.
Alternatively, you could check in your view:
<% if #ar.is_a?(Array) %>
<% #ar.each ... %>
<% else %>
<%= #ar %>
<% end%>
Why don't you try using #ar.inspect and output it to the console to see the instance variables contents.
As long as #ar is an array you should not get a error. If you are returning one record change it to an array with one record.
If you are using active record query interface like the "where" clause; it will return an array with 0 or more active_record objects. If you use find it will return one instance of an active_record object.
So if your method that queries is using the active record where clause #ar should always return an array.
Please try this:
Tablename.find_by_table_id
Example:
if account_id is 10 then, take following example,
#getResults = Account.find_by_account_id(10)
It will gives single record.
we can get values using #getResults.id,#getResults.name ....like wise.
In my rails app, i have the following function in one of my controller page.
def tree
#jstree = ActiveRecord::Base.connection.execute("Select sequence, depth, node, imageid, range from.....several joins")
end
I now want to loop through the resultset and display the sequence only in my view page tree.html.erb. I tried the following code, it does not seem to work.
<% #jstree.each do |tree| %>
<%= tree.sequence %>
<% end %>
I am getting the error message: undefined method 'sequence' for #<Array:0x60e0088>.
Is there a way of looping through the result set of the sql query executed and displaying each column value?
Many many thanks for all suggestion provided :)
Keeping the same syntax as the OP
<% #jstree.each do |tree| %>
<%= tree[0] %>
<% end %>
would accomplish what you were looking for.
You get this error because what you get in #jstree is a raw DB adapter result. If you want to query for some objects by issuing raw SQL queries then use find_by_sql. Example:
Client.find_by_sql("SELECT * FROM clients INNER JOIN orders ON clients.id = orders.client_id ORDER clients.created_at desc")
I have a problem trying to make a list from a acts_as_taggable_on tag_list
I have tag list array, and I want to list it so im trying this:
<%= proyects.tag_list.each do |tagsx| %>
* <%= tagsx %> <br>
<% end %>
And I get the list im looking for, but also the whole array again...
When it renders, looks like this..
* AJAX
* Rails
* Heroku
* Prototype
AJAX, Rails, Heroku, Prototype
Any ideas on getting rid of the last line?
Or do you guys know a more efficient way of achieving this?
Thanks in advance.
Change this:
<%= proyects.tag_list.each do |tagsx| %>
to this:
<% proyects.tag_list.each do |tagsx| %>
You don't want to output the return value of the .each call, just the elements of the array. Calling Array#each with a block returns the array (as you are):
each {|item| block } → ary
each → an_enumerator
Calls block once for each element in self, passing that element as a parameter.
If no block is given, an enumerator is returned instead.
and that's were the comma delimited list is coming from.
because you have a typo in your code :-)
<%- proyects.tag_list.each do |tagsx| %>
* <%= tagsx %> <br>
<% end %>
see the difference?
no '=' after the first % sign
%= means that the result of a Ruby expression is returned to the view
%- means that the Ruby expression is evaluated, but no result is returned
The code in your question gets "proyects.tag_list" , executes the loop, during which it prints out the individual tags, and then returns the whole array to the view because of the '='