0

In a class I need to dynamically set has_many or has_one association according to the object *own attributes (so the foreign object won't need to change).

Something like:

class Child < ActiveRecord::Base
   if orphan == true #<-- I can't find the good solution for this condition
     has_one :parent
   else 
     has_many :parents
   end
end

on class "Parent" class I need to keep:

class Parent < ActiveRecord::Base
  belongs_to :children #this is true if the child is orphan or not
end

Is there a way to do so?

Just in case: I'm using rails 3.2.14

  • I don't believe this is possible as described. Are you sure that's the best solution? Why do you 'need' to do this? Why not just have an alias method that returns a single parent or an array based on `child.parent.size`? – Joe Essey Apr 23 '15 at 16:36
  • Hi Joe, the problem is that I want to modify the least as possible the app. The thing is that, in my specify case, the "child" is a "request" (that is made to a group) and the "parent" is an "agreement" that is met by the respective group --that used to be linked in a "has_one" association. As you can imagine, they are both quite complex models (with several views and controllers associated to them) and I want to have a DRY code, with the least change possible. --that said, yep, the condition will likely go to the controller, if child.orphan == true than call parent else call parents – Marc Rosenfeld Apr 23 '15 at 23:41

1 Answers1

1

My first thought would be to use single-table inheritance, since Orphan is a specific kind of child with different behaviors.

When deciding whether this is the right route, I found this post really helpful.

If you chose use STI, you'd end up with something like...

class Child < ActiveRecord::Base
end

class Orphan < Child
  has_one :parent
end

class StereotypicalFamilyUnit < Child
  has_many :parents
end

Rails will also assume and expect that you have a "type" string column in the Child table. When you call Orphan.new, it will create a child of type "Orphan." And if you do "Orphan.first" it's basically doing Child.where(type: "Orphan").first behind the scenes.

Another option (which I eventually opted for in an app I'm building in lieu of STI), would be to have a boolean as you suggested and use scopes, which might look like:

class Child < ActiveRecord::Base
  has_many :parents

  scope :orphan, -> { where(orphan: true) }
end

Which lets you instead call Child.orphan.new or Child.orphan.first, and do different things in views/controllers when orphan is true. You could then also follow the advice in this prior post to create a custom validation for orphans.

Community
  • 1
  • 1
Lanny Bose
  • 1,811
  • 1
  • 11
  • 16
  • (continuing) Actually your solution works, but I still need to modify the 'parents' model ( `belongs_to child` doesn't seems to work, so I need to specify, `belongs_to :orphan` and `belongs_to :stereotypical_family_unit` In the end, I simply added, at the same time: `has_one :parent` and `has_many :parents` and it made the trick (I can now call child.parent or child.parents) Btw: I wonder if that is / is not a bug --although I don't this it is. – Marc Rosenfeld Apr 23 '15 at 23:30