Creating has_one association within the same model - ruby-on-rails

Let us consider the below model.
User{ id:number(primary_key), column1:string, column2:string)
Now, the column1 can be any string, but column2 can be either null, or have values from column1. However column1 and column2 can't be same. I.E. column2 will be the foreign key and it will reference column1.
How will i create a has_one relationship with these constraints.
Something like,
has_one :master_agreement, :class_name => 'User', :foreign_key => 'column2', :primary_key => 'column1'
but the above mentioned doesn't work for me.

To setup a self-joining relationship in rails you want to use belongs_to not has_one as the key difference is that belongs_to places the foreign key column on the model's table - while has_one places it on the other end.
class User < ActiveRecord::Base
belongs_to :company # references users.company_id
has_one :company # references companies.user_id
end
Lets consider a system where you have a hierarchy of categories:
class Category < ActiveRecord::Base
belongs_to :parent, class_name: 'Category'
has_many :subcategories, class_name: 'Category', foreign_key: 'parent_id'
end
This creates a self joining relationship with the categories.parent_id foreign key column which references categories.id.
While you could potentially use something different than categories.id as the reference you are just making things harder on yourself as the id column already is an indexed primary key column.

Related

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

What is the difference between foreign_key and primary_key when defining an ActiveRecord association?

I am trying to understand the difference between foreign_key and primary_key when defining an association on an ActiveRecord model. Do you need to use both? What is the difference?
class SomeModel < ActiveRecord::Base
has_one :something_else, foreign_key: 'some_id', primary_key: 'some_id'
end
class SomethingElse < ActiveRecord::Base
self.primary_key = 'some_id'
belongs_to :some_model, foreign_key: 'some_id', primary_key: 'some_id'
end
primary_key defines the name of the database field to be used as primary key instead of the default id.
foreign_key defines the name of the database field which keeps references to the primary key field of another model.
See Active Record Associations docs for more.
If you want conceptual understanding on the role of primary and foreign keys, here is one writeup on this topic.
They are on the opposite sides of the association.
Rails takes value of foreign_key and searches model with class_name for records with primary_key of that value
For example:
class PhoneNumber < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_one :phone, foreign_key: :this_users_phone_id_field
has_many :others_with_this_number, ->(user){where.not(id: user.id)},
class_name:'User',
foreign_key: :this_users_phone_id_field,
primary_key: :this_users_phone_id_field
end
See more in rails docs

Model a fork relationship within ActiveRecord

What does the ActiveRecord::Migration and ActiveRecord::Base look like for a class that references itself. I'm modeling an object that "forks" off an existing record and stores that relation in a :source field. That :source field will contain the primary_key :id of it's parent.
ActiveRecord doesn't include a "predefined" relation of this type, but you can define it yourself using the has_many and belongs_to helpers. You would need to add a foreign key, e.g. my_parent_id to the model (I'll call it Thing):
rails g migration AddMyParentIdToThings my_parent:references
Then you would need to define the relation specifying the foreign key and class names:
class Thing < ActiveRecord::Base
belongs_to :parent_thing, class_name: "Thing", foreign_key: :my_parent_id
has_many :child_things, class_name: "Thing", foreign_key: :my_parent_id
end
You can omit the :foreign_key option on the belongs_to (not the has_many) if the foreign key matches the relation name with an appended "_id" e.g.:
belongs_to :my_parent, class_name: "Thing"
When I had to do something like that I like to think of it as a model that links to itself.
In your migration file you just would add parent_id as as integer to that table/model
class Category < ActiveRecord::Base
belongs_to :parent, :class_name => "Category", :foreign_key => :parent_id
has_many :children, :class_name => "Category", :foreign_key => :parent_id
end

Rails 3 : Specify inner join criteria "ON" in the rails way

I want to access the table "Words" from the "linked_to" column, and not from "id" column.
The INNER JOIN query created by Rails always search for the id column in the Words table.
This is what I want to do :
From the Class Point,
Do an inner join to "linked_to" column (I already specify the :foreign_key)
"Linked_to" is not unique in the "Words" table, because there is one line per translation
Filter (Select) in the Words table, the value corresponding to my current language (let's assume dictionnary = 1)
My current Model
class Word < ActiveRecord::Base
has_and_belongs_to_many :points, :foreign_key => "linked_to"
belongs_to :dictionnary
attr_accessible :lang, :value, :dictionnary_id, :language_id, :linked_to
end
class Point < ActiveRecord::Base
has_and_belongs_to_many :words, :association_foreign_key => "linked_to"
belongs_to :priority
attr_accessible :edited_by
end
It's called convention. :) You have created the wrong associations, beginning with your design.
The has_and_belongs_to_many creates a relation between two models, thus using their primary key. Rethink your models: the dictionary_id field does not belong to Words, but is a additional field for the intermediate table. When you 'qualify' the intermediate table, you cannot use HASB anymore. Use a normal intermediate table
WordPointsForDictionary:
belongs_to :word
belongs_to :point
belongs_to :dictionary
Word:
has_many :points, :through => :WordPointsForDictionary
has_many :wordpointsfordictionary
Point:
has_many :words, :through => :WordPointsForDictionary
has_many :wordpointsfordictionary
This way you have removed the repetition and ugly relationships from you models. Clean primary key relationships and that will help you on the long way very much.

For an ActiveRecord one-to-many association, which :foreign_key option should I set?

ActiveRecord's has_many and belongs_to methods both take a :foreign_key option. If I need to use it to handle a nonstandard FK column name, should I set it for the parent model (has_many), child model (belongs_to), or both, or does it matter?
You should set the :foreign_key option on both.
Consider the following two models:
class Article < ActiveRecord::Base
has_many :comments, :foreign_key => "articleID"
end
class Comment < ActiveRecord::Base
belongs_to :article, :foreign_key => "articleID"
end
Declaring has_many in the Article class allows you to do:
Article.find(12).comments # Finds all comments with comment.articleID == 12
The belongs_to method call in the Comment model allows for:
Comment.last.article # Finds article with article.id == comment.articleID
As you can see, in both cases the foreign key is used. If omitted in either location, that particular association proxy will not work properly.
belongs_to guesses the foreign key to be the association name plus _id.
has_one guesses the foreign key to be the name of the containing class plus _id.
Usually for a nonstandard key, you only need it in one place.
class Book < ActiveRecord::Base
# Rails default fk is isbn_id
belongs_to :isbn, :class_name => "BarCode", :foreign_key => "bar_code_id"
end
class BarCode < ActiveRecord::Base
# Rails default fk is bar_code_id, so you don't need to specify it
has_one :book
end

Resources