How to edit additional data in HABTM tables? - ruby-on-rails

How do I update additional data in HABTM tables.
For Example: I have movies, people and HABTM movies_people tables, but there is additional persontype_id field in movies_people table which indicates role of this person in that particular movie. How do I add/change this value?

You should probably be using a has_many :through association, which was introduced just for this reason. Instead of just a movies_people table, you'd have an additional model, called somthing like Favorite or Viewing (depending on what you're trying to accomplish with the association), which belongs_to both :movies and :people, and in your Movie model, you'd do
has_many :favorites
has_many :people, :through => :favorites
This gives you access to movie.people for all the people who have favored this movie and movie.favorites to access anything that would be in your favorites table (like persontype_id)
Josh Susser's Article, Many-to-Many Dance Off does a much better job of explaining this that I could ever hope, so for additional help, I'd take a look at it. http://blog.hasmanythrough.com/2006/4/20/many-to-many-dance-off

There is also a great Railscast on the subject, by Ryan Bates:
http://railscasts.com/episodes/47-two-many-to-many

Related

Relationship advice/association logic in rails

I'm designing an application to create goals for a classroom - at the moment, the data relationships are modeled like this
I knew that out of inexperience I might run into problems and now I'm beginning to - specifically in my routes file - but also just for generally organizing the site and the data relationships.
When a user signs up, they add a student_group (or class), populate it with students and then add subjects. Later they add goals for each subject - although there should also be goals for a student_group, a student, or even the user. I was thinking of something like this - but would it be better as a has_many, through relationship?
Right now, I've only really done work on the User, Student_group, and Student models and these are fairly straight-forward. A user has many student_groups, and a student_group has many students. I'd like a second opinion before I proceed however, so that I don't have to end up going back and doing things over. Thanks!
I think you might be thinking too far ahead. Once you have your app built around your current data model, you'll know better whether you even want to expand it to include the concept of a goal that isn't part of a student's subject. If you decide that it is, then making goals belong_to a subject, student, or user will be pretty simple. At that point, you could also do something like
Class Student
has_many :personal_goals, class_name: "Goal"
has_many :goals, through: :subjects
def all_goals
goals + personal_goals
end
There's probably a more elegant way to model that last relationship. Would you need to go beyond that? Does it make sense to talk about a student group having a goal of its own? I don't know.
As I gone through your database design, I have found that you should have to use different type of relationships, that rails has provided us. I tried my best to design your schema as per my knowledge. you should define relationship in your model as I suggested below. Any good modification are highly appreciated.
User
has_many :student_groups
has_many :students, through: :student_groups
has_many :goals, as: :goalable
StudentGroup
belongs_to :user
has_many :students
has_many :goals, as: :goalable
Student
belongs_to :student_group
has_many :subjects
has_many :characteristics
has_many :goals, as: :goalable
Characteristic
belongs_to :student
Goal
belongs_to :goalable, polymorphic => true
I have defined some polymorphic associations in your schema. If you need any reference related to these association. visit http://guides.rubyonrails.org/association_basics.html
Hope it will help you. Thanks.

Validate uniqueness through join model in rails

I have a has_many :through association setup between two tables (Post and Category). The reason I'm using has_many :through instead of HABTM is that I want to do some validation on the join table (PostCategory).
So I have 4 models in use here:
User:
has_many :posts
has_many :categories
Post:
belongs_to :user
has_many :post_categories
has_many :categories, :through => :post_categories
Category:
belongs_to :user
has_many :post_categories
has_many :posts, :through => :post_categories
PostCategory:
belongs_to :post
belongs_to :category
Basically what I want is: Users can create posts, users can also create their own categories. A user can then categorize posts (not just their posts, any posts). A post can be categorized by many different users (in different ways potentially), and a category could contain many different posts (A user could categorize N posts under a specific category of theirs).
Here's where it gets a little bit tricky for me (I'm a Rails noob).
A post can ONLY belong to ONE category for a given user. That is, a post CANNOT belong to more than ONE category for any user.
What I want to be able to do is create a validation for this. I haven't been able to figure out how.
I've tried things like (inside PostCategory)
validates_uniqueness_of :post_id, :scope => :category_id
But I realize this isn't correct. This would just make sure that a post belongs to 1 category, which means that after one user categorizes the post, no other user could.
Really what I'm looking for is how to validate this in my PostCategory model (or anywhere else for that matter). I'm also not against changing my db schema if that would make things easier (I just felt that this schema was pretty straight forward).
Any ideas?
The simpliest way is to add user_id to PostCategory and to validate uniqueness of post_id with user_id scope.
Another way is to create custom validation which checks using sql if category owner has added category to that post.
Option 1 : use a before_save. In it, do a SQL look up to make sure a post with a similar category for your user doesn't exist (take care that on edit, you'll have to make sure you don't look-up for the current Post that is already in the DB)
Option 2 : custom validators :
http://guides.rubyonrails.org/v3.2.13/active_record_validations_callbacks.html#custom-validators
Never used them, but sounds like it can do what you want

Whats the cleanest way to handle many-to-many relationships in ruby on rails?

