ActiveRecord two way foreign key. - ruby-on-rails

I'm using some open gov data in MYSQL which I've imported into my rails App.
I've extended the database with some of my own tables, and use the rails provided column ids in my tables.
However, the tables of the original database are linked through a unique 'ndb' id.
I thought that by cross-referencing two :foreign_key=>'ndb' between the models I would get the tables linked properly, but through :foreign_key, it appears to be linking the id from one table to the ndb column of another.
My models look like this
class Food < ActiveRecord::Base
has_many :weights, :foreign_key=>'ndb'
has_many :food_names
end
class Weight < ActiveRecord::Base
belongs_to :food, :foreign_key=>'ndb'
Is there a way to specify that the 'ndb' column is the link between the food and weights table, and not the food_id to ndb?

Have you tried set_primary_key 'ndb' in your AR classes?
set_primary_key docs.

What I've done as a possibly temporary solution, is to used the :finder_sql to link the tables together.
My Food model now has:
class Food < ActiveRecord::Base
has_many :weights, :finder_sql =>'Select weights.* FROM weights LEFT JOIN foods ON foods.ndb=weights.ndb WHERE foods.id=#{id}'
I'm not sure if this is the best solution or not, but it seems to be working.

Related

Many-to-Many: Simple vs Rich in Rails

I have a question about these two relationships as I think I'm overthinking it and have confused myself quite a bit.
So they both involve a new table that sits in between the two tables you want to join.
A simple M2M gets the foreign keys from the other two tables (so example would be "blog_posts_categories" table would get the blog_post_id and the category_id foreign keys). Then for the associations, the blog_post and category models would have has_and_belongs_to_many associations with each other but the joined table gets no model.
for a rich M2M, a third joined table is created. This table gets the foreign key from the other two tables, and those two tables get the foreign key of the joined table. Then for the rails association, the joined DOES get a model, and it belongs_to the other two corresponding models. And those two models has_many of the joined table model
Am I anywhere near close to being right? I think my issue is that I keep conflating the table with the model or at least for the simple many-to-many since I keep expecting there should be a model to go along with the table.
Thanks for any direction that can be given.
Your conceptual understanding of the two are almost there. Rather than thinking of them as simple vs. rich, I prefer to think of them as implicit vs. explicit.
Take for example, two models, Book and Author.
With a has_and_belongs_to_many, Rails will implicitly create a join table between your two models. I.e. books_authors.
You can also explicitly create the join table, say, Authorship, that belongs_to both. (Book and Author will then have has_many :authorships.)
In both cases, your domain model will look the same:
Book (1)--(n) Authorship (n)--(1) Author
Now, here is the opninionated part. I prefer to use the explicit approach, as this is easier to grasp, conceptually, and makes it easier to add additional fields to your join table. Say that for example you want the Authorship to be ordered, you can easily add an order column to your Authorship model and use that accordingly.
A third relationship table is suitable for many-to-many relations. You can do something like this:
class BlogPost < ActiveRecord::Base
has_many :blog_post_categories
has_many :categories, through: :blog_post_categories
end
class Category < ActiveRecord::Base
has_many :blog_post_categories
has_many :blog_posts, through: :blog_post_categories
end
class BlogPostCategory < ActiveRecord::Base
belongs_to :blog_post
belongs_to :category
end
The third model is very simple and its overhead is basically negligible. Also it is flexible and extensive if you want to attach more information to that relationship (for example, priority or timestamp). I personally prefer having a standalone table for relationships rather than a few more columns in the blog_posts table.
Here is a relevant blog post: Why You Don’t Need Has_and_belongs_to_many Relationships.
Perhaps you can explain the tradeoffs you're considering here?

How do I add items to join tables in Rails? Do they get their own models?

