Ruby on rails migration question - ruby-on-rails

In the following code a post is created and belongs to Person:
class Person < ActiveRecord::Base
has_many :readings
has_many :posts, :through => :readings
end
person = Person.create(:name => 'john')
post = Post.create(:name => 'a1')
person.posts << post
But I wonder which Reading this post belongs to when it's saved.
I dont quite understand that.
Thanks

post.reading would be nil
Now, I don't think that's what you want, so you'd probably want to protect against that beings saved:
class Reading < ActiveRecord::Base
belongs_to :person
has_many :posts
validates_presence_of :person
end
But, that still seems a bit wrong to me... I'd think that you could have a Person on its own, and a Post on its own, but a reading is the intersection of a Person and a Post. In that case:
class Person
has_many :readings
end
class Post
has_many :readings
end
class Reading
belongs_to :person
belongs_to :post
validates_presence_of :person, :post
end

Related

HABTM relationships with polymorphism

I've got a Person who can be linked to many Structures (structure is polymorphic)
I've got a Venue, who can have many People, as a structure.
I've got a Journal, who can have many People, as a structure.
Here is my modelization :
class Venue < ActiveRecord::Base
has_many :structure_people, :as => :structure
has_many :people, :through => :structure_people
end
class Journal < ActiveRecord::Base
has_many :structure_people, :as => :structure
has_many :people, :through => :structure_people
end
class Person < ActiveRecord::Base
has_many :structure_people
has_many :structures, :through => :structure_people
end
class StructurePerson < ActiveRecord::Base
belongs_to :structure, polymorphic: true
belongs_to :person
end
My problem :
when i try to get people on a Venue or on a Journal, it works. Cool :)
BUT
when i try to get structures on a person, i've got an error :
ActiveRecord::HasManyThroughAssociationPolymorphicSourceError: Cannot have a has_many :through association 'Person#structures' on the polymorphic object 'Structure#structure'.
Anyone could help me to solve this ?
Thanks a lot.
Christophe
I think it's a restriction of Rails, because has_many association will guess a class_name automatically. But polymorphic association may returns multiple class_name. Do you mind use this:
class Person < ActiveRecord::Base
has_many :structure_people
has_many :venues, :through => :structure_people
#Journal is the same.
end
class StructurePerson < ActiveRecord::Base
belongs_to :structure, polymorphic: true
belongs_to :venue, :foreign_key => 'structure_id', :conditions => {:structure_type => 'Venue'}
belongs_to :person
end
Although it is an ugly solution...
I think you can choose an alternative way.
class Person < ActiveRecord::Base
has_many :structure_people
def structures
structure_people.map(&:structure)
end
end
You can't get chaining function of has_many, but you can get polymorphic structures :)

Rails: stringing together multiple has_many relationships