I have one model say user, that can live in multiple towns (represented as another model). If I create a new user I have to choose (and edit) the different towns that they live in. Due to time constraints, I often end up with a "hackyier than I would like" solution involving something like: http://blog.hasmanythrough.com/2006/4/20/many-to-many-dance-off.
Any nice solutions that are popular with SO?
cheers...
Slothishtype
The has_and_belongs_to_many association was built for this very situation. Here is the documentation on it: http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_and_belongs_to_many
Otherwise, if you need to store information abotu the association itself (fields that would not exist in the city table or the user table, but in between), you might just want to set up two, parallel 'has_many_through' associations, and set up a seperate 'user_city' table. So it would be in the user table
has_many :user_cities
has_many :cities, :through => :user_cities
and in the cities table
has_many :user_cities
has_many :users, :through => :user_cities
Then, you CAN just call: user.cities, and get a list of the cities the user lives in.

Best way to model a user's "friendship" with different entities?

I have the following entities:
User
Company
Organization
Users need to be able to add Users, Companies, Organizations, and future party objects to their friend list.
My original idea involved using a Friendship object with a polymorphic relationship to the friend like so:
Simplified Friendship schema:
user_id
friendable_id
friendable_type
User
- has_many :businesses, :through => :friendships, :conditions => ['friendable_type=?', 'Business'], :source => :friendable
My problem is that Ruby on Rails ActiveRecord does not support has_many through relationships through polymorphic relationships on the join table such.
In the end I want to have a single join table to be able to iterate through to get a list of friends of all types, certain types, etc. like below:
john = User.find(5)
john.friendships.map {|friendship| friendship.friendable }
john.businesses (has_many :through scoped to only the businesses)
john.organizations (has_many :through scoped only to the organizations)
I've considered making the User, Business, and Organization inherit from a generic Party class and making the association point to the base Party class, but in the context of an ORM that leads to a bunch of junk fields and it just seems dirty.
What I'd like to know is how others would approach a situation like this where you want to create one-to-many relationships to similar objects through a common join table using ActiveRecord while avoiding this error: :)
Cannot have a has_many :through association 'User#businesses' on the polymorphic object 'Friendship#friendable'.
Any advice greatly appreciated.
Thanks!
Do not use :through, use :as=>friendable instead in polymorphic has_many relationship
It appears that the Rails plugin 'has_many_polymorphs' allows me to do exactly what I want.
http://github.com/fauna/has_many_polymorphs/tree/master
Adding this line to my User model gave me the functionality I wanted:
has_many_polymorphs :friendables, :from => [:businesses, :organizations], :through => :friendships

How should I architect this with Ruby on Rails?

Sorry for the vague title, but this is kind of hard to put into one line.
I have a database full of contact information, and I want to be able to put those different contacts into groups which will also be stored in the database.
So, maybe I have 2 groups, "coworkers" and "neighbors", I want to be able to see a list of all my contacts and be able to add individual contacts to one or more groups.
I'm kind of confused as where to begin with this, could I get some basic outlines of how this might best be implemented? Thanks.
Well, you've got two models, Contact and Group. These two guys are clearly going to have their own tables (probably 'contacts' and 'groups' if you're following the Rails conventions). Since a contact can be in many groups, and a group can have many contacts, you've got what's called a many-to-many relationship between these models. There are basically two ways to implement this in Rails: has_and_belongs_to_many or has_many :through. Which one is best for you will depend a little on your situation.
has_and_belongs_to_many is probably the path of least resistance. You put a couple lines in your models like so:
# contact.rb
has_and_belongs_to_many :groups
# group.rb
has_and_belongs_to_many :contacts
...and create a table called 'contacts_groups' with the columns contact_id and group_id, and you're basically good to go. Easy peasy.
On the other hand, there are some advantages to using an association model with has_many :through. In this approach, you create another model, say, GroupMembership, and set up your models like so:
# contact.rb
has_many :group_memberships # this isn't strictly required, but I'd recommend it
has_many :groups, :through => :group_memberships
# group_membership.rb
has_many :groups
has_many :contacts
# group.rb
has_many :group_memberships # again, recommended but not required
has_many :contacts, :through => :group_memberships
This gives you most of the same convenience methods as has_and_belongs_to_many, and also lets you store any extra data you might want about the association, like the date they joined the group or the reason they were added. Even if you don't have any of that now, it's nice to account for the possibility of adding it later. Also, this lets you take a more RESTful approach to adding and removing contacts to and from groups, if that's something you're interested in, since you can model it in terms of creating and destroying GroupMembership resources.
By and large, I tend to lean toward the latter approach, especially as I've gotten more in to RESTful architectures. On the other hand, if you're not worried about REST and you're certain you'll never want to keep any extra information about memberships, has_and_belongs_to_many is probably simpler and requires less code to get working. For more in-depth information on the differences and implementation details, see the ActiveRecord Associations API docs.
You could structure a Ruby on Rails database to be :
Contact ( first_name:string, last_name:string, title:enum number:string, cell:string, notes:text, email:string ) => many_many :groups (or has_many :groups, :through=> :contact_group)
Contact_Group { group_id:integer, contact_id:integer }
Group ( name:string ) => many_many :contacts ) (or has_many :contacts, :through=> :contact_group)
That might be the general idea. You also could do relational fields.
You don't want to use the has_and_belongs_to_many approach. It's deprecated. Please read the API and make sure you implement a join model / has_many :through approach. The API will tell you how to do this and also mention why has_and_belongs_to_many is bad.
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Resources