How to create an association that automatically sets the attributes of a join table?

I am completely confused about how I should “efficiently use rails” using my associations.

Here is an example model configuration from a Rails 4 application:

class Film < ActiveRecord::Base # A movie, documentary, animated short, etc has_many :roleships has_many :participants, :through => :roleships has_many :roles, :through => :roleships # has_many :writers........ ? end class Participant < ActiveRecord::Base # A human involved in making a movie has_many :roleships end class Role < ActiveRecord::Base # A person role in a film. ie "Writer", "Actor", "Extra" etc has_many :roleships end class Roleship < ActiveRecord::Base # The join for connecting different people # to the different roles they have had in # different films belongs_to :participant belongs_to :film belongs_to :role end 

Given the configuration of the model above, the code I would like to allow me to add authors directly to the movie and, ultimately, configure the connection correctly.

So, for example, I would like to do something like this:

 ## The Code I WISH I Had Film.create!(name: "Some film", writers: [Participant.first]) 

I'm not sure if I will think about it completely wrong, but it seems impossible. What is the right way to do this? Invested resources? Custom Setter + Area? Something other? Virtual attributes? thanks!

+4
source share
2 answers

I created an example application based on your question. https://github.com/szines/hodor_filmdb

I think it’s useful to configure the “Member” and the “Role Model” through the association, but it will work without it. It depends on how you want to use this database later. Without this request will not work: Participant.find(1).films

 class Participant < ActiveRecord::Base has_many :roleships has_many :films, through: :roleships end class Role < ActiveRecord::Base has_many :roleships has_many :films, through: :roleships end 

Remember to give permission for additional fields (strong_parameters) in your film_controller.rb

 def film_params params.require(:film).permit(:title, :participant_ids, :role_ids) end 

What is strange is that if you create a new movie with a participant and a role, two entries will be created in the connection table.

I hope for this help, and someone can help us improve further ... if you have any questions, just let me know.

Update:

You can create some kind of virtual attribute in your model. For instance:

 def writers=(participant) @writer_role = Role.find(1) self.roles << @writer_role self.participants << participant end 

and you can use: Film.create(title: 'The Movie', writers: [Participant.first])

+3
source

If you have a normal connection with has_and_belongs_to_many , for example, with a movie and a participant, you can create a movie along with your examples.

As your joining model is more complex, you need to create separate roles separately:

 writer= Roleship.create( participant: Participant.find_by_name('Spielberg'), role: Role.find_by_name('Director') ) main_actor= Roleship.create( participant: Participant.find_by_name('Willis'), role: Role.find_by_name('Actor') ) Film.create!(name: "Some film", roleships: [writer, main_actor]) 

To do this, all the attributes that you use to create roles and films must be assigned by the masses, so in Rails 3.2 you will need to write:

 class Roleship < ActiveRecord::Base attr_accessible :participant, :role ... end class Film < ActiveRecord::Base attr_accessible :name, :roleships ... end 

If you want to use the role__id role, you must write

 class Film < ActiveRecord::Base attr_accessible :name, :roleship_ids ... end 

Application:

Because of this, you can write the setter method

 class Film ... def writers=(part_ids) writer_role=Role.find_by_name('Writer') # skiped code to delete existing writers part_ids.each do |part_id| self.roleships << Roleship.new(role: writer_role, participant_id: part_id) end end end 

but this makes your code dependent on the data in your database (the contents of the roles table), which is a bad idea.

0
source

Source: https://habr.com/ru/post/1485898/


All Articles