Rails3: Use joined table's data - ruby-on-rails

I'm trying to access my joined table data but alas..
For example association between authors and books, author have many books:
I'm using join funtion to join the author table to the books table in order to access the author's author_name attribute
class Author < ActiveRecord::Base
has_many :books
attr_accessible :author_name
end
class Book < ActiveRecord::Base
belongs_to :author
end
random_author = Author.first
books = random_author.books.where(id > 5).joins(:author) #this should make all author attributes available to each book, right?
book_1 = books.first
book_1.author_name
=> NoMethodError: undefined method `author_name' for #<Book:0x111111>
Of course using the association would work: book_1.author.author_name but that will require another query, which is what I'm trying to avoid.
I mean the joins operation joins the author's data- there must be a way to access it right?
p.s. I can use includes method. and eager load the author data as well, but since I'm just needing a single attribute- is there a way to accomplished it with only a joins method? Thank you

You need to add
.select('books.*, author.name AS author_name')
So your query becomes
books = random_author.books.where(id > 5).joins(:author).select('books.*, author.name AS author_name')

Related

How to retrieve all related objects from an existing selection set in Rails

In a Rails app I have two models which are related via has_many and belongs_to associations:
class Entity < ActiveRecord::Base
has_many :applicants
end
class Applicant < ActiveRecord::Base
belongs_to :entity
end
I'm using SearchKick to first select some Entities - the details of this don't really matter, but given an existing collection of Entity objects, how can I retrieve all of the related Applicant objects?
# select some entities (in my app I'm using SearchKick to run the search)
entities = Entity.search params[:query]
# now find the applicants related to the selected entities
applicants = entities.???
This works, but is very slow given a large selection:
# retrieve the applicants related to the selected entities
applicants = []
entities.each do |entity|
applicants += entity.applicants
end
Is there a Rails short-hand to retrieve the Applicants related to the selected Entities?
Other things I've tried:
entities.class => Entity::ActiveRecord_Relation
entities.applicants => #error
entities.applicant_ids => #error
Like this?
Applicant.joins(:entity).where("entities.id < ?", 1000)
This answer came from Andrew Kane, the developer of SearchKick:
One way is to use the include option to eager load associations.
Entity.search "*", include: [:applicants]
Another option is to get all ids from the entities, and pass them into
a query for applicants.
Applicant.where(entity_id: entities.map(&:id))
I found that the second option worked well for me.
Entity.where("id < ? ", 1000).includes(:applicants)
To get all applicants
Entity.where("id < ? ", 1000).includes(:applicants).collect(&:applicants).flatten

And query for Activerecord has_many relations with array argument

I need to make and query with has_many relation model.
I have following tables. Articles has has_many relation to tags.
class Article < ActiveRecord::Base
has_many :tags
end
class Tag < ActiveRecord::Base
belongs_to :article
end
For example, I would like to get articles contains "BBQ" and "Pork"
I have following code but it return articles contains "BBQ" or "Pork"
tags = ["BBQ", "Pork"] # number of items could be any
Article.joins(:tags).where(tags: { tag_name: tags } )
Edit:
We don't know how many items in tags.
tag_name field is String.
It's not that pretty but you could try
Article.joins(:tags).where(tags: { tag_name: "BBQ" } ).where(tags: {tag_name: "Pork"})
If you need something more reusable you can create a scope such as "by_tag_name":
Article.rb
scope :by_tag_name, ->(name) { where(tags: {tag_name: name} }
And use it simply like:
Article.joins(:tags).by_tag_name("BBQ").by_tag_name("Pork")
If tags is of unknown size:
#articles_with_tags = Article.joins(:tags)
#assume tags is a regular ruby array ["Pork", "Soy Sausages"]
tags.each do |tag|
#articles_with_tags = #articles_with_tags.by_tag_name(tag)
end
I would first get all the tag records that are BBQ like so:
Tag.where(tag_name:"BBQ")
Then from those, I would add all the tag records that have tag_name Pork:
Tag.where(tag_name:"BBQ") + Tag.where(tag_name:"Pork")
Then in order to the the articles that they belong to, I would take the combined array and append .articles.
So my final search would be:
(Tag.where(tag_name:"BBQ") + Tag.where(tag_name:"Pork")).articles
Note on database structure
My guess is that you want to have two tables, one for all the tags used on your site, and one for the articles. You want each article to possibly have multiple tags. If thats the case, then it might make more sense to make a join table instead of just having the two, because that would mean that a tag could belong to multiple articles and and multiple articles could belong to a tag. To do that, you would add a table:
create_table :article_tags do |i|
i.integer :article_id
i.integer :tag_id
end
In that case, you could have a simpler query.

How to retrive same name attributes of joined table in active record rails 4

I have following association
class Article < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :article
end
comments and articles table both contains column name text. I want to join both the table and would like to to get all the attributes from articles table including text attribute and text attribute from comments table.
In sql i would do something like this
select comments.text as comment_text, articles.* from articles,comments
I want to achieve same o/p using active record query.
I tried following thing but it didn't work
Article.joins(:comments).select("articles.*", "comments.text as comment_text")
Above query only return text attribute of comment and not the text attribute of articles table. What am I doing wrong?
I think what you looking for is how to do a eager loading.
Article.includes(:comments)
Try this:
Article.includes(:comments).select("articles.*, comments.text as comment_text")

How can I fetch all the associated records?

Current_user has many favorite communities. Favorite communities can be fetched by this.
#communities = current_user.get_up_voted(Community)
Then each community has many topics just like this.
Community has_many: Community_topics
Community_topic belongs_to: Community
Now, how can I fetch all the topics that are belonging to current_user's favorite communities?
I tried this
#communities = current_user.get_up_voted(Community)
#community_topics = Community_topics.where(:community_id => #communities).page(params[:page]).order("last_active_at DESC")
But I got this error:(
NameError (uninitialized constant UsersController::Community_topics):
Follow the documentation to the letter:
A has_many association indicates a one-to-many connection with another
model. You’ll often find this association on the “other side” of a
belongs_to association. This association indicates that each instance
of the model has zero or more instances of another model.
Make sure your spelling is correct, that you have a parent_table_id field in the child table, and you have declared that the child table belongs_to its parent.
If you make a model:
e.g. my_model.rb
it contents should looke like this:
class MyModel < ActiveRecord::Base
end
so in controller you will call it:
#myvariable = MyModel.where(......)
Make sure of your naming conventions. Check if they are correct.

Using Retrieval Multiple Objects for another Retrieval in Active Records/Ruby on Rails

Kind of new to Ruby/Rails, coming from c/c++, so I'm doing my baby steps.
I'm trying to find the most elegant solution to the following problem.
Table A, among others has a foreign key to table B (let's call it b_id), and table B contains a name field and a primary (id).
I wish to get a list of object from A, based on some criteria, use this list's b_id to access Table B, and retrieve the names (name field).
I've been trying many things which fail. I guess I'm missing something fundamental here.
I tried:
curr_users = A.Where(condition)
curr_names = B.where(id: curr_users.b_id) # fails
Also tried:
curr_names = B.where(id: curr_users.all().b_id) # fails, doesn't recognize b_id
The following works, but it only handles a single user...
curr_names = B.where(id: curr_users.first().b_id) # ok
I can iterate the curr_users and build an array of foreign keys and use them to access B, but it seems there must be more elegant way to do this.
What do I miss here?
Cheers.
Assuming you have following models:
class Employee
belongs_to :department
end
class Department
has_many :employees
end
Now you can departments based on some employee filter
# departments with employees from California
Department.include(:employees).where(:employees => {:state => "CA"}).pluck(:name)
For simplicity, let's take an example of Article and Comments, instead of A and B.
A Comment has a foreign key article_id pointing at Article, so we can setup a has_many relationship from Article to Comment and a belongs_to relationship from Comment to Article like so:
class Article < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :article
end
Once you have that, you will be able do <article>.comments and Rails will spit out an array of all comments that have that article's foreign key. No need to use conditionals unless you are trying to set up a more complicated query (like all comments that were created before a certain date, for example).
To get all the comment titles (names in your example), you can do <article>.comments.map(&:title).

Resources