Federico Fernádez
2006-Aug-03 20:26 UTC
[Rails] More than one has_many :through association between the same 2 models
I wonder if you can have more than one has_many :through association between 2 models. For example... I have a model Teacher and a model Class Now, 1 Teacher works in many Classes, right?. So I need a join model like class Work < ActiveRecord::Base belongs_to :teacher belongs_to :class end But I also would like to know if a teacher CAN teach a class before I assign him or her to one class. So I would like to have a new join model like "CanTeach" : class CanTeach< ActiveRecord::Base belongs_to :teacher belongs_to :class end The question is... can I do that? Because now the Teacher and Class Models would look like... class Teacher< ActiveRecord::Base has_many :works has_many :classes, :through => :works has_many :works has_many :classes, :through => :can_teach end class Class < ActiveRecord::Base has_many :works has_many :teachers, :through => :works has_many :works has_many :teachers, :through => :can_teach end but this doesn''t work.. Anyone knows how to do this? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060803/583baf17/attachment-0001.html
Nauhaie
2006-Aug-04 10:31 UTC
[Rails] Re: More than one has_many :through association between the
I would be very interested in an answer, too... But I suggest you read this: http://rubyonrails.org/api/classes/ActiveRecord/Associations/ClassMethods.html#M000530 And try to work around your problem with the the following option: :source: Specifies the source association name used by has_many :through queries. Only use it if the name cannot be inferred from the association. has_many :subscribers, :through => :subscriptions will look for either +:subscribers+ or +:subscriber+ on Subscription, unless a +:source+ is given. So you can have aclass.capable_teachers and aclass.actually_teaching_teachers or something like that. Can you tell me if it works? Nauhaie -- Posted via http://www.ruby-forum.com/.
j`ey
2006-Aug-04 12:20 UTC
[Rails] Re: More than one has_many :through association between the
I first suggest you find a better model name thatn class, that could muck things up, alot. Perhaps Lesson. j`ey http://www.eachmapinject.com Federico Fern?dez wrote:> I have a model Teacher and a model Class-- Posted via http://www.ruby-forum.com/.
Federico Fernandez
2006-Aug-04 14:26 UTC
[Rails] Re: More than one has_many :through association between the
Nauhaie wrote:> I would be very interested in an answer, too... > > But I suggest you read this: > http://rubyonrails.org/api/classes/ActiveRecord/Associations/ClassMethods.html#M000530 > > And try to work around your problem with the the following option: > > :source: Specifies the source association name used by has_many :through > queries. Only use it if the name cannot be inferred from the > association. has_many :subscribers, :through => :subscriptions will look > for either +:subscribers+ or +:subscriber+ on Subscription, unless a > +:source+ is given. > > So you can have aclass.capable_teachers and > aclass.actually_teaching_teachers or something like that. Can you tell > me if it works? > > NauhaieIf I understood the documentation right, I could do this: class Teacher< ActiveRecord::Base has_many :lessons, :through => :works, :source => :teacher has_many :classes, :through => :can_teach, :source => teacher end class Lesson< ActiveRecord::Base has_many :teachers, :through => :works, :source => :lesson has_many :teachers, :through => :can_teach, , :source => :lesson end Keeping the classes "CanTeach and Work" without changes. I will try this and let you know. -- Posted via http://www.ruby-forum.com/.
Federico Fernandez
2006-Aug-04 14:59 UTC
[Rails] Re: More than one has_many :through association between the
Federico Fernandez wrote:> Nauhaie wrote: >> I would be very interested in an answer, too... >> >> But I suggest you read this: >> http://rubyonrails.org/api/classes/ActiveRecord/Associations/ClassMethods.html#M000530 >> >> And try to work around your problem with the the following option: >> >> :source: Specifies the source association name used by has_many :through >> queries. Only use it if the name cannot be inferred from the >> association. has_many :subscribers, :through => :subscriptions will look >> for either +:subscribers+ or +:subscriber+ on Subscription, unless a >> +:source+ is given. >> >> So you can have aclass.capable_teachers and >> aclass.actually_teaching_teachers or something like that. Can you tell >> me if it works? >> >> Nauhaie > > > If I understood the documentation right, I could do this: > > class Teacher< ActiveRecord::Base > > has_many :lessons, :through => :works, :source => :teacher > > has_many :classes, :through => :can_teach, :source => teacher > > end > > > > class Lesson< ActiveRecord::Base > > has_many :teachers, :through => :works, :source => :lesson > > has_many :teachers, :through => :can_teach, , :source => :lesson > > end > > > Keeping the classes "CanTeach and Work" without changes. > > I will try this and let you know.It didn''t work, at all. Now when I do: t = Teacher.find(:first).contracts I get a HasManyThroughAssociationNotFoundError and if I do: l = Lesson.find(:all) I get another error. In summary, that''s not the way to do it (you need the "has many" :JoinTable statement, and/or I didn''t understand the ":source" option. -- Posted via http://www.ruby-forum.com/.
Josh Susser
2006-Aug-04 15:06 UTC
[Rails] Re: More than one has_many :through association between the
Federico Fernandez wrote:> Nauhaie wrote: >> I would be very interested in an answer, too... >> >> But I suggest you read this: >> http://rubyonrails.org/api/classes/ActiveRecord/Associations/ClassMethods.html#M000530 >> >> And try to work around your problem with the the following option: >> >> :source: Specifies the source association name used by has_many :through >> queries. Only use it if the name cannot be inferred from the >> association. has_many :subscribers, :through => :subscriptions will look >> for either +:subscribers+ or +:subscriber+ on Subscription, unless a >> +:source+ is given. >> >> So you can have aclass.capable_teachers and >> aclass.actually_teaching_teachers or something like that. Can you tell >> me if it works? >> >> Nauhaie > > > If I understood the documentation right, I could do this: > > class Teacher< ActiveRecord::Base > has_many :lessons, :through => :works, :source => :teacher > has_many :classes, :through => :can_teach, :source => teacher > end > > class Lesson< ActiveRecord::Base > has_many :teachers, :through => :works, :source => :lesson > has_many :teachers, :through => :can_teach, , :source => :lesson > end > > Keeping the classes "CanTeach and Work" without changes. > > I will try this and let you know.I responded to your email about this yesterday but I guess my response was lost. You must have unique names for associations within a class. If you reuse the same name, only the last has_many will be available. Just name them differently. And DON''T use :class or :classes - that will just bork everything up as "class" is both a keyword and a method on Object in ruby. You can spell it klass or clazz if you want. You can also take the approach of having only one join model with an attribute that indicates the state of the relationship, such as whether the teacher is qualified to teach the class vs if he is currently teaching it. I like this way best. class Teaching < ActiveRecord::Base belongs_to :teachers belongs_to :courses end class Course < ActiveRecord::Base has_many :teachings has_many :teachers, :through => :teachings end class Teacher < ActiveRecord::Base has_many :teachings has_many :courses, :through => :teachings has_many :courses_can_teach, :through => :teachings, :class_name => "Course", :conditions => "status = ''can''" has_many :courses_does_teach, :through => :teachings, :class_name => "Course", :conditions => "status = ''does''" end -- Josh Susser http://blog.hasmanythrough.com -- Posted via http://www.ruby-forum.com/.
Nauhaie
2006-Aug-04 15:19 UTC
[Rails] Re: More than one has_many :through association between the
Uhh... I''m not sure I get the difference between :source and :class_name... :class_name - specify the class name of the association. Use it only if that name can?t be inferred from the association name. So has_many :products will by default be linked to the Product class, but if the real class name is SpecialProduct, you?ll have to specify it with this option. :source: Specifies the source association name used by has_many :through queries. Only use it if the name cannot be inferred from the association. has_many :subscribers, :through => :subscriptions will look for either +:subscribers+ or +:subscriber+ on Subscription, unless a +:source+ is given. Huh? -- Posted via http://www.ruby-forum.com/.
Nauhaie
2006-Aug-04 15:27 UTC
[Rails] Re: More than one has_many :through association between the
In fact, Rails Recipes says: class Magazine < ActiveRecord::Base has_many :subscriptions has_many :readers, :through => :subscriptions has_many :semiannual_subscribers, :through => :subscriptions, :source => :reader, :conditions => [''length_in_issues = 6''] end They say that :source should be used instead of :class_name... Frederico, can you make :source work in your case? -- Posted via http://www.ruby-forum.com/.
Federico Fernandez
2006-Aug-04 15:48 UTC
[Rails] Re: More than one has_many :through association between the
Josh Susser wrote:> Federico Fernandez wrote: >> Nauhaie wrote: >>> I would be very interested in an answer, too... >>> >>> But I suggest you read this: >>> http://rubyonrails.org/api/classes/ActiveRecord/Associations/ClassMethods.html#M000530 >>> >>> And try to work around your problem with the the following option: >>> >>> :source: Specifies the source association name used by has_many :through >>> queries. Only use it if the name cannot be inferred from the >>> association. has_many :subscribers, :through => :subscriptions will look >>> for either +:subscribers+ or +:subscriber+ on Subscription, unless a >>> +:source+ is given. >>> >>> So you can have aclass.capable_teachers and >>> aclass.actually_teaching_teachers or something like that. Can you tell >>> me if it works? >>> >>> Nauhaie >> >> >> If I understood the documentation right, I could do this: >> >> class Teacher< ActiveRecord::Base >> has_many :lessons, :through => :works, :source => :teacher >> has_many :classes, :through => :can_teach, :source => teacher >> end >> >> class Lesson< ActiveRecord::Base >> has_many :teachers, :through => :works, :source => :lesson >> has_many :teachers, :through => :can_teach, , :source => :lesson >> end >> >> Keeping the classes "CanTeach and Work" without changes. >> >> I will try this and let you know. > > I responded to your email about this yesterday but I guess my response > was lost. You must have unique names for associations within a class. If > you reuse the same name, only the last has_many will be available. Just > name them differently. And DON''T use :class or :classes - that will just > bork everything up as "class" is both a keyword and a method on Object > in ruby. You can spell it klass or clazz if you want. > > You can also take the approach of having only one join model with an > attribute that indicates the state of the relationship, such as whether > the teacher is qualified to teach the class vs if he is currently > teaching it. I like this way best. > > class Teaching < ActiveRecord::Base > belongs_to :teachers > belongs_to :courses > end > > class Course < ActiveRecord::Base > has_many :teachings > has_many :teachers, :through => :teachings > end > > class Teacher < ActiveRecord::Base > has_many :teachings > has_many :courses, :through => :teachings > has_many :courses_can_teach, :through => :teachings, > :class_name => "Course", :conditions => "status = ''can''" > has_many :courses_does_teach, :through => :teachings, > :class_name => "Course", :conditions => "status = ''does''" > end > > -- > Josh Susser > http://blog.hasmanythrough.comHello Josh! wow.. thanks for the help, but let me see if I got it:> has_many :courses_can_teach, :through => :teachings, > :class_name => "Course", :conditions => "status = ''can''"This means that I need a table called "courses_can_teach" with the same structure of the table "courses", right? The database will have 2 different tables, but as you use :class_name => "Course" they will be represented with only one model class called "Course", am I right? Then you use :conditions => "status = ..." so you can use 1 Join Table instead of two. However, even though your suggestion is good, I don''t want one join table, but two, becase I want the Join Table "teachings" to use a different set of attributes than the Join Table "capabilities", and it would be strange to mix both sets in one Join Table. If I want to use more than one Join Table I don''t know what to do. In addition, there is something strange in your solution, because I''ll be able to do this: t1 = Teacher.find(:first).courses_can_teach t2 = Teacher.find(:first).courses_does_teach and t1 << course, etc.. But what if, given a course, I want to do operations over the teachers associated to it. If I do this: c = Course.find(:first).teacher what am I going to get? A teacher who can teach that course, or a teacher who does teach that course? I will probably have to make the searching methods by hand. Then, I would say that in rails you have to decide between freedom to do your database models pretty and efficient, and the benefits of using ActiveRecords Associations. -- Posted via http://www.ruby-forum.com/.
Federico Fernandez
2006-Aug-04 16:04 UTC
[Rails] Re: More than one has_many :through association between the
Nauhaie wrote:> In fact, Rails Recipes says: > > class Magazine < ActiveRecord::Base > has_many :subscriptions > has_many :readers, :through => :subscriptions > has_many :semiannual_subscribers, > :through => :subscriptions, > :source => :reader, > :conditions => [''length_in_issues = 6''] > end > > They say that :source should be used instead of :class_name... > Frederico, can you make :source work in your case?I haven''t tried Josh''s reply yet, because my real model is a bit more complicated than the example. I was doing the migrations now, I''m late for college, so I will complete it tomorrow, and let you know if it worked with "source" and/or "class_name". -- Posted via http://www.ruby-forum.com/.
Federico Fernandez
2006-Aug-05 03:53 UTC
[Rails] Re: More than one has_many :through association between the
Federico Fernandez wrote:> Nauhaie wrote: >> In fact, Rails Recipes says: >> >> class Magazine < ActiveRecord::Base >> has_many :subscriptions >> has_many :readers, :through => :subscriptions >> has_many :semiannual_subscribers, >> :through => :subscriptions, >> :source => :reader, >> :conditions => [''length_in_issues = 6''] >> end >> >> They say that :source should be used instead of :class_name... >> Frederico, can you make :source work in your case? > > I haven''t tried Josh''s reply yet, because my real model is a bit more > complicated than the example. I was doing the migrations now, I''m late > for college, so I will complete it tomorrow, and let you know if it > worked with "source" and/or "class_name".Ok... I could make it work with 2 join tables. It was a little pain on the ass to get it set, but then I felt good... I have what I wanted. Below is the explanation of what I did. Notice that I changed some class names for the sake of understandability. Also please note that my real application is more complex, which is the reason why using 2 join tables may look like a strange decision in this example, but it is not (or not that much) in my application.> class Scheduling< ActiveRecord::Base# the teachers work in some courses through schedulings> belongs_to :teachers > belongs_to :courses > end> class Screening< ActiveRecord::Base# the teachers can work in some courses through screenings> belongs_to :teachers > belongs_to :courses > > end > > class Course < ActiveRecord::Base > has_many :schedulings > has_many :screenings> has_many :teachers_does_teach, :through => :schedulings, :source => :teacher > has_many :teachers_can_teach, :through => :screenings, :source => :teacher > end > > class Teacher < ActiveRecord::Base > has_many :schedulings > has_many :screenings> has_many :courses_does_teach, :through => :schedulings, :source => :course > has_many :courses_can_teach, :through => :screenings, :source => :course > endAnd I have the following tables: - teachers, courses, screenings, scheduling AND... - teachers_can_teach, teachers_does_teach with the same structure as teachers - courses_can_teach, courses_does_teach with the same structure as courses So now I can do this: screen = Screening.new t = Tutor.find(11) c = Course.find(3) t.screenings << screen c.screenings << screen s.year = 1974 s.college = "University of Minesota" s.comments = "Graduated with honors" s.save sched = Scheduling.new t = Tutor.find(11) c = Course.find(3) t.schedulings << sched c.schedulings << sched s.day = "monday" s.save Then I can do things like: t.courses_can_teach.find(:first).name t.courses_does_teach_count AND I don''t have the following methods: t.courses c.teachers which is fine, since that wouldn''t make sense in my example. Now... I don''t know if using two has-many-through associations is better than using one (as Josh suggested) but I''m happy to know that you can do it in rails. I really don''t like having to change my ER diagrams because of framework restrictions, do you? -- Posted via http://www.ruby-forum.com/.
Josh Susser
2006-Aug-05 16:47 UTC
[Rails] Re: More than one has_many :through association between the
Federico Fernandez wrote:> Ok... I could make it work with 2 join tables. It was a little pain on > the ass to get it set, but then I felt good... I have what I wanted. > Below is the explanation of what I did. Notice that I changed some class > names for the sake of understandability. Also please note that my real > application is more complex, which is the reason why using 2 join tables > may look like a strange decision in this example, but it is not (or not > that much) in my application. > > ... > > Then I can do things like: > > t.courses_can_teach.find(:first).name > t.courses_does_teach_count > > AND I don''t have the following methods: > > t.courses > c.teachers > > which is fine, since that wouldn''t make sense in my example. > > Now... I don''t know if using two has-many-through associations is better > than using one (as Josh suggested) but I''m happy to know that you can do > it in rails. I really don''t like having to change my ER diagrams because > of framework restrictions, do you?There''s no problem with having multiple has_many :through associations in a model. If that''s the best fit to model your problem, then that''s what you should do. Looks like you''ve worked out a good solution. Nicely done. -- Josh Susser http://blog.hasmanythrough.com -- Posted via http://www.ruby-forum.com/.
Federico Fernandez
2006-Aug-06 04:06 UTC
[Rails] Re: More than one has_many :through association between the
Josh Susser wrote:> Federico Fernandez wrote: >> Ok... I could make it work with 2 join tables. It was a little pain on >> the ass to get it set, but then I felt good... I have what I wanted. >> Below is the explanation of what I did. Notice that I changed some class >> names for the sake of understandability. Also please note that my real >> application is more complex, which is the reason why using 2 join tables >> may look like a strange decision in this example, but it is not (or not >> that much) in my application. >> >> ... >> >> Then I can do things like: >> >> t.courses_can_teach.find(:first).name >> t.courses_does_teach_count >> >> AND I don''t have the following methods: >> >> t.courses >> c.teachers >> >> which is fine, since that wouldn''t make sense in my example. >> >> Now... I don''t know if using two has-many-through associations is better >> than using one (as Josh suggested) but I''m happy to know that you can do >> it in rails. I really don''t like having to change my ER diagrams because >> of framework restrictions, do you? > > There''s no problem with having multiple has_many :through associations > in a model. If that''s the best fit to model your problem, then that''s > what you should do. Looks like you''ve worked out a good solution. Nicely > done. > > -- > Josh Susser > http://blog.hasmanythrough.comYes, that''s what I think too... and this issue made me think about the philosophy behing ActiveRecords Associations. In an initial stage you have 1 Model - 1 Table, but then, as the ER Diagramm gets more complex you will end with more tables than models, if you want Rails to generate methods for you. I''m not sure, but perhaps this is something to improve in the framework (or maybe it is something normal and good... I''m just thinking loud) Thanks for your help. I''m a newbie in ror and I''m starting to love it in part due to the nice community. -- Posted via http://www.ruby-forum.com/.