how to add one more connection to a model? - ruby-on-rails

For example, I have 2 models:
ticket.rb
belongs_to :user
user.rb
has_many :tickets, dependent: :destroy
In the table Tickets I have
t.integer "user_id"
This all works fine. But what if I wish to add a new field assignee_id, and that should be a user from the same table Users?
I can add just a field assigne_id and populate it with user_id I need, but I would like to use a construction like #ticket.assignee.name like I use for #ticket.user.name. Please could you help me?

You can do, Rails allows you to pass bunch of parameters to belongs_to. In your case, You need to specify the foreign key and the class name of the association.
This is how you can join assignee to user table
#ticket.rb
belongs_to :assignee, foreign_key: "assignee_id", class_name: "User"
source: edgeguides.rubyonrails.org
source: api.rubyonrails.org

Related

Using a has_one or belongs_to in a polymorphic association

I have an Business model and an polymorphic Address model.
Each business has one main address but I would like advise on if it is better to have business belong_to the polymorphic model or if it is better to say each business has_one address
belongs_to :main_location_address, class_name: "Address"
has_one :main_location_address, class_name: "Address", as: :addressable
I have tried both but belongs_to still requires a addressable attribute for the address.
Also how would this work with accepts_nested_attributes_for in the Business model and in the controller?
When representing relationships between entities it is important to reflect them in such a way that there is a logical resemblance to their real life counterparts.
It makes sense to say
Business has one address/main address
rather than saying Business belongs to an address.
If you want to enforce a database constrain that a business can only have one address, you can create a unique index.
Since it is a polymorphic relation, I'm assuming it will be used by other models as well. If you do not need to enforce uniqueness for all models, you could go for a partial index to create a unique index only where addressable_type is Business.
class AddIndexToAddress < ActiveRecord::Migration
def change
add_index :addresses, [:addressable_id, :addressable_type], unique: true, where: "addressable_type = 'Business'"
end
end
This will work if you only need strictly one address per business.
It is not clear from the question if you have an additional relationship to manage multiple addresses for a business as well. In that case you need opt for a belong_to relationship with business containing the main address id.
class Business < ApplicationRecord
belongs_to :main_address, class_name: 'Address', foreign_key: :address_id, optional: true
has_many :addresses, class_name: 'Address', as: :addressable
end
You can add validations as per your business requirements.
If you want to ensure that a buisness actually can only have one main address then you need to use a belongs_to assocation and create a foreign key column.
class AddMainLocationAddressToBuisnesses < ActiveRecord::Migration[7.0]
def change
add_reference :buisnesses, :main_location_address,
null: true,
foreign_key: { to_table: :addresses }
end
end
belongs_to :main_location_address, class_name: "Address", optional: true
Since the foreign key is stored on a column in the buisnesses table it can only have a single possible value per buisness.
has_one :main_location_address, class_name: "Address", as: :addressable
Will just fetch the first joined row off the addresses table. While you could monkey around and add addresses.main_location boolean column It provides no guarentee that there actually is just one main location address per addressable unless you for example write a custom constraint.
But then again if you're using a polymorphic assocation you have already tossed referential integrity out the window.

Rails association with multiple custom field names?

I have Members and Skills tables.
Each member record has 3 links to a skill: skill_primary, skill_secondary and skill_tertiary.
Each of those columns is just an ID that corresponds to a row in the Skills table.
What I want to be able to do is is reference a members given skill and get that record from the sills table.
So: member.skill_primary would return the actual Skill record.
What type of associations would I set up to pull that off?
To do this you need to declare 3 belongs_to associations and use the :class_name and :foreign_key options.
class Member < ActiveRecord::Base
belongs_to :skill_primary, class_name: 'Skill', foreign_key: :skill_primary
belongs_to :skill_secondary, class_name: 'Skill', foreign_key: :skill_secondary
belongs_to :skill_tertiary, class_name: 'Skill', foreign_key: :skill_tertiary
end
For documentation on these options, see section 4.1.2 of the Rails Guide for Active Record Associations: http://guides.rubyonrails.org/association_basics.html#belongs-to-association-reference

Understanding use of foreign_key and class_name in association

