David Sousa
David Sousa

Reputation: 71

Ruby on Rails Polymorphic - Controller and View solution

I have been trying to wrap my mind on a polymorphic structure for my app for a while now, but I can't get it, and I don't know how to solve it.

I have a Supplier model, and a supplier's profile can by a Company OR a Person as listed below.

Supplier Model

class Supplier < ActiveRecord::Base
    belongs_to :profile, :polymorphic => true
    accepts_nested_attributes_for :personable, :allow_destroy => true, :reject_if => :all_blank
end

Company Model

class Company < ActiveRecord::Base
    has_one :supplier, as: :profile
end

Person Model

class Person < ActiveRecord::Base
    has_one :supplier, as: :profile
end

On the Model level (on console) my associations works fine, but I have to those between the two model up front (supplier.profile = Company.new, for example).

What I want is, when a user get to the NEW Supplier action he can select on the form if the Supplier is a Person or a Company, and then something must be done to show the correct fields for. And back on the Create action, handle everything.

I have read many stackoverflow questions and watch Ryan Bates cast #197 and #394.

I'm a Rails enthusiastic, not a programmer.

If someone can point me out to the right direction, I would be thankful.

Regards, David

Upvotes: 3

Views: 249

Answers (1)

agmcleod
agmcleod

Reputation: 13621

This largely depends on the variety of fields you need, and how much data is shared. But if they are very different, I would actually have two separate divs or section on the page that a radio button toggles showing one & hiding the other with javascript. Can do this pretty easily with jquery at the bottom of the view, given it's a default in rails:

 <input type="radio" name="supplier_type" value="person" />
 <input type="radio" name="supplier_type" value="company" />

 <script>
   $('input[name="supplier_type"]').on('change', function () {
      if ($(this).val() === "person") {
        $('.person-form').show();
        $('.company-form').hide();
      }
      else {
        $('.person-form').hide();
        $('.company-form').show();
      }
   });
 </script>

Then inside each of those divs have an entirely separate form that post to different actions. If the data is different enough to require two forms, then it's worth having two different controllers for this.

Now if it's just a couple fields different, or an additional field for one or something. I would have the radio button same as above inside the form_for. Again attach some javascript to show or hide the values. In the controller, use a check against the radio button value to get the params you need:

 supplier_params = params.slice :list, :of, :generic, :params

 if params[:supplier_type] == "company"
   supplier_params.merge! params.slice :company_name
 elsif params[:supplier_type] == "person"
   supplier_params.merge! params.slice :person_name
 end

 Supplier.new supplier_params 

Upvotes: 2

Related Questions