I've looked everywhere, and can't find anything (maybe cause it's not possible)
I have a Meeting model and a Language model (which has a string column called language). Each Meeting has 2 Languages.
Is there a way to make an association, such as:
rails g migration AddLanguageToMeetings language:references
And then store an array of 2 language_ids in the reference?
For example, Meeting.language_id = [1,2]
And then be able to call the Language, like:
meeting.language_id[0].language
How can I se up this association? Do I need to have 2 different columns with each associated id?
Thanks!!
What you want is a N-to-N relation. Create another model called MeetingLanguage with two columns:
create_table :meeting_languages do |t|
t.references :meetings
t.references :languages
end
and associations:
class MeetingLanugage < ActiveRecord::Base
belongs_to :language
belongs_to :meeting
end
And then in Meeting module:
has_many :meeting_languages
has_many :languages, through: :meeting_languages, source: :language
Now you can have as many languages as you want for a single meeting.
What you're describing is a has_many, where the foreign key exists in the languages table, or in a joining table between the languages and meetings tables.
If you want each Meeting to point two exactly two Languages, then you can use two foreign keys in the meetings table, give each language a real name, and then have two belongs_to associations in your Meeting.
Related
I am working on a rails app, with different tables and associations, and trying to find out the best solution for that, don't know yet.
One table/class is called categories
For example
Categories
- Stocks
- Reits
-(...)
One table for each category
Stocks
belongs_to :category
Reits
belongs_to :category
Than i want to create a table called "Dividends", with a condition, don't know if is possible, for example:
Dividends
belongs_to :category
if category_id == 1
belongs_to :stock
end
if category_id == 2
belongs_to :reit
end
With the command:
rails g scaffold dividends category:references stock:references reit:references
But i don't know if it would be confusing, an if maybe would be better create a table for each class, for example:
StocksDividends
belongs_to :category
belongs_to :stock
ReitsDividends
belongs_to :category
belongs_to :reit
Would like some help on thinking about that solution.
just a quick hint - take a look at polymorphic associations:
https://guides.rubyonrails.org/association_basics.html#polymorphic-associations
The mechanics of it put a foreign key in the dividends table along with a type column. The type column tells you what type of record is the parent - the stock or the reit.
For example I have model Match and model Player. What I want is for Player to be able to participate in many matches.
So it should look smth like this:
#match_first = Match.first
#match_last = Match.last
#match_first.players
#player1, player3, player4
#match_last.players
#player1, player4, player5
Both matches can have same players simultanously.
In your Match model:
has_many: :players, through: :appearances
In your Player model:
has_many: :matches, through: :appearances
class Appearance < ActiveRecord::Base
belongs_to :match
belongs_to :player
You could have extra attributes on appearance like 'goals_scored'. The through model doesn't have to be called Appearance... it could be Attendance or MatchPlayer or PlayerMatch, but you can see that the last two names are constraining, because out of this association you can also see all the matches a player appeared in.
Rails provides two ways to accomplish the many-to-many relationship. The first, which #zoot's answer describes, is has_many :through. This is a great option if the relationship is a Model in its own right (i.e., needs additional attributes or validations).
If the relationship between the two entities is direct such that you don't really need a third model, you can use the has_and_belongs_to_many association.
In your Match model:
has_and_belongs_to_many :players
In your Player model:
has_and_belongs_to_many :matches
When you use has_and_belongs_to_many you do need to create a join table that holds the relationship. The migration for that (assuming a relatively recent version of Rails) might look like:
class CreateJoinTableMatchesPlayers < ActiveRecord::Migration
def change
create_join_table :matches_players, :users do |t|
t.index [:match_id, :player_id], unique: true
end
end
end
There's a section in the Active Record Associations guide that talks about how to choose between the two approaches.
Let's say, on a rails app (with postgresql), I have this database with a polymorphic association between work_steps and sub_assemblies / parts:
Part.rb
belongs_to :sub_assembly, optional: true
has_many :work_steps, as: :component
belongs_to :site
belongs_to :car
Sub_assembly.rb
has_many :work_steps, as: :component
has_many :parts
work_step.rb
belongs_to :component, polymorphic: true
Now, I want to query my database: I want a list of all the work_steps filtered with a specific array of sites and a specific array of cars.
For instance, all the work_steps linked to parts that belongs to Site A and Car X & Z.
Because of the polymorphic association with the sub_assemblies and this same table which is linked to parts table, I cannot figure out how to do it.
At the end, I need an ActiveRecord Relation. How would you do it simply? I tried a lot of things but without success.
Any one to help me?
Thank you in advance.
Okay, so work_step is what you want to be able to be used by multiple models.
So inside the migration for CreateWorkSteps:
t.references :component, polymorphic: true
This basically does
t.integer :component_id # Refers to id (of sub-assembly or part)
t.string :component_type # Refers to type of object (sub-assembly or part)
add_index :work_steps, [:component_type, component_id]
Now in your model:
work_step.rb
belongs_to :component, polymorphic: true
sub_assembly.rb
has_many :work_steps, as: :component
has_many :parts
part.rb
has_many :work_steps, as: :component
belongs_to :site
belongs_to :car
belongs_to :sub_assembly, optional: true
Okay, so you wish to query your database and obtain
work_steps
linked to parts
belongs to site A and Car X and Z
So, here the list of steps you should do in ActiveRecord (I'm not going to give a single-query answer as that's too much effort. Also, the step order is in logical order, but remember that ActiveRecord queries use lazy evaluation and SQL queries are evaluated in a certain order.)
#Join parts w/ site and cars
Use #Where siteName is in [A], carName is in [X, Z]
Now, you LEFT join with sub_assembly (So even if the part has no sub_assembly_id, it isn't removed).
Now this is the annoying step. For your first join, you'll want to join parts_id with component_id AND component_type == "Part" (Remember to prefix your tables when joining, e.g work_steps.component_id and do this from the beginning.)
For your second join, you'll want to join sub_assembly_id with component_id AND component_type == "Sub_assembly"
Now you have a HUGE ActiveRecord object, select only what makes a work_step.
Good luck! I won't hold your hand with a pre-written answer, through...because I'm too lazy to boot into Rails, make migrations, make models, seed the models, then write the query myself. ;)
Oh ya, and I ended up giving a single query answer anyway.
I'm trying to do a has_many relation with a table on creation and also to add it in another table already created.
I have my User table already with no relations.
I want to create a Pro_user with a relation has_many User.
The thing is that one User can have multiple Pro_user and a Pro_user can also also have multiple User.
So both tables need a has_many right ?
So what I thought of was that
rails g model pro_user name:string email:string password_digest:string user:references
But this is not the right thing, it's doing a belongs_to from Pro_user to User
And also how should I do to do add the has_many on my existing table User ? Do I have to do a migration to recreate the table and adding the relation ?
Thanks for your help !
The recommended approach for a many to many association is the "has_many_through" approach. This allows you to add additional columns later on to the join table if you need more data. You'll need a join table that will at the least have two reference columns to your Users and ProUsers tables along with the standard id column.
(Refer to: http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association)
So your User and ProUser tables will not have any reference columns in them. Instead you'll make a third table called BoatsAndPros (call it whatever you like) and do:
create_table :boats_and_pros do |t|
t.belongs_to :user, index: true
t.belongs_to :pro_user, index: true
t.timestamps
end
Then in the corresponding boats_and_pros.rb Model file you'll add:
belongs_to :user
belongs_to :pro_user
In your user.rb file you'll add:
has_many :boats_and_pros
has_many :pro_users, through: :boats_and_pros
In your pro_user.rb model file you'll add
has_many :boats_and_pros
has_many :users, through: :boats_and_pros
Two key takeaways are:
The "oldschool" has_and_belongs_to_many approach is still fine however doesn't allow room to grow like the has_many_through approach here and you'll need to specifically name the table pro_users_users because Rails expects the two tables to be listed in lexical order.
One-to-many relationships like what you ended up with on your original attempt keep the reference in one of the tables while many-to-many relationships require a third join table as shown above.
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