How can I set a fallback ordering system? - ruby-on-rails

I'm printing a list, ordered as such:
<% #users.order(:number).each do |u| %>
<%= u.name %>
<% end %>
But some users will have the same value of :number, and in that case the records appear to be ordered based on time_created. How can I set a fallback or secondary ordering system to be used when records have the same value of the attribute used to order them?

You can just keep adding on to the order method.
#users.order(:number, :name, :last_logged_in, :id)
If the numbers are the same, it will break the tie with name, then last_logged_in, then id. This is all done in the database for you.
If you already had the data in memory, then you could use Ruby's sort_by method.

You're probably going to want to use sort_by instead of order.
#users.sort_by {|u| [u.number, u.second_option] }
that will sort first by number and then if number matches it will pull whatever the second option is and compare by that. Technically you can throw as many things to sort by as you want into that array.
Edit: Actually, there's a similar question already answered here

Related

Show only unique results with collection_select

I have a series of reviews for a professor, I want users to be able to sort reviews based on the class taught. I have a collection_select but I'm having trouble filtering out duplicates, so for example if more than one user had a professor for "English" you will just see "English" twice in the list.
This is what I have:
<%= collection_select(:professor, :id, Review.where(professor_id: #professor.id), :id, :whatclass) %>
I've seen some solutions saying that I should add .uniq but that dosen't seem to do anything.
<%= collection_select(:professor, :id, Review.where(professor_id: #professor.id).uniq, :id, :whatclass) %> I'm pretty sure this is not working because it's referring to the Review.id rather than Review.whatclass
Your list contains duplicates because it has an entry for every review, not for every class taught, which is not unique for each review. I am not even sure you need to use collection_select to render a simple list of unique class names.
In the controller, try:
#unique_classes = Review.
where(professor_id: #professor.id).
pluck(:whatclass).uniq
Here, pluck returns an array of just the whatclass attributes of every review of the professor. Calling uniq on that will drop any duplicates in the array. If you have lots of reviews for each professor, you can get better performance by having the database filter the duplicates:
#unique_classes = Review.
where(professor_id: #professor.id).
pluck("DISTINCT whatclass")
This will generate a SELECT DISTINCT query, so the array pluck returns will already be unique.
Finally, you can plug this array of whatclass values into a simple select_tag:
select_tag :class_name, options_for_select(#unique_classes)
The code above is untested, so it might need some changes to work.

How to display ROR 5 ActiveRecord pluck as String in html.erb

In html.erb I have:
<%= ContactDescribe.where(["contact_describe_id = ?", "12"]).limit(1).pluck(:borrower_or_lender_text) %>
The field is retrieved successfully. But returns an array element. I need to learn how to convert that element to a string.
In addition to Deepak's answer, you can also convert the Array into a "Sentence" String
<%= ContactDescribe.where(contact_describe_id: 12).limit(1).pluck(:borrower_or_lender_text).to_sentence %>
Recommendation:
As pointed out by TheChamp, it is best practice to already "prepare" the values needed in the views as instance variables from the controller. See my recommended refactor
# controller
def YOUR_ACTION_NAME
#contact_describe = ContactDescribe.where(contact_describe_id: 12).first
end
# view
<%= #contact_describe.borrower_or_lender_text %>
Note: you won't even need pluck anymore unless you have other reasons why you want limit(1)
The issue here is that where returns a collection - something similar to an array, just in ActiveRecord - no matter what limit you set on it. To retrieve the information you would use .first or [0] since you always only return one object.
But, since you are looking for a specific ContactDescribe object. Do this instead:
ContactDescribe.find_by(contact_describe_id: 12).borrower_or_lender
Additionally there two things you should improve in your code.
1: Logic should go into the controller or the model. A view is solely here to show objects.
2: What is up with the contact_describe_id field? Why not call it id. It seems redundant. Isn't user.id more convenient than user.user_id?
You can make use of join
<%= ContactDescribe.where(contact_describe_id: 12).limit(1).pluck(:borrower_or_lender_text).join(',') %>

Showing database items

I would like to have a link that only displays the last 10 database submissions with a select number of tables per submission. Hope that makes sense. So in short a can click 'recent submissions' and it will display the last 10 via customer name, submission date, and id number . Currently in the controller i have the following just to test the link but of course it display every table.
<h2>LAST 10 SUBMISSIONS</h2>
<%= #posts.each do |post| %>
<%end%>
Sorry, this is more of a comment than an answer but I don't have enough rep to leave a comment.
You could retrieve a bunch of #posts, which will be an array of ActiveRecord Relations. That means you can use Ruby's nifty Array methods. Here's an example:
#sorted_posts = #posts.sort_by { |p| p.created_at }.take(20)
And then pass in #sorted_posts where you currently have #posts in the code you posted above. But for performance and good practice you should probably retrieve that data in the proper format from the query itself.
#last_twenty_posts = Post.order("created_at DESC").limit(20) # limit by whatever number you want
Hope that helps!
You can simply order the posts by some attribute specifying the submission time (e.g., created_on) and limit the results to a number you want. For example:
Post.order("created_on DESC").limit(10)
This would return the last 10 Post objects based on their created_on attribute, with the newest first.

How to show text instead of integers?

I have a form with a pull down list of Races (asian, caucasian, African/black, etc).
These races are represented by my Race model. I can create a record successfully, however, when I try to view the record the corresponding integer of the race is displayed and not the text.
How do I get the text associated instead of the integer id?
Thanks.
Provided you supply a minimum set of data for us to assist, I risk an answer as generically as I can.
If you are using a form_for builder
<%= f.collection_select :race_id, Race.all, :id, :name %>
or whatever you call your fields
If you are using a form_tag
<%= select_tag :race_id, options_from_collection_for_select(Race.all, "id", "name") %>
These are as I said pretty generic answers, you can build further on them. Check this link for more:
http://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html
You are seeing the value of the selected option which is the index of the array I imagine. You can use that index to get the text value from your races array. Without seeing more code that is all I can provide.

How to convert an integer column in the model to be used as a string in the view

For database columns that are integers that "represent" strings, what is the best way to show the string value in the view?
For example, if I collect "payment_method" values as integers in my form as follows:
<%= f.select :payment_method, { "Visa" => "1", "Mastercard" => "2", "Amex" => "3"} %>
How can I show the saved integer as a string in my view files? What can I add to my model, so that
<%= #relevantvariable.payment_method %>
or something similar returns string values like "Visa", "Mastercard" or "Amex" instead of their respective integer values?
Thanks much for handling such a basic question!
Either don't use an integer value, and store the payment method directly as a string in the db, or create a PaymentMethod model.
With the association set up, you'd be able to refer to the name of the payment method as so:
<%= #relevantvariable.payment_method.name %>
Don't try to manually handle lists of names / ids - that will quickly get unmanageable.
Edit: after reading your comment, if you went with the first option and stored a string in the table, definitely don't allow the user to type the value directly, maintain a list on the model (or similar), that you seed your dropdown from, that way you're still constraining the possible values. You could even add a custom validator if you want to be certain what you putting in the database.
I'd stick with cheeseweasel solution but you can do one thing to show that on your view...
<% if #relevantvariable.payment_method == 1 %>
<%= "Visa" %>
<% else %>
<%= "Mastercard" %>
You probably would want to use a switch/case instead but you got the idea
As I said I think you should stick with cheeseweasel solution since there are many problems with this approach... it's your call
So you have your payment methods in a separate table payment_methods and the owner ( say user) contains a has_one relationship with it
class User < AR::Base
has_one :payment_method
end
Then show the payment method name just like
<%=
#user.payment_method.name #or whatever you have.
%>
However, while you are loading the #user data, you can perform a eager loading by :include. Like
User.find(user_id, :include => :payment_method)
This will load the PaymentMethod data earlier even for multiple users with single query.

Resources