开发者

Best way to do the following join in Rails 3

开发者 https://www.devze.com 2023-03-14 10:43 出处:网络
I have the following classes: class Annotation < ActiveRecord::Ba开发者_运维问答se has_many :annotation_tags

I have the following classes:

class Annotation < ActiveRecord::Ba开发者_运维问答se
  has_many :annotation_tags
end

class Tag < ActiveRecord::Base
  has_many :annotation_tags
end

class AnnotationTag < ActiveRecord::Base
  belongs_to :annotation
  belongs_to :tag
end

and the following join:

SELECT `annotations`.*, annotation_tags.* FROM `annotations` JOIN annotation_tags on
    annotation_tags.annotation_id =  annotations.id and annotation_tags.tag_id = 123

What is the best way to code this in Rails 3?


You have two options:

Use has_many, :xs, :through => :ys.

class Annotation < ActiveRecord::Base
  has_many :annotation_tags
  has_many :tags, :through => :annotation_tags
end

class Tag < ActiveRecord::Base
  has_many :annotation_tags
  has_many :annotations, :through => :annotation_tags
end

class AnnotationTag < ActiveRecord::Base
  belongs_to :annotation
  belongs_to :tag
end

Then you can type:

tag = Tag.find(123)
annotations = tag.annotations

Alternatively, if you don't need extra attributes on your AnnotationTag model, i.e. it's purely a join table, you can use has_and_belongs_to_many. Your join table must not have an id column, so in the migration, make sure you specify :id => false as described in the ActiveRecord Associations API docs

class Annotation < ActiveRecord::Base
  has_and_belongs_to_many :tags
end

class Tag < ActiveRecord::Base
  has_and_belongs_to_many :annotations
end

class AnnotationsTag < ActiveRecord::Base # First part of model name must be pluralized.
  belongs_to :annotation
  belongs_to :tag
end

In this case the syntax for getting all the annotations for a tag is the same.

tag = Tag.find(123)
annotations = tag.annotations


Here was my initial attempt:

tag_id = 123
Annotation.joins("JOIN #{AnnotationTag.table_name} on #{AnnotationTag.table_name}.annotation_id =  #{Annotation.table_name}.id and #{AnnotationTag.table_name}.tag_id = #{tag_id}").scoped

@Cameron's is a much cleaner solution, but did require my join table class name to be changed to AnnotationsTags (note the plural).

0

精彩评论

暂无评论...
验证码 换一张
取 消