How can I fetch all the associated records? - ruby-on-rails

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.

Related

Rails3: Use joined table's data

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')

Understanding Rails associations

I'm learning Rails and I'm trying to connect the dots between Ruby and what's going on when creating associations. For example:
class Post < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :posts
end
I've read an explanation online that relates the use of belongs_to and has_many here to attr_accessor in Ruby. This is a tad confusing ... how is that so? I understand this sets up the 1:M association between Post and User, specifically Post has a foreign key containing a user id. In the rails console, I can do something like:
user = User.first
user.posts
user2 = User.create(username: 'some guy').save
post2 = Post.new(title: 'stuff', body: 'some more stuff')
user2.posts << post2
So are these kind of like 'getter' and 'setter' methods where an object of each class corresponds to a specific row in the database and I can use these methods because of their association/relationship?
To answer your exact question, the answer is "kinda yes, kinda no".
What rails does internally to set up the association is pretty complicated. yes, getter/setter methods are involved, yes, pointing at table rows are involved... but this isn't exactly what Active Record does, and it isn't only what Active Record does.
If you really want to know what Active Record does inside: you can just go and look at the source code on github.
If you have a more specific question... I recommend you update your question to ask that :)

How do you associate one model with another?

I have a model called Topic and another called Product.
Here's how the Topic model looks,
class Topic < ActiveRecord::Base
belongs_to :product
end
Topic has columns "title" and "body".
And here's Product,
class Product < ActiveRecord::Base
has_many :topics
end
Product has columns "name" and "desc". Name is unique.
When I create a new Topic, I want the title of Topic to be stored in Name of Product, only if Name doesn't exist yet. If it does, it should not make any change.
But how do I do this?
UPDATE:
User comes to /topics page, enters Title and Body.
What the Topics_controller should do,
1. Read the Title that has been given by the user.
2. Check if that Title already exists in the Products.
3. If it doesn't add it.
4. If it does, don't do anything.
I don't understand how these two models are linked together and how I can access records from the model.
You can achieve this by using one of the callbacks, which ActiveRecord provides.
I'm not sure if I understand your requirements perfectly, so maybe you need to alter the following example:
class Topic < ActiveRecord::Base
belongs_to :product
before_save :add_product_name
private
def add_product_name
self.product.name ||= self.title if Product.find_by(name: self.title).nil?
end
end
You can write a callback like before_create :add_topic_name
Where that method will find product name of topic and assign it to the title of product.
Your requirements are a bit unclear here. Can you specify what your end goal is, from a Behaviour point of view?
If i understand correctly though, why not just overwrite the title method for Topic. This way you are not duplicating data in the DB.
within your Topic class:
class Topic < ActiveRecord::Base
def title
read_attribute(:title) || product.name # will get title of #topic if not nil, else product name
end
end

Scope of the rails find_by_id method

Suppose I have a rails app with two models Person and House. Each Person object has a House_id property.
I would like to define the following method inside of my Person model:
def locate_house
current_house_id = house.find_by_id(person)
end
But I am getting an undefined variable error for house, how can I ensure that this is within scope?
You are trying to rewrite something already built into rails. Use a belongs_to relationship:
class Person < ActiveRecord::Base
belongs_to :house
end
Then you can just do:
person.house
To get the associated house.
Your model--House--is a ruby constant that requires capitalization
def locate_house
current_house_id = House.find_by_id(person)
end
House is a constant and needs a capital letter like someone else said, look at Rails Guides regarding relationships between Active Record Models. There are many possible realtionships, has many is probably what you are looking for. Since, in reality, a person can have multiple houses.

ActiveRecorded associated model back reference

It is easy to associate a model to another using has_many/belongs_to methods. Let's suppose the following models:
class Movie < ActiveRecord::Base
has_many :actors
end
So, I can find the actors from a given movie instance. But now, given an actor instance obtained through the actors association, I'd like to find the movie instance related in the association. Some method like 'associated_instance' or 'back_association' that would make the following statement return true:
movie_instance.actors[0].**associated_instance** == movie_instance
Is there any built in way to do that?
Thanks
Assuming you have your relationships correctly defined, I'm guessing your encountering the situation where you want to effectively traverse an association but then traverse backwards eg.
movie.actors.movie
With a HABTM relationship rails doesn't build the .movie method for you on the actors collection, but what you can do is extend the association to include such a method:
class Movie < ActiveRecord::Base
has_and_belongs_to_many :actors do
def movie
proxy_owner
end
end
end
There is an excellent guide on association extensions by Mike Gunderloy on the Rails Guides site: http://guides.rubyonrails.org/association_basics.html#association-extensions
Hope I've stabbed at this question in the right direction :)
Yes you can do what you want using
movie_instance.actors[0].movie
The question still remains why you would want to do this as you already have it
...given an actor instance obtained
through the actors association...
If you're using the actors association, you already have the movie object. What is the problem that you're trying to solve here?
My suspicion is that if we finally get to the bottom of what you're trying to accomplish, the answer is going to be "read the docs on 'has_and_belongs_to_many' and/or 'has_many :through'."
Edit:
I just now noticed your clarification below (although movies and plots could be considered many-to-many as well, since they get recycled endlessly).
Assuming that you really are trying to use a many-to-one relationship, is the root of your problem that you forgot the following?
class Plot < ActiveRecord::Base
belongs_to :movie
end

Resources