I'm unable to grasp the detail understanding of following rails association.
has_many through
has_and_belongs_to_many
What this associations do and the effect on table? please help
Has_many is basically saying that one thing links to many, for example one category has many products within in. Belongs_to is basically the other way around, so a product belongs to category. They allow you to retrieve data from a table that links to the other table e.g. You could get the category title from the product table for a certain product through that link. Does that help?
From Choosing Between has_many :through and has_and_belongs_to_many
Rails offers two different ways to declare a many-to-many relationship
between models. The simpler way is to use has_and_belongs_to_many,
which allows you to make the association directly:
class Assembly < ActiveRecord::Base
has_and_belongs_to_many :parts
end
class Part < ActiveRecord::Base
has_and_belongs_to_many :assemblies
end
The second way to declare a many-to-many relationship is to use
has_many :through. This makes the association indirectly, through a
join model:
class Assembly < ActiveRecord::Base
has_many :manifests
has_many :parts, through: :manifests
end
class Manifest < ActiveRecord::Base
belongs_to :assembly
belongs_to :part
end
class Part < ActiveRecord::Base
has_many :manifests
has_many :assemblies, through: :manifests
end
The simplest rule of thumb is that you should set up a has_many
:through relationship if you need to work with the relationship model
as an independent entity. If you don't need to do anything with the
relationship model, it may be simpler to set up a
has_and_belongs_to_many relationship (though you'll need to remember
to create the joining table in the database).
You should use has_many :through if you need validations, callbacks,
or extra attributes on the join model.
Let me highlight the most important sentence:
The simplest rule of thumb is that you should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don't need to do anything with the relationship model, it may be simpler to set up a has_and_belongs_to_many relationship
has and belongs to many is very simple to use, but you don't have direct access to related objects, you can only hold references to two models, and nothing else.
While has many through will enable you to do things like user.role and to get a list of all connected second model instances. It will also enable you to get access to data specific to the relation between first and second models.
It all depends if you need something quick and easy, like for a mockup or you want to build a long-term project. I recommend you to check this out for more details.
Related
All of the references I've found either show me how to do it upon table creation, or are for a much earlier version of rails. Ideally, I'd like like the foreign_key to be named 'author_id' in the questions table to distinguish it from other users who may be leaving comments or answers later.
class Question < ApplicationRecord
belongs_to :user
end
class User < ApplicationRecord
has_many :questions
end
You can create a new empty migration file in your terminal via rails generate migration RenameUserFkOnQuestion. Open it up and build your migration. This is a handy guide if you're not sure on the name of something.
def change
change_table :questions do |t|
t.rename :user_id, :author_id
end
end
Run the migration and head over to your models. You'll need to update your relationships like so:
class Question
belongs_to :author, class_name: 'User'
end
class User
has_many :questions, inverse_of: :author
end
Then you should be good to go.
I've got a table 'users' but one user might be a manager of another user, one user could also be a manager of many other users, so its a one-to-many relationship, and it only involes one table. heres my approach:
1.I've added 'manager_id'(which really stores another uners id) column to users table.
2.I've defined relationship in User model class:
belongs_to :manager, foreign_key: 'manager_id',class_name:'User'
has_many :minions, class_name:'User'
Now, say in rails console if i set one users 'manager_id' to another users id its all fine. but if i try to use methods like 'user.manager' or 'user.minions' it says those methods aren't defined. Were have i gone wrong?
I think you want to implement self inheritance that can be done as :
class User < ActiveRecord::Base
self.inheritance_column = :child_class
has_many :minions, :foreign_key => :parent_id, :as => :parent
belongs_to :parent, :polymorphic => true
end
This is just a sketch of what i understood from the above description, it can be enhanced.
In Ruby on Rails 4, I've these models:
def User < ActiveRecord::Base
has_one :company, dependent: :destroy
end
def Company < ActiveRecord::Base
belongs_to :user
end
So now, I want User as Employer to be able to have a company, and this Company can have many Users(Employees).
And when I log a User as Employee, I want to able to list all the companies he works.
What is the best way to do this?
I'm not sure I could give you a full working code file without some more information, but I think this is the best way to proceed.
class User < ActiveRecord::Base
self.table_name = "users"
#Define shared associations/methods
end
class Employee < User
has_and_belongs_to_many :companies
#Employee only associations/methods
end
class Employer < User
has_one :company
#Employer only associations/methods
end
class Company < ActiveRecord::Base
has_and_belongs_to_many :employees
belongs_to :employer
end
Since both inherit from the same User model, they will share a table. Since both derived models only use has_x, the foreign key will be in the other table, meaning they can share a table schema without a ton of null values.
Again I'm not sure this will work by itself, but I think it's a good start. Another advantage is that by segregating the code like this, you can independently change functions by the type of person (e.g. you could have a generic log function on user, but make it more specific on Employee and Employer - such as including the company or companies they are tied to).
I realized after the fact that there is another way of doing this. You can make User have a polymorphic association to either Employee or Employer. Then you would check the user record for which type it is, then pull the association and call the methods on that record (Employee or Employer).
The only thing I don't like about this solution is that it involves 3 tables and from what I've seen you can get by with 1.
I am really confused about the difference between class_name and source options of has_many.
For class_name, it is said on the API doc that:
Specify the class name of the association. Use it only if that name can’t be inferred from the association name. So has_many :products will by default be linked to the Product class, but if the real class name is SpecialProduct, you’ll have to specify it with this option.
And for source:
Specifies the source association name used by has_many :through queries. Only use it if the name cannot be inferred from the association. has_many :subscribers, through: :subscriptions will look for either :subscribers or :subscriber on Subscription, unless a :source is given.
It seems that these two options have the same function, that is, to specify the class name of the association, except that source is only used for has_many :through, and class_name can be set in every has_many association.
If so, why it is necessary for has_many to have these two options with the very similar functions? Why just use class_name only to specify all the association name?
I searched in many places but could not find the answer. I also read Rails: difference between :source => ?? and :class_name => ?? in models ,but it still does not explain why it is necessary for the existences of both class_name and source.
Thanks in advance.
The key point is class_name specify the class name of the association where source specifies the source association name.
Example:
lass User < ActiveRecord::Base
has_many :listing_managers
has_many :managed_listings, through: :listing_managers, source: :listing
end
class Listing < ActiveRecord::Base
has_many :listing_managers
has_many :managers, through: :listing_managers, source: :user
end
class ListingManager < ActiveRecord::Base
belongs_to :listing
belongs_to :user
end
On the above code example user is class_name. When we are declaring has_many :managers, through: :listing_managers then rails is expecting there is either manager or managers association with in ListingManager . Since we want to use user association for creating managers we have to tell it to rails that make managers association using ListingManager's user association.
Here is another example that use class_name option
class User < ActiveRecord::Base
has_many :listing_managers
has_many :listings, through: :listing_managers
end
class Listing < ActiveRecord::Base
has_many :listing_managers
has_many :managers, through: :listing_managers
end
class ListingManager < ActiveRecord::Base
belongs_to :listing
belongs_to :manager, class_name:"User"
end
On the above code we are declaring belongs_to :manager association on ListingManager but there is no model named manager that's why we have to set class_name option. Now, since we have manager association on
ListingManager we don't need to set source option on Listing that we had to do on first example.
Hope above will help someone.
I currently have application which allows users to upload an image.
Currently. each image belongs to a certain event, or in my case a certain week.
To reduce redundancy and server overload with the same image being uploaded multiple times, I would like to allow the user to upload (1) image and give them the option to assign it to multiple weeks that are load in the database.
Here is the setup now:
Creative Model
class Creative < ActiveRecord::Base
belongs_to :week
mount_uploader :image, CreativeUploader
end
Week Model
class Week < ActiveRecord::Base
has_many :creatives
end
The issue I am having is getting my application to pass multiple [week_id]'s to a single creative.
Should this be converted to a has_and_belongs_to_many relationship with a join table?
NestedForm
<%= creative_form.collection_select(:week_id, #campaign.weeks, :id, :start_at) %>
TIA
EDIT If it's a many-to-many relationship then your associations will look like this, and yes, you need a new join table.
Creative Model
class Creative < ActiveRecord::Base
has_and_belongs_to_many :week
mount_uploader :image, CreativeUploader
end
Week Model
class Week < ActiveRecord::Base
has_and_belongs_to_many :creatives
end