Activerecord relation with custom keys - ruby-on-rails

_categoriesI'm trying to re-create some legacy database relation using Activerecord. I'm an Activerecord newbie, by the way I solved every problem until now except for some association where the key is not the ID.
I have two tables:
Product
id
model
name
type
DataCategory
id
name
tree
The association here is driven by "type" and "tree": how can I create this association with ActiveRecord?
I try with:
has_many :data_categories, foreign_key: 'type', primary_key: 'tree'
but it doesn't work

I think you need inverse foreign_key and primary_key like this:
has_many :data_categories, foreign_key: 'tree', primary_key: 'type'
Hope it helps

What is stored in 'type' and 'tree'? The foreign key is the database field on DataCategory that holds the unique id of the Product. The primary key is the database field on Product that holds that unique id. By default, they would be product_id and id respectively. In your case, assuming 'tree' holds the product id, it would be
has_many :data_categories, foreign_key: 'tree'
It's not necessary to specify the primary key because you appear to be using the default of 'id'

Related

Foreign key that doesn't point to a primary key in rails and postgres?

I'm using Rails with a legacy postgres database, meaning no migrations. The schema is defined separately.
I have two tables: notification and notification_type. The notification_type table has an ID (primary key) and a code column. The notification table has a notitification_type column with a foreign key on the notificiation_type table's code column.
class Notification < ActiveRecord::Base
...
belongs_to :notification_type, foreign_key: 'notification_type'
...
NotificationType:
class NotificationType < ActiveRecord::Base
has_many :notifications
end
When I call create on the notification model, it gives me a foreign key error because it's trying to create with the ID column of notification_type, not the code column.
ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR: insert or update on table "notification" violates foreign key constraint "notification_notification_type_fkey"
DETAIL: Key (notification_type)=(18) is not present in table "notification_type".
Where 18 is the ID, but I need it to use the code, which would be something like 1 or 2. I saw the association_foreign_key value, but it seems that it only works with the has_and_belongs_to_many association.
psql, just for closure:
Foreign-key constraints:
"notification_notification_type_fkey" FOREIGN KEY (notification_type) REFERENCES notification_type(code)
Basically, how do I get rails to honor the foreign key relationships in my database instead of always using the primary key?
Just do:
belongs_to :notification_type, foreign_key: 'notification_type', primary_key: 'code'
The primary_key defaults to id but you can use anything you want.
You'll want to specify the same options for your has_many :notifications association - the has_many is completely unaware of it's associated belongs_to, so it needs to know if you're using non-standard keys as well.

Custom includes association in rails

I have the following table
Users(user_id, name, last_name)
Relationships(user_id, spouse_id)
I want to run the following query
person = Relationships.includes(:person).where(:name => 'David')
But I don't want the related person to be associated by the user_id. I would rather it be associated by the spouse_id only for this specific query.
Rails is perfectly content to allow multiple associations to the same table, providing they use a different foreign key.
In this case, you'd have something like this:
class User
has_many :relationships
has_many :spouses, class_name: "Relationship", foreign_key: :spouse_id
end
User.first.spouses would then be a collection of all relationships where the user's id was present in the spouse_id field.

Rails association primary_key option

I understand that foreign keys are for specifying when you have a different column name (different than parent child's class name) on the child class. I know what primary keys and foreign keys are and have read the rails documentation on associations several times, but I can't figure out what the primary key option is for.
1) But what is the primary_key option for? How does it change the sql when an association is called?
2) In what instances would you need to specify the primary_key on association?
3) In what instances would you need to specify both the primary_key and foreign_key?
below is an example of specifying the foreign_key option on associations:
class User
has_many :texts, foreign_key: :owner_id
end
class Text
belongs_to :user, foreign_key: :owner_id
end
User Table
id| name |
Text Table
id| owner_id |name
Ok so I thought more about the SQL and figured it out. You use foreign_key option when your child has a different foreign_key name then your parent's classname_id BUT on your parent table, you are still using ID as your identifier.
user table
id|name|age
text table
id|random_id|conversations
select * from user where user.id = text.random_id
select * from text where text.random_id (foreign_key) = account.id (primary key)
On the other hand, you use primary_key with foreign_key when you don't want to use id at all to link the relationship.
user table
id|userable_id|name|age
text table
id|userable_ss_id|conversations
HERE: if you wanted to link the userable_ss_id to userable_id, you would include both primary_key and foreign_key options on both relationships.
class User
has_many :texts, primary_key: :userable_ss_id, foreign_key: :userable_id
end
class Text
belongs_to :user, primary_key: :userable_ss_id, foreign_key: :userable_id
end
Basic rule of thumb:
select * from text where text.(foreign_key) = account.(primary key)
primary key concerns the main table and foreign key the associated one
U 've used the foreign key correctly. If for isntance User had another primary key than :id u'd have to specify that either.
#User
has_many :texts, primary_key: :uuid, foreign_key: owner_id
So you need this options, if you want to have another naming of the keys than rails conventions assume for the main and associated table respectivly
Rails uses convention over configuration.
By convention, all database tables in rails have a primary-key of the id column.
If, for some odd reason (eg you've got a legacy database), your table uses a different primary key to id... you use the primary_key call to tell rails what it is.
By convention, all associations use a foreign-key of <model>_id for the foreign key.
If, for some reason, your association uses a different foreign-key to find the associated model - you'd use foreign_key to tell rails what it is.
Unlike primary_key, using foreign_key can be much more common. Especially when you have more than one association using the same table but with different association names.

Rails foreign key other than id

I have an ActiveRecord named Ad, and it has column id and server_id. They are both unique. id is given by Rails, but what's meaningful here is server_id.
Then I need to create another ActiveRecord named Bid which has 1 to 1 relationship with Ad. Bid has a key ad_id which refers to Ad.server_id.
I know that I should specify Ad has_one Bid and Bid belongs_to Ad, and specify foreign key name through foreign_key: "ad_id". What's troubling me here is I can only find out how to let Bid.ad_id refer to Ad.id while I want it refers to Ad.server_id.
Can anybody show me how to achieve this? Thanks!
User primary key
Bid.rb
belongs_to :ad, :foreign_key => :ad_id, :primary_key => :server_id
Ad.rb
has_one :bid, :foreign_key => :ad_id, :primary_key => :server_id
foregin_key option is not needed here but adding to make the difference between it and primary_key clear.
Have you tried using 'references' when generating your model.
i.e.
rails generate model Advertisement bid:references

conflict between attribute name and foreign key name

I am wondering if it is possible to have the following situation: I have a person object that has both an attribute called email and a foreign key called email which is realized as a has_many relationship. The latter is supposed to contain not only the primary email but also secondary ones. Would this cause conflict when I invoke #person.email? What would be the standard way to work around this? Thanks.
Create a secound field that could be used as a foreign key and then in the associated model add :foreign_key => 'your_foreign_key' as aparameter to the existing association like this:
has_many :email_addresses, :class_name => 'ClassName', :foreign_key => 'your_foreign_key'
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html <-- Documentation about that.

Resources