Clear ORM
Search…
has_many through
Has many through represents a relation where both side can relate to multiple models.
Basically, in SQL this can be performed by using a middle-table which store foreign key of both of the classes.

Usage Example

For example, let's assume we have a table posts and a table tags which are loosely connected: a post can have multiple tags at once, while a tag can references multiple posts. In this example, we will need a middle-table which will be named post_tags :
1
CREATE TABLE tags (
2
id bigserial NOT NULL PRIMARY KEY,
3
name text NOT NULL
4
);
5
6
CREATE UNIQUE INDEX tags_name ON tags (name);
7
8
CREATE TABLE posts (
9
id bigserial NOT NULL PRIMARY KEY,
10
name text NOT NULL,
11
content text
12
);
13
14
CREATE TABLE post_tags (
15
tag_id bigint NOT NULL,
16
post_id bigint NOT NULL,
17
FOREIGN KEY (tag_id) REFERENCES tags (id) ON DELETE CASCADE,
18
FOREIGN KEY (post_id) REFERENCES posts (id) ON DELETE CASCADE
19
);
Copied!
You may notice usage of FOREIGN KEY constraints over post_tags. Clear doesn't provide any feature for cascading deletion, and relay exclusively on PostgreSQL.
Now, let's define our models:
1
class Post
2
include Clear::Model
3
4
primary_key
5
6
column name : String
7
column content : String?
8
9
has_many tags : Tag, through: "post_tags"
10
end
11
12
class Tag
13
include Clear::Model
14
15
primary_key
16
17
column name : String
18
19
has_many tags : Post, through: "post_tags"
20
end
Copied!
And thats all ! Basically, in this case, we may not want to create a model PostTag as the table exists only to make the link between the two models.
Addition and deletion is provided in elegant way even without model:
add_to_post.cr
1
p = Post.new({name: "My new post"})
2
p.save!
3
# Add the tag Technology to the post
4
p.tags << Tag.query.find_or_create({name: "Technology"}){}
Copied!
p has to be saved in database before linking the tag.
delete_tag.cr
1
p = Post.query.first!
2
3
tags = p.tags
4
tags.unlink( tags.where(name: "Technology").first! )
Copied!

Middle-table model

Optionally, we can define our middle-table model. In this case, you should use the model as through argument :
1
class Post
2
include Clear::Model
3
4
class Tag
5
include Clear::Model
6
7
belongs_to post : Post
8
belongs_to tag : Tag
9
10
self.table = "post_tags"
11
end
12
13
primary_key
14
15
column name : String
16
column content : String?
17
18
has_many tags : Tag, through: Post::Tag
19
end
20
21
class Tag
22
include Clear::Model
23
24
primary_key
25
26
column name : String
27
28
has_many tags : Post, through: Post::Tag
29
end
Copied!
Note: The model Post::Tag don't have primary key which can lead to issues with Clear. Feel free to leave issues to the community here.
Last modified 2yr ago