Własny scope przy relacji many-to-many

Witam
Mam 3 tabele: posts,taggings,tags
przy czym:
post has_many tags
tag has_many posts
tagging belongs_to post,tag

Chcę skonstruować scope Post.find_by_tag, który by mi zwrócił wszystkie posty z przypisanym tagiem “tag1”. Jak zbudować polecenie SQL, które by to realizowało?
EDIT:
Przy pomocy wujka G udało mi się wysmażyć coś takiego, ale nie zwraca to tego, czego chcę, czyli rekordów tylko z tabeli Posts.

SELECT * FROM posts INNER JOIN (tags,taggings) ON (taggings.post_id=posts.id AND taggings.tag_id=tags.id) WHERE tags.name="akcja"

Nie do końca rozumiem, co chcesz osiągnąć. Nie możesz po prostu wklepać czegoś w stylu @posts = Tag.find_by_name('elo').posts? Jeśli powiązania masz poprawnie zrealizowane, to nie powinno być problemu.

O, myślałem, że findery typu find_by_ działają tylko dla pól wewnętrznych modelu, a nie dla asocjacji. Dzięki.

W podanym przeze mnie rozwiązaniu Tag#find_by_name nawet nie rusza asocjacji :wink: Po prostu najpierw wyszukujesz tag po nazwie, a później wyświetlasz wszystkie należące do niego posty.

W jakiś sposób chyba musi, bo w bazie tabela tags nie ma pola “posts”
Poza tym chyba zapomniałem dodać, że to jest has_many :through, a nie zwykłe has_many. Co nie zmienia faktu, że rozwiązanie działa.

Jeśli koniecznie chcesz SQL-a to np. taki działa:

select * from posts where id in (select post_id from taggings where tag_id in (select id from tags where name = 'tag'));

Choć oczywiście najelegantsze i najszybsze rozwiązanie to nie jest :wink:

EDIT: tzn. działa w MySQL-u, w postgresie też powinien, ale pewien nie jestem. Natomiast na pewno nie jest uniwersalny i przenośny.

Znalazłem jeszcze jedno omijając zagnieżdżenie SELECT JOINem, ale już nie pamiętam jak do tego doszedłem :smiley: Dzięki za odpowiedzi.

Pokaż swoje modele Post i Tag (pamiętaj o użyciu [ code ] [ / code] :slight_smile: )

Proszę:
post.rb

[code=ruby]class Post < ActiveRecord::Base
attr_accessible :text, :title
belongs_to :user
has_many :taggings
has_many :tags, :through => :taggings

validates :user_id, :presence => true
validates :text, :presence => true,
:length => {:minimum => 20}
validates :title, :presence => true,
:length => {:maximum => 60}

default_scope :order => “posts.created_at DESC”
scope :search,lambda { |query|
where(“posts.title LIKE ? OR posts.text LIKE ?”, “%#{query}%”, “%#{query}%”)
}
scope :tag, lambda { |tag_name|
joins(:taggings,:tags).where(“taggings.tag_id=tags.id AND tags.name=”#{tag_name}" AND taggings.post_id=posts.id")
}
end[/code]
tag.rb

[code=ruby]class Tag < ActiveRecord::Base
attr_accessible :name

validates :name, :presence => true
has_many :taggings
has_many :posts, :through => :taggings

scope :search,lambda { |query|
where(“tags.name LIKE ?”, “%#{query}%”)
}
end[/code]