【Rails】단일 테이블 상속(STI)에 대해서
단일 테이블 상속(STI)이란?
STI(Single Table Inheritance)
같은 컬럼 설계의 테이블을, 하나의 테이블에 정리해, 계승하는 것으로 불필요한 테이블을 늘리지 않고, DRY인 테이블 설계로 한다고 하는 것.
(테이블이 많네요 w)
사고방식은 클래스의 계승과 같다!!
예
STI 미사용 (일반 테이블 설계)
Authors、categorys、tags
3개 모두 같은 컬럼 설계인데 테이블을 각각 작성하고 있는 것은 가독성이 내려, 낭비.
STI 사용
그림에도 쓰여진 대로, authors, category, tags는 의사 테이블이며, DB에는 실재하지 않는 테이블이 됩니다.
존재하지 않으므로 모든 데이터는 taxonomies에 저장됩니다.
이 그림은 DB 레벨에서의 상관도입니다.
Model 레벨에서는, Articles.rb등의 기술을 보면 알지만 Author, Category, Tag(Article tags를 개입시켜)와 직접 어소시에이션이 짜넣어지고 있습니다.
Article과 Taxonomy는 각 Model 파일을 보면 어소시에이션은 조합되어 있지 않은 것을 알 수 있습니다.
다시 말하지만, 이것은 DB 레벨의 상관 다이어그램입니다.
DB와 Model은 분리해 생각하지 않으면 반드시 혼란스럽습니다.
모델
article.rbclass Article < ApplicationRecord
belongs_to :category
belongs_to :author
has_many :article_tags, dependent: :destroy
has_many :tags, through: :article_tags
end
taxonomies.rbclass Taxonomy < ApplicationRecord
end
author.rbclass Author < Taxonomy
has_many :articles
end
category.rbclass Category < Taxonomy
has_many :articles
end
tag.rbclass Tag < Taxonomy
has_many :article_tags
has_many :articles, through: :article_tags
end
의사 테이블 3개는 상속원이 ApplicationRecord를 상속한 Taxonomy가 되어 있는 점에 주의! !
Active Record
[1] pry(main)> Article.joins(:tags).where(tags: { id: 1 }).first
Article Load (3.5ms) SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxo
nomies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1 ORDER BY `articles`.`id` ASC LIMIT 1
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'tags.id' in 'where clause': SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_ta
gs`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxonomies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1 ORDER
BY `articles`.`id` ASC LIMIT 1
[3] pry(main)> Article.joins(:tags).where(tags: { id: 1 })
Article Load (2.0ms) SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxon
omies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1
Article Load (0.6ms) SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxo
nomies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1 LIMIT 11
=> #<Article::ActiveRecord_Relation:0x3fe90b9879dc>
여기서의 포인트는 에러가 출력되고 있는가 하는 것.
왜냐하면, where
는 조건대로 좁혀 주어도 사용되기 전까지는 실행되지 않기 때문에, 에러가 출력되지 않는다.
오류 문에는 WHERE 'tags'문자가 있습니다.
이것은 tags 테이블로부터라는 조건하에 검색을 걸고 있는데, 단일 테이블을 계승한 테이블은 의사 테이블이며, 실재하지 않는다.
실재하지 않는 테이블로부터 검색하는 것은 무리이므로 에러가 나와 있다.
[6] pry(main)> Article.joins(:tags).where(taxonomies: { id: 1 })
Article Load (9.0ms) SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxon
omies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `taxonomies`.`id` = 1
=> []
이제 ok
덧붙여서 어떤 SQL이 달리는지만 보고 싶을 때는 to.sql
를 사용한다.
[7] pry(main)> Article.joins(:tags).where(tags: { id: 1 }).to_sql
=> "SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxonomies`.`id` = `artic
le_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1"
테이블 주위 너무 약해서 SQL에 격려합니다.
Reference
이 문제에 관하여(【Rails】단일 테이블 상속(STI)에 대해서), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/niwa1903/items/218713c076fb0075712f
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
STI 미사용 (일반 테이블 설계)
Authors、categorys、tags
3개 모두 같은 컬럼 설계인데 테이블을 각각 작성하고 있는 것은 가독성이 내려, 낭비.STI 사용
그림에도 쓰여진 대로, authors, category, tags는 의사 테이블이며, DB에는 실재하지 않는 테이블이 됩니다.
존재하지 않으므로 모든 데이터는 taxonomies에 저장됩니다.
이 그림은 DB 레벨에서의 상관도입니다.
Model 레벨에서는, Articles.rb등의 기술을 보면 알지만 Author, Category, Tag(Article tags를 개입시켜)와 직접 어소시에이션이 짜넣어지고 있습니다.
Article과 Taxonomy는 각 Model 파일을 보면 어소시에이션은 조합되어 있지 않은 것을 알 수 있습니다.
다시 말하지만, 이것은 DB 레벨의 상관 다이어그램입니다.
DB와 Model은 분리해 생각하지 않으면 반드시 혼란스럽습니다.
모델
article.rbclass Article < ApplicationRecord
belongs_to :category
belongs_to :author
has_many :article_tags, dependent: :destroy
has_many :tags, through: :article_tags
end
taxonomies.rbclass Taxonomy < ApplicationRecord
end
author.rbclass Author < Taxonomy
has_many :articles
end
category.rbclass Category < Taxonomy
has_many :articles
end
tag.rbclass Tag < Taxonomy
has_many :article_tags
has_many :articles, through: :article_tags
end
의사 테이블 3개는 상속원이 ApplicationRecord를 상속한 Taxonomy가 되어 있는 점에 주의! !
Active Record
[1] pry(main)> Article.joins(:tags).where(tags: { id: 1 }).first
Article Load (3.5ms) SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxo
nomies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1 ORDER BY `articles`.`id` ASC LIMIT 1
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'tags.id' in 'where clause': SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_ta
gs`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxonomies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1 ORDER
BY `articles`.`id` ASC LIMIT 1
[3] pry(main)> Article.joins(:tags).where(tags: { id: 1 })
Article Load (2.0ms) SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxon
omies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1
Article Load (0.6ms) SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxo
nomies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1 LIMIT 11
=> #<Article::ActiveRecord_Relation:0x3fe90b9879dc>
여기서의 포인트는 에러가 출력되고 있는가 하는 것.
왜냐하면, where
는 조건대로 좁혀 주어도 사용되기 전까지는 실행되지 않기 때문에, 에러가 출력되지 않는다.
오류 문에는 WHERE 'tags'문자가 있습니다.
이것은 tags 테이블로부터라는 조건하에 검색을 걸고 있는데, 단일 테이블을 계승한 테이블은 의사 테이블이며, 실재하지 않는다.
실재하지 않는 테이블로부터 검색하는 것은 무리이므로 에러가 나와 있다.
[6] pry(main)> Article.joins(:tags).where(taxonomies: { id: 1 })
Article Load (9.0ms) SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxon
omies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `taxonomies`.`id` = 1
=> []
이제 ok
덧붙여서 어떤 SQL이 달리는지만 보고 싶을 때는 to.sql
를 사용한다.
[7] pry(main)> Article.joins(:tags).where(tags: { id: 1 }).to_sql
=> "SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxonomies`.`id` = `artic
le_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1"
테이블 주위 너무 약해서 SQL에 격려합니다.
Reference
이 문제에 관하여(【Rails】단일 테이블 상속(STI)에 대해서), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/niwa1903/items/218713c076fb0075712f
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
class Article < ApplicationRecord
belongs_to :category
belongs_to :author
has_many :article_tags, dependent: :destroy
has_many :tags, through: :article_tags
end
class Taxonomy < ApplicationRecord
end
class Author < Taxonomy
has_many :articles
end
class Category < Taxonomy
has_many :articles
end
class Tag < Taxonomy
has_many :article_tags
has_many :articles, through: :article_tags
end
[1] pry(main)> Article.joins(:tags).where(tags: { id: 1 }).first
Article Load (3.5ms) SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxo
nomies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1 ORDER BY `articles`.`id` ASC LIMIT 1
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'tags.id' in 'where clause': SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_ta
gs`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxonomies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1 ORDER
BY `articles`.`id` ASC LIMIT 1
[3] pry(main)> Article.joins(:tags).where(tags: { id: 1 })
Article Load (2.0ms) SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxon
omies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1
Article Load (0.6ms) SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxo
nomies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1 LIMIT 11
=> #<Article::ActiveRecord_Relation:0x3fe90b9879dc>
여기서의 포인트는 에러가 출력되고 있는가 하는 것.
왜냐하면,
where
는 조건대로 좁혀 주어도 사용되기 전까지는 실행되지 않기 때문에, 에러가 출력되지 않는다.오류 문에는 WHERE 'tags'문자가 있습니다.
이것은 tags 테이블로부터라는 조건하에 검색을 걸고 있는데, 단일 테이블을 계승한 테이블은 의사 테이블이며, 실재하지 않는다.
실재하지 않는 테이블로부터 검색하는 것은 무리이므로 에러가 나와 있다.
[6] pry(main)> Article.joins(:tags).where(taxonomies: { id: 1 })
Article Load (9.0ms) SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxon
omies`.`id` = `article_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `taxonomies`.`id` = 1
=> []
이제 ok
덧붙여서 어떤 SQL이 달리는지만 보고 싶을 때는
to.sql
를 사용한다.[7] pry(main)> Article.joins(:tags).where(tags: { id: 1 }).to_sql
=> "SELECT `articles`.* FROM `articles` INNER JOIN `article_tags` ON `article_tags`.`article_id` = `articles`.`id` INNER JOIN `taxonomies` ON `taxonomies`.`id` = `artic
le_tags`.`tag_id` AND `taxonomies`.`type` IN ('Tag') WHERE `tags`.`id` = 1"
테이블 주위 너무 약해서 SQL에 격려합니다.
Reference
이 문제에 관하여(【Rails】단일 테이블 상속(STI)에 대해서), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/niwa1903/items/218713c076fb0075712f텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)