Rails 3 Joins -- Select only certain columns - ruby-on-rails

Below is a relationship between Comments and a user. Each comment has one user so I'm building out a join in the code below.
I was wondering how to build this code to only include specific columns in the join. I don't need all of the user information. Just the first_name. Any suggestions.
Current Code:
#comments = Comment.where(:study_id => #study.id).joins(:user)

You could use something like this:
#comments = Comment.joins(:user)
.select("comments.*, users.first_name")
.where(study_id: #study.id)

Extending Aldo's answer to show a way to retrieve the resulting foreign column value.
#comments = \
Comment\
.joins(:user)
.select("comments.*, users.first_name as users_first_name")
.where(study_id: #study.id)
# Now it's stored on each comment as an attribute, e.g.:
puts #comments.first.read_attribute(:users_first_name)
puts #comments.first.attributes['users_first_name']
# Note that inspecting the comment won't show the foreign data
puts #comments.first.inspect # you won't see user's first name output
You could also declare users_first_name as an attrib on the comment with attr_accessible. I don't think there's any magic way to automatically set it, but you could easily do so yourself in a post-select loop.

Related

Ruby on Rails controller order with strings

So I'm trying to organize one of my views so that the articles of my website are listed by the name of the title. For example some of my articles are named "article pt.1, history pt.2, society pt.1, etc". I do have them sorted correctly using this line of code in the Articles controller
def index
#articles = Article.order(:user_id)
end
It does work using the user id, but if I wanted to add another category and have them in alphabetical order, I would need to update the user id of each article which is not practical as they number a little over 200 in the database. What I would like to is somehow take a partial of the article title and sort each one like I am with the user_id field. This way I can sort each one using the string partial such as "article" from "article pt.1"
Thank you for reading and have a wonderful day!
Why not just sort by the title? Assuming you have a column in your articles table called title:
For alphabetical order
def index
#articles = Article.order(:title)
end
For reverse alphabetical order
def index
#articles = Article.order(title: :desc)
end
If you really want to just sort by a substring of the title. You'll have to add a new column to the articles table (called slug in this example):
rails g migration AddSlugToArticles slug:text
rails db:migrate
Then you'll have to update the slug field of every record
Article.all.each do |article|
new_slug = #your code to generate substring here
article.update(slug: my_string
end
then order by slug:
def index
#articles = Article.order(:slug)
end
First of all, it is not very clear about the output that you want, but based on assumption and the description mentioned in the post, it seems like you want to sort the string field not based on whole value but based on substring.
It is better to use the order to get the strings alphabetically sorted.
#articles = Article.order(:title)
And it will also serve the purpose as it will first match the first alphabet of each string and also handle null values at the same time.
Why write a custom logic if the purpose is fulfilled by an already defined method.
I was able to do it using the sort function instead of order using the :title field on the articles controller.
def index
#articles = Article.sort(:title)
end

Rails join single record to scope

Lets say there is a model called Comments. No we do #comments = Comment.where(name: 'John'). Next we do comment = Comment.find_or_create_by(...). Is there a way in Rails to join comment to #comments? For arrays I can do #comments << comment but I want activeRecords...
#comments.inspect returns "#<ActiveRecord::Relation []>"
I'm using rails 5.1.3
Thanks, Andreas
#comments will be an array of instances of Comment. comment will be an instance of Comment. Therefore, there is nothing wrong with doing #comments << comment and it will achieve the result you desire.
You should try before asking!
Active Record Relations have every method that arrays do available to them, so all you need to do is:
#comments << comment
or
#comments.push(comment)
EDIT: Have tried the above and seems to work for me however another solution:
ids = #comments.collect(&:id)
#comments = Comment.where(id: (ids + comment.id))
This will take the ID's from every record in #comments, then add them to the other comment's ID, then return all comments that have an ID in that range
Yes you can do something like this
If you want data in the active record format.
Comment.where(conditions).or(Comment.where(id: 1))
The rest of all the solution are complex or provides the data in the array form.

Does Rails Auto-Assign ID's?

I'm trying to sort my users in my controller, and I wanted to sort them by id number. My question is, does rails automatically assign orders an id when they are created, or do I need to add that to the create function in my create action in my controller? For example, can I say this:
def index
#users = User.all.order(:WHAT TO PUT HERE???????)
end
Would I put :id in the space? If I did so, would I need to define id somewhere else or is this something ruby does on the back end?
In most cases Rails would return you records sorted by id. But you should not rely on Rails as sorting is database-specific.
To explicitly add sorting by id you should use:
def index
#users = User.order(:id)
end
Id is automatically added, you don't need to declare it anywhere.
Rails only helps you create the table via migrations. When a migration creates a table it automatically adds the id column as a primary key set to auto increment. So why you create records it's actually the database that adds the id, or as aforementioned, it auto increments it +1 from the last id. Therefore, when you use ActiveRecord to create a record you don't need to specify an id.
Now for your main question: you can pass the name of the column to the order method when you want to sort ascending by that column. You don't need to call all though.
So just do this:
User.order(:id)
That will sort from lower ids to higher. To do the opposite:
User.order("id DESC")
This will give your the most recently created records first by sorting from higher ids to lower.
If you want to sort User by ID
#users = User.order(:id) #ASC default
#users = User.order('id ASC') #ASC explicit
#users = User.order('id DESC') #DESC explicit
...and never forget the User.order('-id') unary minus shortcut...

Rails 4: Ordering Users based on the *last word* in their `name` attribute?

I have a User model with a name attribute. In my PagesController, I want to set an instance variable equal to all of the User objects, but I want to order them based on last name. I know I can do:
#sortedusers = User.order(:name => :asc)
to order the users based on their name attribute, but how do I do it based on last name? (i.e. how do I order the Users based on the last word of their name attributes?
Thanks.
Define a virtual attribute last name in your model
def last_name
name.split(' ').last
end
and then
User.order(:last_name => :asc)
I'd suggest storing the users' last name separately. Barring that, you can use sort_by, like so:
items.sort_by! { |a| a.split(' ') } or something along those lines. Note, this most likely cannot be used straight, it's merely intended to point you in the right direction, as most of my answers are.

Postgres ORDER BY values in IN list using Rails Active Record

I receive a list of UserIds(about 1000 at a time) sorted by 'Income'. I have User records in "my system's database" but the 'Income' column is not there. I want to retrieve the Users from "my system's database"
in the Sorted Order as received in the list. I tried doing the following using Active Record expecting that the records would be retrieved in the same order as in the Sorted List but it does not work.
//PSEUDO CODE
User.all(:conditions => {:id => [SORTED LIST]})
I found an answer to a similar question at the link below, but am not sure how to implement the suggested solution using Active Record.
ORDER BY the IN value list
Is there any other way to do it?
Please guide.
Shardul.
Your linked to answer provides exactly what you need, you just need to code it in Ruby in a flexible manner.
Something like this:
class User
def self.find_as_sorted(ids)
values = []
ids.each_with_index do |id, index|
values << "(#{id}, #{index + 1})"
end
relation = self.joins("JOIN (VALUES #{values.join(",")}) as x (id, ordering) ON #{table_name}.id = x.id")
relation = relation.order('x.ordering')
relation
end
end
In fact you could easily put that in a module and mixin it into any ActiveRecord classes that need it, since it uses table_name and self its not implemented with any specific class names.
MySQL users can do this via the FIELD function but Postgres lacks it. However this questions has work arounds: Simulating MySQL's ORDER BY FIELD() in Postgresql

Resources