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.
Related
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 :)
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.
Say I have two models and one belongs to another. Now normaly you would assign an object to the association when populating the fields. Does rails allow overriding the set method so that the association assignment can be customised?
E.g
class Person
# something about shirts
end
class Shirt
belongs_to :person
def person=(p)
self.person = Person.find_or_create_by_name(p)
end
end
And then use something like so auto bind the association but using a string to do the searching and binding automatically. Is this possible?
s = Shirt.new
s.person = "Test Person"
Thanks
ROR Guides cover the association extension you need.
UPDATE:
Actually, overriding setter is not that bad, once you understand what you're doing. But you have to be careful, since it can cause infinite loop (as in your example). So if you're using Rails 3.2, you have to use super, in other case you have to use alias_method_chain.
Short version: Where should I store environment-specific IDs? ENV['some-variable']? Somewhere else?
Long version:
Let's say I have a model called Books and a book has a Category. (For the sake of this question, let's say a book only has one category.)
class Book < ActiveRecord::Base
belongs_to :category
end
class Category < ActiveRecord::Base
has_many :books
end
Now let's say one category is called 'erotica.' And I want to suppress erotica books in my type ahead. That seems straight forward. But in production and in development 'erotica' has a different ID. I don't want my code to be ID dependent. I don't want it to be string dependent (in case 'erotica' is renamed pr0n or whatever).
I think I should have something like
def suppress_method
suppress_category_id = look_up_suppression_id
...
end
but where should 'look up' look?
Thanks!
Taking this approach will be brittle, what if you want to suppress multiple categories? Erotica and Politics? The best design here is for you to actually add 'suppressed' as a boolean to category in a migration, and maintain that in your application's administration interface. After you've done that you can add a named scope like:
class Category < ActiveRecord::Base
named_scope :not_suppressed, :conditions=>{:suppressed=>false}
# or for rails 3
scope :not_suppressed, where(:suppressed=>false)
end
Then just update your type ahead code to do:
Category.not_suppressed.find ...
Rather than
Category.find
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