This seems like it should have been asked numerous times already, but my Google-fu isn''t strong enough to find the answer. DHH advocates separating HABTM relationships into a join model, and I need to store some metadata about the join, so this makes sense. The problem is creation order and validations. Say, you have three models, like so: class Foo < AR::Base has_many :bars, :through => :quux has_many :quuxes end class Bar < AR::Base has_many :quuxes, :dependent => :destroy has_many :foos, :through => :quuxes end class Quux < AR::Base belongs_to :foo belongs_to :bar end Foo is valid without any Bars, and a Bar may belong to multiple Foos. However, a Bar should never exist without being associated with at least one Foo. So, how would you ensure that every time a Bar is created, the proper Quux is also created, without ever leaving an opportunity for a Bar to exist without a Foo? My initial thought is that a transaction is necessary, in this order: 1) Create Bar (rollback on fail) 2) Create Quux, referencing bar.id and foo.id (rollback on fail) How do I enforce this order and maintain database integrity in the model layer? This seems silly; if there''s an obvious answer/resource I''m missing, please let me know. Thanks. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Brandon Mitchell wrote:> This seems like it should have been asked numerous times already, but my > Google-fu isn''t strong enough to find the answer. DHH advocates > separating HABTM relationships into a join model, and I need to store > some metadata about the join, so this makes sense. The problem is > creation order and validations. > > Say, you have three models, like so: > > class Foo < AR::Base > has_many :bars, :through => :quux > has_many :quuxes > end > > class Bar < AR::Base > has_many :quuxes, :dependent => :destroy > has_many :foos, :through => :quuxes > end > > class Quux < AR::Base > belongs_to :foo > belongs_to :bar > end > > Foo is valid without any Bars, and a Bar may belong to multiple Foos. > However, a Bar should never exist without being associated with at least > one Foo. > > So, how would you ensure that every time a Bar is created, the proper > Quux is also created, without ever leaving an opportunity for a Bar to > exist without a Foo? > > My initial thought is that a transaction is necessary, in this order: > 1) Create Bar (rollback on fail) > 2) Create Quux, referencing bar.id and foo.id (rollback on fail) > > How do I enforce this order and maintain database integrity in the model > layer? > > This seems silly; if there''s an obvious answer/resource I''m missing, > please let me know. Thanks. > -- > Posted via http://www.ruby-forum.com/.This is quite simple with validations. In your Bar model you will want the following: #Validate belongs to a foo validates_presence_of :foo_id #Validates foo exists - ONLY use this if the foo object is already saved. validates_associated :foos Rails will do all the work with Quux on your behalf. --------------------------------------------------------------------------------------------------- FYI, If you do not need to directly work with the Quux model itself, you may find it tidier to use a has_and_belongs_to_many association with a join table instead of your proposed has_many :through. Like so: class Foo < AR::Base has_and_belongs_to_many :bars, :join_table => :quuxes end class Bar < AR::Base has_and_belongs_to_many :foos, :join_table => :quuxes end and have a join table called quuxes (or maybe foo_bar depending on how you like to name your join tables) with columns foo_id and bar_id --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Matt wrote:> This is quite simple with validations. In your Bar model you will want > the following: > > #Validate belongs to a foo > validates_presence_of :foo_id > #Validates foo exists - ONLY use this if the foo object is already > saved. > validates_associated :foos > > Rails will do all the work with Quux on your behalf.This is, perhaps, what I would *like* to do, but Bar does not have a foo_id. At least, Rails 2.0.2 doesn''t seem to be proxying #foo_id on Bar to #foo_id on Quux, by default. This has to be one of the most used paradigms in Rails >= 1.1, but I can''t seem to find the "conventional" method for assuring that a Bar cannot be created without an associated Foo.> FYI, If you do not need to directly work with the Quux model itself, > you may find it tidier to use a has_and_belongs_to_many association > with a join table instead of your proposed has_many :through.I do need to use a join model, rather than a join table. I have other metadata I need to store in Quux. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
> > #Validate belongs to a foo > > validates_presence_of :foo_id > This is, perhaps, what I would *like* to do, but Bar does not have a > foo_id. At least, Rails 2.0.2 doesn''t seem to be proxying #foo_id on Bar > to #foo_id on Quux, by default.Apologies, that should be :foo_ids (plural, as it is a has_many association) and it should be managed directly by the association. It is an array of the Foo id''s associated with Bar. Updating this should be updating the quuxes table according to the associations you have set up. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Hi The following is one solution I got to my problem class KnowledgeBase < ActiveRecord::Base has_many :sd_knowledge_bases has_many :sds, :through => :sd_knowledge_bases # (...) end # app/models/sd.rb class Sd < ActiveRecord::Base has_many :sd_knowledge_bases has_many :knowledge_bases, :through => :sd_knowledge_bases # # (...) end # app/models/sd_knowledge_base.rb class SdKnowledgeBase < ActiveRecord::Base belongs_to :knowledge_base belongs_to :sd # (...) end # in controller action (assuming params[:id] is the ID of your SD) @knowledge_bases = Sd.find(params[:id]).knowledge_bases But I get the error uninitialized constant SD::SDKnowledgeBasis Note Basis My table structure as below 1)knowledge_bases id integer not null default nextval(''public.knowledge_bases_id_seq''::text) name character varying(200) keyword text url character varying(500) summary text details text 2)sd_knowledge_bases id integer not null default nextval(''public.service_desk_knowledge_bases_id_seq ''::text) sd_id integer knowledge_base_id integer Pls help Sijo -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
I have the 3 tables 1)service_desk_tickets id integer not null default nextval(''public.service_desk_tickets_id_seq'': :text) number character varying(15) title character varying(100) service_desk_status_id integer etc..... 2)cis id integer not null default nextval(''public.cis_id_seq''::text) citype character varying(30) ci_number character varying(15) content_id integer etc.... 3)service_desk_cis(This is a junction table) id integer not null default nextval(''public.service_desk_cis_id_se q''::text) service_desk_ticket_id integer ci_id integer service_desk_ci_association_type_id integer Associations as In service_desk_ticket.rb has_many :service_desk_cis has_many :cis, :through => :service_desk_cis In ci.rb has_many :service_desk_cis has_many :service_desk_tickets, :through => :service_desk_cis in service_desk_cis.rb belongs_to :service_desk_ticket belongs_to :ci In controller @sd_cis=ServiceDeskTicket.find(params[:id]).cis (This is working) MY PROBLEM IS HOW TO GET service_desk_ci_association_type_id Please help Sijo -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Hi, The implementation of has_many and belongs_to association is only not enough to join two taIf u have implement two tables..And also u use the following query @sd_cis=ServiceDeskTicket.find(params[:id], :include [:service_desk_cis]) and u retrieve the field of ServiceDeskTicket table as @sd_cis.id and u retrieve the field of Service_desk_cis table as @sd_cis.service_desk_cis.service_desk_ci_association_type_id On Feb 18, 2008 1:13 PM, Sijo Kg <rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> > I have the 3 tables > > 1)service_desk_tickets > > id integer not null default > nextval(''public.service_desk_tickets_id_seq'': > :text) > number character varying(15) > title character varying(100) > service_desk_status_id integer > etc..... > > 2)cis > > id integer not null default nextval(''public.cis_id_seq''::text) > citype character varying(30) > ci_number character varying(15) > content_id integer > etc.... > > 3)service_desk_cis(This is a junction table) > > id integer not null default nextval(''public.service_desk_cis_id_se > q''::text) > service_desk_ticket_id integer > ci_id integer > service_desk_ci_association_type_id integer > > Associations as > In service_desk_ticket.rb > > has_many :service_desk_cis > has_many :cis, :through => :service_desk_cis > > In ci.rb > has_many :service_desk_cis > has_many :service_desk_tickets, :through => :service_desk_cis > > in service_desk_cis.rb > > belongs_to :service_desk_ticket > belongs_to :ci > > In controller > @sd_cis=ServiceDeskTicket.find(params[:id]).cis (This is working) > > MY PROBLEM IS HOW TO GET service_desk_ci_association_type_id > > Please help > Sijo > -- > Posted via http://www.ruby-forum.com/. > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
I did in controller @sd_cis=ServiceDeskTicket.find(params[:id], :include => [:service_desk_cis]).cis And in view <% 0.upto(@sd_cis.length-1) do |loop_index| %> <td><%=CiStatus.find(@sd_cis[loop_index].content.ci_status_id).name%></td> <td><%=@sd_cis[loop_index].ci_number%></td> <td><%=CiType.find(@sd_cis[loop_index].citype).name%></td> <td><%=@sd_cis[loop_index].content.name%></td> <td><%=CiClass.find(@sd_cis[loop_index].content.ci_class).name%></td> <td><%= @sd_cis[loop_index].service_desk_cis.service_desk_ci_association_type_id %></td> <% end %> If I comment last line(@sd_cis[loop_index.....)No error everything ok.But if uncomment it I get the error undefined method `service_desk_ci_association_type_id'' for ServiceDeskCi:Class Sijo -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Hi, U may try this type of for loop tag to display the contents.... <% for sd_cis in @sd_cis %> <%= sd_cis.service_desk_cis.service_desk_ci_association_type_id %> <% end %> I think i should helpful to u... On Feb 18, 2008 3:34 PM, Sijo Kg <rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> > I did > in controller > > @sd_cis=ServiceDeskTicket.find(params[:id], :include => > [:service_desk_cis]).cis > > And in view > > <% 0.upto(@sd_cis.length-1) do |loop_index| %> > > <td><%=CiStatus.find > (@sd_cis[loop_index].content.ci_status_id).name%></td> > <td><%=@sd_cis[loop_index].ci_number%></td> > <td><%=CiType.find(@sd_cis[loop_index].citype).name%></td> > <td><%=@sd_cis[loop_index].content.name%></td> > <td><%=CiClass.find(@sd_cis[loop_index].content.ci_class).name%></td> > <td><%> @sd_cis[loop_index].service_desk_cis.service_desk_ci_association_type_id > %></td> > > > <% end %> > > If I comment last line(@sd_cis[loop_index.....)No error everything > ok.But if uncomment it I get the error > undefined method `service_desk_ci_association_type_id'' for > ServiceDeskCi:Class > > Sijo > -- > Posted via http://www.ruby-forum.com/. > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Did you create foreign key in your migration when you created service_desk_cis to its related table ? -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Migration file is class CreateServiceDeskCis < ActiveRecord::Migration def self.up create_table :service_desk_cis do |t| t.column :service_desk_ticket_id, :integer t.column :ci_id, :integer t.column :service_desk_ci_association_type_id, :integer t.column :created_by, :integer t.column :modified_by, :integer t.column :created_on, :datetime, :null=>false t.column :created_at, :datetime, :null=>false t.column :updated_on, :datetime, :null=>false t.column :updated_at, :datetime, :null=>false end end def self.down drop_table :service_desk_cis end end -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
I see your migration file. you dont have foreign key to link them in database, you should add like this in your new migration : execute ''ALTER TABLE service_desk_cis ADD CONSTRAINT fk_service_desk_cis FOREIGN KEY (service_desk_status_id) REFERENCES service_desk_tickets(id)'' I hope it will works. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Sorry this is the correct one : execute ''ALTER TABLE service_desk_cis ADD CONSTRAINT fk_service_desk_cis FOREIGN KEY (service_desk_ticket_id ) REFERENCES service_desk_tickets(id)'' I hope it will work. ---- website: http://teapoci.blogspot.com YM : booking2heaven -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
The servicedeskticket migration was class CreateServiceDeskTickets < ActiveRecord::Migration def self.up create_table :service_desk_tickets do |t| t.column :number, :string, :limit=>15 t.column :title, :string, :limit=>100 t.column :status, :integer t.column :category, :integer t.column :sub_category, :integer t.column :primary_assignee_group, :string, :limit=>50 t.column :impact, :integer t.column :urgency, :integer t.column :priority, :integer t.column :resolved, :boolean, :default=>false t.column :description, :string, :limit=>100 end end def self.down drop_table :service_desk_tickets end end In the controller @sd_ticket=ServiceDeskTicket.find(params[:id]) @sd_ticket.service_desk_cis.each do |t| puts t.service_desk_ci_association_type_id end This worked..What may be the differnce? -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
sorry, my internet was down. the difference is : -- YOUR PROBLEM HERE --- @sd_cis=ServiceDeskTicket.find(params[:id], :include =>[:service_desk_cis]).cis -- YOUR WORKING TEST SCRIPT --- @sd_ticket=ServiceDeskTicket.find(params[:id]) it''s quite difference. Please run it : @testcis = Ci.find(params[:id]) @testcis.service_desk_cis.service_desk_ticket_id I need to know what it works or no. if it is not working, it means that your cis can not be linked to service_desk_cis, so you can try to add foreign key there. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Thanks for your reply..It worked like @servicedesk_cis_join = @sd_ticket.service_desk_cis @sd_cis = @servicedesk_cis_join.map(&:ci) @sd_cis_association_type_ids = servicedesk_cis_join.map(&:service_desk_ci_association_type_id) And in view <%= @sd_cis_association_type_ids[loop_index] %> -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---