I have three models which look something like this:
Class User < ActiveRecord::Base
has_many :comments
end
Class Comment < ActiveRecord::Base
belongs_to :user
has_many :votes
end
Class Vote < ActiveRecord::Base
belongs_to :comment
end
Now I want to get all the votes associated with a user's comments like so:
#user.comments.votes
But this throws the error:
undefined method `votes' for #<ActiveRecord::Relation:0x3f6f8a0>
This seems like it should work, but I suspect ActiveRecord is coughing on the deeper has_many relationship. I've hacked together an SQL query that gets the desired results, but I suspect there's a cleaner way using purely ActiveRecord. Any tips?
You should use a has_many :through association
In your case it would be
Class User < ActiveRecord::Base
has_many :comments
has_many :votes, :through => :comments
end
Class Comment < ActiveRecord::Base
belongs_to :user
has_many :votes
end
Class Vote < ActiveRecord::Base
belongs_to :comment
end
And then simply get the votes with
#user.votes
Try this:
Vote.joins(comment: :user).where(users: {id: #user.id})

Nested associates the rails way

I'm fairly new to Rails and I'm trying to gain a better understanding of how to be leverage the Rails framework for my associations.
While it's not specific for my app, the structure is similar -- for my example, I'll use the standard blog associates.
Example Models:
class Author < ActiveRecord::Base
has_many :posts, :through => :posts
end
class Post < ActiveRecord::Base
belongs_to :author
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
end
My challenge is that I want to select all comments that belong to a specific author. I understand how to reference post and author elements that are associated with a specific post:
comment_author = Comment.first
puts comment_author.post.author.name
But as I stated I'm trying to select all comments that belong to a specific author. I could accomplish this by doing a find_by_sql, but I want to ensure db independence and I want to do this the "Rails way."
Thanks!
You can use the has_many :through assocication:
class Author < ActiveRecord::Base
has_many :posts
has_many :comments, :through => :posts
end
#Femaref provided the exact answer to your question and you should accept it. Mine is merely a complement.
If an author can leave comments on posts, here is what you might want to do:
class Author
has_many :posts
has_many :comments
has_many :responses, through: :posts, source: :comments
end
class Post
belongs_to :author
has_many :comments
end
class Comment
belongs_to :author
belongs_to :post
end
To get all the comments left by sophia: sophia.comments
To get all the comments left on sophia's posts: sophia.responses
See the options for has_many (especially through and source)

activerecord / db theory - where do I put these fields?

I have the models shown below. I need to store some details that are specific a person and a house (first_viewed:date, opening offer:decimal, etc). I feel like these should belong to the PersonHouse model but I'm not certain enough. Any suggestions?
class Person < ActiveRecord::Base
has_many :houses, through: :person_houses
has_one :favorite_house, through: :person_houses
end
class PersonHouse < ActiveRecord::Base
belongs_to :house
belongs_to :person
end
class House < ActiveRecord::Base
has_many :house_people
has_many :people, through: :person_houses
end
I could do something like this to get all the details but perhaps there is a more effient way.
#house = House.find(1)
#house.house_people.each do |hp|
puts hp.person.name
puts hp.first_viewed
puts #house.address
end
I think your assumption is correct. If the data is relevant to the relationship between a person and a house, then yes it belongs on this model. The only recommendation I would make is to rename this model to a name that better describes what the relationship is. It doesn't have to be the concatenation of the two models it joins. I don't know exactly what the model is going to be ultimately used for, but SelectedHouse, HouseProspect or something along those lines might work.
You can also delegate properties to the house or person models:
class PersonHouse < AR::Base
belongs_to :person
belongs_to :house
delegate :address, :to => :house, :prefix => true
delegate :name, :to => :person, :prefix => true
end
person_house.address
person_house.person_name

Rails has_many :through and has_one :through associations

First I'm using Rails 3.1 from the 3-1-stable branch updated an hour ago.
I'm developing an application where I have 3 essential models User, Company and Job, Here's the relevant part of the models:
class User < ActiveRecord::Base
has_many :companies_users, class_name: "CompaniesUsers"
has_many :companies, :through => :companies_users, :source => :company
end
class Company < ActiveRecord::Base
has_many :companies_users, class_name: "CompaniesUsers"
has_many :employees, :through => :companies_users, :source => :user
has_many :jobs, :dependent => :destroy
end
class Job < ActiveRecord::Base
belongs_to :company, :counter_cache => true
end
class CompaniesUsers < ActiveRecord::Base
belongs_to :company
belongs_to :user
end
The code works just fine, but I have been wondering if it's possible to:
I want to link a job with an employer, so think of this scenario: A user John who's an employee at Example, he posted the job Rails Developer, so I want to access #job.employer and it should get me back the user John, in other words:
#user = User.find_by_name('john')
#job = Job.find(1)
#job.employer == #user #=> true
So I thought of two possible solutions
First solution
class Job
has_one :employer, :through => :employers
end
class User
has_many :jobs, :through => :employers
end
class Employer
belongs_to :job
belongs_to :user
end
Second solution
class Job
has_one :employer, :class_name => "User"
end
class User
belongs_to :job
end
Which route should I go? Is my code right ?
I have another question, how to get rid of the class_name => "CompaniesUsers" option passed to has_many, should the class be Singular or Plural ? Should I rename it to something like Employees ?
P.S: I posted the same question to Ruby on Rails: Talk
Unless I'm missing something, I'd suggest simply doing
class Job
belongs_to :employer, :class_name => "User"
end
class User
has_many :jobs
end
This would give you methods like
user = User.first
user.jobs.create(params)
user.jobs # array
job = user.jobs.first
job.employer == user # true
You'll need an employer_id integer field in your Jobs table for this to work.
Typically you want to name your pass through model:
company_user
Then you don't need this:
class_name: "CompaniesUsers"
Just make sure the name of your database table is:
company_users
What you have works for you, so that's great. I just find when I don't follow convention I
run in to trouble down the road.

Resources