I have two models: Reader and Magazine. I obviously want to have a join table, readers_magazines, to represent which magazines each reader is subscribed to.
So I create my Reader model (with fields like name, address and age) and my Magazine model (with fields like Title and Active?). In each model I write has_and_belongs_to_many of the other.
Then I write a migration, CreateReadersMagazinesJoin, and write:
create_join_table :readers, :magazines do |t|
t.index 'reader_id'
t.index 'magazine_id'
end
And migrate the database. All good.
My question is... what now? Do I create a model for the join table? That seems wrong, and yet I do need some model validations (I don't want to represent the same User-Subscription combo twice). So do I write a model for it and manually specify the database table to use?
What is the correct procedure in this situation?
From the rails guides:
A has_and_belongs_to_many association creates a direct many-to-many
connection with another model, with no intervening model.
That means that using a has_and_belongs_to_many association might be easier for you to setup (because there is no middle model) but you don't have any kind of control over the join table, validations, etc. HABTM are normally considered harmful and you would want to use a has_many :through relationship instead, that is the same but having a model to represent the join table, so you have control over everything.
More information here.
Do I create a model for the join table? That seems wrong, and yet I do need some model validations.
If you don't want to add an additional fields to the join table, you don't really need to create the model for it.
And in most cases the validation that are required by yours, can be applied to one or both the tables.
I don't want to represent the same User-Subscription combo twice.
What do you mean twice, I havent seen the cases for that, however since the User-Subscription is something external the for the join table, you can explain more crear.
Where you have the choice between a habtm relationship or separate model, I would consider whether you need a rich amount of data in the join. In the present case, I think you do need extra data in the join. For example, a subscription would have a start date and an end date. It may also have a billing date and billing amount. You would not normally populate this information in a join table but rather in a stand alone model.
I would call the join table subscriptions and thus create a model Subscription. Then you can do it like this:
class Reader < ActiveRecord::Base
has_many :subscriptions
has_many :magazines, through: :subscriptions
end
class Subscription < ActiveRecord::Base
beongs_to :reader
belongs_to :magazine
end
class Magazine < ActiveRecord::Base
has_many :subscriptions
has_many :readers, through: :subscriptions
end

Rails relationship based on common field

I've found quite a few topics on ActiveRecord has_many relationships, but I haven't found exactly what I am looking for.
I've got two tables that each have the column xyz_id. This id is a corresponding ID in an API service I'm subscribed to.
I want to have a has_many relationship through these corresponding ids in the corresponding columns on each table. Such that, if an item in table_1 has an xyz_id of "abcdefg", I can do something like table_1.relation and it will return all elements in table_2 with a matching xyz_id. I could leverage ActiveRecord throughout my code and utilize queries, but I think there has to be a better way. Any thoughts?
EDIT: I a word.
ActiveRecord lets you specify arbitrary fkeys when you define the relationship, like so:
class Assembly < ActiveRecord::Base
has_and_belongs_to_many :parts,
foreign_key: :xyz_id
end
class Part < ActiveRecord::Base
has_and_belongs_to_many :assemblies,
foreign_key: :xyz_id
end
Source: http://guides.rubyonrails.org/association_basics.html

has_and_belongs_to_many where both models have underscore names

I'm working with Rails 3.2.1 and have the two models CookingVenue and DiningVenue with associated MySQL tables of cooking_venues and dining_venues. I have set up the has and belongs to many relationship between the two models but what's the name of the MySQL table name here to represent the join?
Is it cooking_venues_dining_venues?
Will Rails try to find habtm relationships between cooking and venues etc, or is Rails really clever enough to work all this out?
Like you said, cooking_venues_dining_venues is the name of the join table. After creating this table with cooking_venue_id and dining_venue_id field you need to define has_and_belongs_to_many association in both model.
class CookingVenue < ActiveRecord::Base
has_and_belongs_to_many :dining_venues # foreign keys in the join table
end
class DiningVenue < ActiveRecord::Base
has_and_belongs_to_many :cooking_venues # foreign keys in the join table
end
Yup. You just name the join table in alpha order like you have done and you should be good to go.

rails model relationship and migration

I have some problem trying to understand when building a rails app with several models and relation ships between them...
If I take a basic example like a model Group, a model User and a model Car
class Group < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
belongs_to :group
has_many :cars
end
class Car < ActiveRecord::Base
belongs_to :user
end
Will those relation ship statements automatically create the following functions:
group.users
user.group
user.cars
car.user
It seems that we sometimes need to have to create "references" in migration (like adding a reference toward User in Car table) but is this always required ?
In this case, what is the difference of creating the migration and of adding the relationship statement in the models ? I sometimes have the feeling this is used for the same purpose.
Thanks a lot for your help,
Regards,
Luc
The association declarations are there for Rails only. You have to define the foreign keys (references) in the database, so that Rails can properly save the data.
Remember, despite all the magic, it's still backed by a relational database, so good practices there will pay off in the long run.

Resources