I am new to rails and this is a very basic question. I am trying to understand the need of foreign key and class_name.
has_many :task, foreign_key: "created_by"
has_many :memberships, class_name: "TaskMembership"
Can anyone explain the need of foreign_key & class_name.
Here is the answer of my question
Suppose you have a User model and Post model.And you have to set an association like User has many post
User Model
has_many :posts
Post Model
belongs_to :user
Now suppose your user is some author so we have to set some meaningful name so instead of user we will use author but have to specify which class it is referring
Post Model
belongs_to :author, class_name: 'User'
Now problem will occur because rails will look for author_id column in posts table .So here foreign key will come into picture.We will have to find user_id
Post Model
belongs_to :author, class_name: 'User', foreign_key: 'user_id'
See more better explanation association
has_many association is used for for one-to-many type relationships in rails. For instance, if you have a model User which can has many profiles, your User to Profile association will be has many.
class User < ActiveRecord::Base
has_many :profiles
end
class Profile < ActiveRecord::Base
belongs_to :user
end
If you have a foreign key different than user_id in profiles table, you explicitly specify foreign_key. Same is the case with class name. If your association name is different than actual model name, you explicitly specify class name after association (as you did for memberships).
Hope it helps.
in your model
class First < ActiveRecord::Base
has_many :seconds
end
class Second < ActiveRecord::Base
belongs_to :first
end
and in your second class table,create first_id column

Having different associations between two models Rails

I am building an event app that lets users post events, and other users can 'register' themselves as attending that event. I currently have two models, 'User' and 'Article', where article is the event that a user can post. An article belongs_to :user and a user has_many :articles, dependent: :destroy.
I am trying to set up a new database to store which users plan to attend an event, in the form of a 'Registration', where it stores a user and the event he plans to attend. This means i need a many to many association between Users and Articles (as a user can attend multiple events, and an event can have multiple attendees). But will this not conflict with the original setting that states an article belongs to a single user?
How do i set this up so my associations dont interfere?
You could try either a has_many through: or a has_and_belongs_to_many relationship. Personally, I think I would use a HABTM for this, but the advantage of a HM Through is that there is an intermediate model, which can be used for additional information (such as whether an "attendee" is going or merely interested, etc): http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
As for having multiple different associations between the same two models, you can name the association anything you like but specify the class_name of the model you are pointing to: http://guides.rubyonrails.org/association_basics.html#has-and-belongs-to-many-association-reference
For example:
class Article < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :attendees, class_name: "User", join_table: "articles_attendees", foreign_key: "attended_event_id", association_foreign_key: "attendee_id"
...
end
And for your User model:
class User < ActiveRecord::Base
has_many :articles
has_and_belongs_to_many :attended_events, class_name: "Article", join_table: "articles_attendees", foreign_key: "attendee_id", association_foreign_key: "attended_event_id"
...
end
That way you're able to name your association whatever you like, just be sure to keep your singulars singular and your plurals plural, and generally everything readable. class_name should be the name of the model to which you are defining the relationship. foreign_key is the database column name containing the ID of the models in which the relationship is defined. For example, in your User model, foreign_key should be the user ID. The association_foreign_key is the column containing the ID of the model to which you are linking.
Also don't forget to create your migration. Something like this example:
class CreateArticlesAttendees < ActiveRecord::Migration
def self.up
create_table :articles_attendees, :id => false do |t|
t.references :attended_event
t.references :attendee
end
add_index :articles_attendees, [:attended_event_id, :attendee_id]
add_index :articles_attendees, :attendee_id
end
def self.down
drop_table :articles_attendees
end
end

What inverse_of does mean in mongoid?

What inverse_of does mean in mongoid associations? What I can get by using it instead of just association without it?
In a simple relation, two models can only be related in a single way, and the name of the relation is automatically the name of the model it is related to. This is fine in most cases, but isn't always enough.
inverse_of allows you to specify the relation you are referring to. This is helpful in cases where you want to use custom names for your relations. For example:
class User
include Mongoid::Document
has_many :requests, class_name: "Request", inverse_of: :requester
has_many :assignments, class_name: "Request", inverse_of: :worker
end
class Request
include Mongoid::Document
belongs_to :requester, class_name: "User", inverse_of: :requests
belongs_to :worker, class_name: "User", inverse_of: :assignments
end
In this example, users can both request and be assigned to tickets. In order to represent these two distinct relationships, we need to define two relations to the same model but with different names. Using inverse_of lets Mongoid know that "requests" goes with "requester" and "assignments" goes with "worker." The advantage here is twofold, we get to use meaningful names for our relation, and we can have two models related in multiple ways. Check out the Mongoid Relations documentation for more detailed information.

Resources