How I model Many to many associations with checkbox collection in Rails
First of all, why do we need Active Record Relations and associations? Because associations make common operations simpler, faster and will save you a lot of time. It will also lead to better results for the end user. Associations extend your Rails-objects with methods that can be accessed anywhere to list, select or filter related objects with less code. Your code will also be dryer and easier to read.
Once you’ve seen the benefits, you’ll be glad you spent the time learning it. And once you’ve nailed it for one project, the next time will be easy as brewing your morning coffee. Features like these are the main advantages of Rails in the first place, so make sure you don’t miss it.
In this example I will be using a Band-model and a Tag-model. A Band has zero, one or many tags, and the same with tags and related bands. As for the final result, we will be able to display a list bands with all it’s corresponding tags, and list all bands that’s tagged with respect to a certain tag.
To complete the use case, I will make a simple user interface with checkboxes (Checkbox collection-helper) to do our band-tagging.
I assume you’ve already got the following up and running:
•The band model
•The tag model
Appropriate controllers and views for the two
The key here is to create a third model, that will serve as a bridge between the two main models. It will function as storage for what’s called a JOIN clause between the band and tag model. A JOIN clause is used to combine rows from two or more tables, based on a related column between them. It’s a classic in SQL terms. You can name this bridging model whatever, but I prefer to use the names of the two models that it will serve.
Lets start by creating the BandTag model
rails generate model BandTag
This will generate som stuff including a file called something like
db/migrate/20171121194425_create_band_tags.rb
To create the appropriate new column for our model from this file, simply run
bundle exec rake db:migrate
Now I need to create a migration for the two rows that will link the actual band to tag. Depending on the Rails version there are shortcuts for this operation, but I like to write it manually as a seperate migration:
rails generate migration AddReferencesToBandTags
This will create a new migration file in the db/migrations folder that we will change to
class AddReferencesToBandTags < ActiveRecord::Migration
def change
add_reference :band_tags, :band, index: true, foreign_key: true
add_reference :band_tags, :tag, index: true, foreign_key: true
end
end
Then I’ll add the relation connection in my two initial models, starting with band.rb:
class Band < ActiveRecord::Base
has_many :band_tags
has_many :tags, :through => :band_tags
end
…and also to the Tag model, file tab.rb:
class Tag < ActiveRecord::Base
has_many :band_tags
has_many :bands, :through => :band_tags
end
Finally, we add the belongs_to attribute to the bridging model, band_tag.rb:
class BandTag < ActiveRecord::Base
belongs_to :tag
belongs_to :band
end
hello
hello
hello
Let’s continue later with the views and checkboxes… Stay tuned!
Test to see if incremental builds are working now.