Ruby On Rails Relationships - One to Many - ruby-on-rails

I'm a beginning to ROR, but here's what I'm trying to achieve. I have two items I want to associate: matters and people. Each matter can have many people. That is, I want to create people and matters separately and later be able to link them.
For example, I may create:
Bill Clinton
Barack Obama
I may create the matters:
Global warming
War on terror
I want to be able to associate the users Bill Clinton AND Barack Obama to BOTH matters. Can someone point me to a tutorial that can show me how to do this?

I think has_and_belongs_to_many is used less and less by the RoR community now. While still supported, I think it is now more common to have an intermediate model (in your case something like PoliticianMatter) to join your Politician and Matter models.
Then your politician_matter table will have a PK, a politician_id and a matter_id.
Then you have
class PoliticanMatter < ActiveRecord::Base
belongs_to :politician
belongs_to :matter
end
The advantage of this approach is that if there ever need to be future properties of the politician -> matter relationship (e.g importance, date of last occurrence) you have a model which affords this - has_and_belongs_to_many would not support the addition of these extra properties.
You can also access the many to many relationship directly from the Politician and Matter models like this
class Politician < ActiveRecord::Base
has_many :politician_matters
has_many :matters, :through => :politician_matters
end
class Matter < ActiveRecord::Base
has_many :politician_matters
has_many :politicians, :through => :politician_matters
end

You need a many2many relationship between these two entities.
A matter can be studied by many people
A person can studie several matters
Rails uses the has_and_belongs_to_many helper to do that. You'll find more about that in the documentation and many many blog posts!
has_and_belongs_to_many helper

class Politician < ActiveRecord::Base
has_and_belongs_to_many :tasks
end
class Task < ActiveRecord::Base
has_and_belongs_to_many :politicians
end
What you need are 3 tables:
politicians, tasks and politicians_tasks (having the two columns politician_id and task_id, no primary key)
Hope this helps
Seb

Related

Rails: Marking content as complete for individual users, when content is common across them

I'm relatively new to Rails, so apologies in advance if this is an obvious question. I could not find an answer through searching.
I'm building a basic application which acts as an educational course - users can view lessons, take in the content, and mark lessons as 'complete' accordingly.
I would like users to be able to see which lessons are complete, by marking them as such in the course overview.
I have a Users model and a Lessons model, and the lessons are identical per user at present. If lessons were unique per user, this would presumably be solvable with a boolean 'complete' column for each lesson. This is not the case in this application, however - some users will have completed a lesson; others will not have.
How would I best go about a solution to this? All suggestions and ideas welcome.
Use many-many association and establish relationship among the 3 models.
class Student < ActiveRecord::Base
has_many :progresses
has_many :subjects, through: :progresses
end
class Subject < ActiveRecord::Base
has_many :progresses
has_many :students, through: :progresses
end
class Progress < ActiveRecord::Base
belongs_to :student
belongs_to :subject
end
To be precise use this link to get good understanding on many-many association :)
Third model, say Progress or Completion or Grades or UserLessons... that will belong to user and lesson, and have a field called complete or score or grade....
It's a classic case of many-to-many relation.
User can read multiple lessons
Lessons could be read/complete by multiple users
So to do this is to create another model with column user_id lesson_id as a foreign key for user and lesson and create an additional column completed boolean

Rails Multiple HABTM

I'm building a rails application for an art exhibition website. At the moment I have 4 models, Curator, Exhibition, Artist, and Artwork.
The application should work as follow, An Exhibition can be curated by many curators, an exhibition can display multiple artworks, an artwork can be displayed in many exhibitions, artist can own many artworks, and artworks belongs to one artist.
I'm a rail newb and I'm having difficulty building the relationship between the models. Can you tell me if I'm doing this right, or maybe there is a better way?
curator.rb
class Curator < ActiveRecord::Base
has_and_belongs_to_many :exhibitions
end
exhibition.rb
class Exhibition < ActiveRecord::Base
has_and_belongs_to_many :curators
has_and_belongs_to_many :artworks
end
artwork.rb
class Artwork < ActiveRecord::Base
has_and_belongs_to_many :exhibitions
belongs_to :artist
end
artist.rb
class Artist < ActiveRecord::Base
has_many :artworks
end
Thanks!
I would recommend using has_many :through if you want to have validations on your relationships, use callbacks or want to add extra attributes.
If you want to have more information regarding this matter, this rails guide is great:
http://guides.rubyonrails.org/association_basics.html#choosing-between-has_many-through-and-has_and_belongs_to_many
Your HABTM looks fine though. If you run into any problem, it would be advisable to also reference your joined tables.
It looks right to me.. Do create the join tables naming convention would be:
curators_exhibitions
artworks_exhibitions
Hope you get the idea.
Also you would want to check out has_many :through in case you would want to do validations on top of the relationships!

