Um ein paar der neuen Rails-Features auszuprobieren, baue ich eine
kleine Filmdatenbank. Darin gibt es Filme, Personen, Rollen und
RollenTypen. RollenTypen gibt es "Schauspieler" und "Regisseur". Ich
möchte nun für Personen eine Assoziation definieren, die die Person mit
allen Filmen verknüpft, in denen sie mitgespielt hat.
Das hatte ich mir zunächst so gedacht
class Person < ActiveRecord::Base
has_many :roles, :include => :role_type
has_many :acts_in, :through => :roles, :source => :movie,
:order => 'release_date',
:conditions => { :roles => { :role_type => { :name => 'Actor' } } }
Es funktioniert aber nicht, weil das :include von roles nicht an die
abgeleitete acts_in weitergegeben wird. Nächster Versuch
class Person < ActiveRecord::Base
has_many :roles
has_many :acts_in, :through => :roles, :source => :movie,
:order => 'release_date',
:include => :role_type,
:conditions => { :roles => { :role_type => { :name => 'Actor' } } }
Geht auch nicht, weil :include sich auf das Zielmodel, nämlich Movie,
bezieht.
Ist es ohne handgeschriebenes SQL möglich, eine Bedingung zu
formulieren, die sich auf ein weiteres, zu dem through-Objekt gejointes
Objekt bezieht?
Michael
--
Michael Schuerig
mailto:michael@schuerig.de
http://www.schuerig.de/michael/
on 2009-03-08 01:12
on 2009-03-08 09:39
Hallo Michael,
hier mein Lösungsvorschlag:
class Person < ActiveRecord::Base
has_many :films
has_many :roles, :through => :films, :uniq => true
end
class Film < ActiveRecord::Base
belongs_to :person
belongs_to :role
end
class Role < ActiveRecord::Base
has_many :films
has_many :people, :through => :films
end
Das sind alle Modelle die ich benötige.
Role entspricht den von Dir definierten Rollentypen
p = Person.find_by_name('Clint Eastwood')
Jetzt kannst ich alle Filme abfragen in welchen Clint Eastwood z.B.
als Schauspieler mitgespielt hat:
p.roles.find_by_name('Schauspieler').films
oder
p.films.all(:conditions => ['role_id = 1']) falls die Rolle
'Schauspieler' die id = 1 hat.
Die zweite Abfrageform sieht nicht so elegant aus ist aber schneller
in der Ausführung.
Gruss,
Roman
Am 08.03.2009 um 01:11 schrieb Michael Schuerig:
on 2009-03-08 11:03
On Sunday 08 March 2009, Roman Sladeczek wrote: > belongs_to :person > belongs_to :role > end > > class Role < ActiveRecord::Base > has_many :films > has_many :people, :through => :films > end Ja, das geht, meine Modellierung ist aber anders, das Role-Model hat keinen String, der die Art der Rolle bestimmt, sondern einen FK auf RoleType. Das genau ist die Schwierigkeit. class Role < ActiveRecord::Base belongs_to :person belongs_to :role_type belongs_to :movie validates_presence_of :person_id, :role_type_id, :movie_id end class RoleType < ActiveRecord::Base validates_presence_of :name end Mir ist vollkommen klar, dass ich mir für diesen Beispielfall die Modellierung so zurecht biegen könnte, dass es funktioniert. Das möchte ich nicht, weil das Ergebnis, um das es mir geht, nicht ein fertiges Produkt, sondern eine neue Erkenntnis ist. Ich möchte redundante Typ-Strings im Role-Model vermeiden und diese in ein weiteres Model, RoleType, herausziehen. Dadurch vermeide ich bei der DB-Modellierung Update- und Delete-Anomalien. Außerdem will ich keine IDs als Parameter für Bedingungen angeben. -- Ja, ich weiß natürlich, dass das starke Einschränkungen sind, ich will aber sehen, ob ich trotzdem mit AR das Ziel erreichen kann. Anders gesagt, ich möchte AR dazu bringen, SQL zu erzeugen, das etwa so aussieht: SELECT ... FROM people JOIN roles ON roles.person_id = people.id JOIN movies ON roles.movie_id = movies.id JOIN role_types ON roles.role_type_id = role_types.id WHERE role_types.name = 'Director' Michael -- Michael Schuerig mailto:michael@schuerig.de http://www.schuerig.de/michael/
on 2009-03-09 00:54
On Sunday 08 March 2009, Michael Schuerig wrote: > Anders gesagt, ich möchte AR dazu bringen, SQL zu erzeugen, das etwa > so aussieht: > > SELECT ... FROM people > JOIN roles ON roles.person_id = people.id > JOIN movies ON roles.movie_id = movies.id > JOIN role_types ON roles.role_type_id = role_types.id > WHERE role_types.name = 'Director' So kommt zumindest im Ergebnis heraus, was ich haben möchte: class Person < ActiveRecord::Base has_many :roles, :include => :role_type module RoleTypeExtensions def as_actor self.find(:all, :joins => 'JOIN role_types ON roles.role_type_id = role_types.id', :conditions => { :role_types => { :name => name }}) end end has_many :movies, :through => :roles, :extend => RoleTypeExtensions named_scope actors, :order => 'lastname, firstname', :joins => { :roles => :role_type }, :conditions => { :roles => { :role_types => { :name => 'Actor' }}} named_scope :with_movie_in_year, lambda { |year| { :joins => { :roles => :movie }, :conditions => ["movies.release_date between date(':year-01-01') and date(':year-12-31')", { :year => year }] } } ... end @actor.movies.as_actor Person.actors.with_movie_in_year(2004) Michael -- Michael Schuerig mailto:michael@schuerig.de http://www.schuerig.de/michael/
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.