Rails 2 tables, 1 model

I am relatively new to ruby/rails and I have the following question:
I am working on a scheduling app and have a model named Classes and another named ClassEntries. The relationship between them is that each user can have multiple class entries per semester, each relating to one class. Each record in the Classes table belongs to a specific University. A User can have multiple entries in the ClassEntries table for 1 semester (typically 5). Their schedule is comprised of all their ClassEntries with the same semester ID.
I am not sure whether I should have a third model called Schedule that brings together the info in the ClassEntries and Classes models for the user at hand. I originally wrote this functionality in PHP and I simply used a MySQL JOIN to gather the necessary information. In Rails it seems that there should be a better way to accomplish this.
What would be the best way of going about this in Rails?
Many thanks
So, what you are looking for is pretty much associations in Rails.
You would have the following:
def User < ActiveRecord::Base
has_many :course_entries
has_many :courses, :through => :class_entries
end
def CourseEntry < ActiveRecord::Base
belongs_to :user
belongs_to :course
end
def Course < ActiveRecord::Base
has_many :course_entries
has_many :users, :through => :class_entries
end
With those associations set up, Rails would allow you to do such things like
some_user.courses or some_course.users and it will make the joins through CourseEntry for you.
Let me know if this helps. If you need me to go more in depth let me know.

Many-to-one bidirectional relation in Rails

I'm begininng with Rails and I'm getting kind of confused with the relations.
The problem is quite simple, I have a Station class representing a train station, and a Shop class. I'd simply want the shop to have a station, representing the closest train station, so I guess it would be a many-to-one relation.
Without any ORM I'd just add a foreign key of the station in the shop table. After looking up about rails relations, I ended up with
class Shop < ActiveRecord::Base
belongs_to :station
end
class Station < ActiveRecord::Base
has_many :shop
end
As properly speaking, the shop does not really BELONG to a station I'm finding this kind of strange, so I'd like to know if this is the right way to proceed or if I'm getting confused.
Thank you in advance.
This is the right way to proceed. "Belongs to" simply means "has a foreign key to" - it doesn't necessarily mean that this is a sensible way of describing the relationship in real terms.
As posted, the code won't quite work - you need to pluralize the has_many side; i.e.:
class Station < ActiveRecord::Base
has_many :shops
end
You can test the relationship actually works by firing up the rails console ('rails c') from your application folder and the experimenting with creating objects. Assuming you've created the corresponding tables, you should be able to do things like:
station = Station.create
shop = Shop.create
shop.station = station
station.shops
station.shops.build
...etc
belongs_to and has_many do not describe either the ownership or the scope or the life cycles for the objects they relate. They just describe the references (the keys) between the objects.
Such references can have their life cycle tied with :dependent, :autosave, etc. options.
Other options such as :read_only reduce privileges of edition from reference to another.
Ownership is a concept that you have to define yourself. For instance: a Post in a forum can "belong" to different users with different privileges. Who is the owner? The admin? The last editor? The one that created the post? For such behaviors, extra definition and mechanics are needed. I recommand you take a look at the CanCan gem for this ( https://github.com/ryanb/cancan ).
class Station < ActiveRecord::Base
has_many :shops, :dependent => "nullify"
end
if your station gets deleted still the shops will be their

ActiveRecord relationships between HAVE and IS

So I have the following models in my Ruby on Rails setup: users and courses
The courses need to have content_managers and those content_managers are made up of several individuals in the users model.
I'm a newbie, so bear with me. I was thinking of creating a new model called content_managers that has a user_id and a course_id that links the two tables. It makes sense to me that courses HAVE content_managers. However from the users model, it doesn't make sense that users HAVE content_managers. Some of them ARE content_managers.
From that point of view I believe I'm thinking about it incorrectly and need to set up my ActiveRecord in a different manner from what I'm envisioning. Any help is appreciated.
Thanks!
There's no "have" or "are" in ActiveRecord, only "has_many", "has_one" and "belongs_to". With those tools you should be able to do what you want.
An example:
class Course < ActiveRecord::Base
has_many :content_managers
end
class ContentManager < ActiveRecord::Base
has_many :content_manager_members
has_many :users,
:through => :content_manager_members,
:source => :user
end
class ContentManagerMember < ActiveRecord::Base
belongs_to :course_manager
belongs_to :user
end
class User < ActiveRecord::Base
has_many :content_manager_members
has_many :content_managers,
:through => :content_manager_members
end
Be sure to index these correctly and you should be fine, though navigating from User to Course will be slow. You may need to cache some of this in order to find the level of performance you want, but that's a separate issue that will be uncovered during testing.
Whenever implementing something like this, be sure to load it up with a sufficient amount of test data that will represent about 10x the anticipated usage level to know where the ceiling is. Some structures perform very well only at trivial dataset sizes, but melt down when exposed to real-world conditions.

Resources