Filtering a Party/Role CRUD based on relationship type, using the same controller

Hi there everyone,

I have a tradicional “Party/Role Model” in my app:

 - *Party*  ( an organization, a person, etc)
 - *PartyRelationship* ( One or more relationships between parties.

They can have relationship types: customer, supplier, reseller,
etc)

However, I need to create two “shorcuts” :

  • one to customers CRUD and
  • one to suppliers CRUD , even if they´re actually both “parties”
    behind the scenes
    .

I´d like to show on my navigation menu:

  1. A “Customers” link routing to the customer crud. (Actually, the
    party
    CRUD, knowing ahead it would be dealing with a “customer” party
    relationship)
  2. A “Supplier” link routing to the supplier crud. (Actually, the same
    party CRUD, knowing ahead it would be dealing with a “customer” party
    relationship)

These links will also need to filter the parties being listed, based on
their relationship types.

What´s the recommended approach to this?

Thanks in advance!

Regard.
Leandro

Hi Leandro,

I would go for two controllers here. A CustomersController and a
SuppliersController. You would just need to handle the Party model
appropriately in each one of those controllers.

Best regards,
// Marco

On Sat, Aug 22, 2015 at 10:59 PM Leandro França <

Sorry… I am addressing Marco… :wink:
Liz

Sorry, Leandro, but I do not agree with you. However I may not
understand
what you have offered. Just seems to me that the solution is
model-drive. Where in the Party and PartyRelationship controller
aspects
of CRUD can be managed in building respective association calls. Like
<<
to create, .destroy to delete, etc… Maybe at a maintenance level
Role/Customer and CustomerType/Supplier Controllers would be appropriate

(Forgive I am writing quickly)

I would suggest a model structure like the following:

class Party < ActiveRecord::Base
has_many :party_relationships
has_many :roles
end

class Role < ActiveRecord::Base
belongs_to :party_relationship
end

class CustomerType < ActiveRecord::Base
belongs_to :party_relationship
end

class PartyRelationship < ActiveRecord::Base
belongs_to :party

customer, supplier, reseller

scope :customer, -> { where(customer_type_id: 1) } ## id values are
specific as to new table/record creation and to my seed below
scope :supplier, -> { where(customer_type_id: 2) }
scope :reseller, -> { where(customer_type_id: 3) }
has_many :customer_types
end

Offering seed.rb

Assuming you are starting anew

unless Party.count > 0
Party.create!(name: ‘Person#1’, role_id: 2 ) ## id: 1
Party.create!(name: ‘Person#2’, role_id: 2 ) ## id: 2
Party.create!(name: ‘Vendor#1’, role_id: 3 ) ## id: 3
Party.create!(name: ‘Vendor#2’, role_id: 3 ) ## id: 4
Party.create!(name: ‘Company#1’, role_id: 1 ) ## id: 5
Party.create!(name: ‘Company#2’, role_id: 1 ) ## id: 6
end

unless PartyRelationship.count > 0
PartyRelationship.create!(party_id: 1, customer_type_id: 1 ) ## Person
1
is an Person that is a customer
PartyRelationship.create!(party_id: 2, customer_type_id: 2 ) ## Person
2
is an Person that is a supplier
PartyRelationship.create!(party_id: 3, customer_type_id: 3 ) ## Vendor
1
is an Companu that is a reseller
PartyRelationship.create!(party_id: 4, customer_type_id: 1 ) ## Vendor
2
is an company that is a customer
PartyRelationship.create!(party_id: 5, customer_type_id: 2 ) ## Company
1
is an organization that is a supplier
PartyRelationship.create!(party_id: 6, customer_type_id: 3 ) ## Company
2
is an organization that is a reselller
end

PartyRelationship.create!(party_id: 1, customer_type_id: 2 ) ## Person
1
is an Person that is a supplier

unless Role.count > 0
Role.create!(role_name: ‘Organization’)
Role.create!(role_name: ‘Person’)
Role.create!(role_name: ‘Company’)
end

unless CustomerType.count > 0
CustomerType.create!(name: ‘customer’)
CustomerType.create!(name: ‘supplier’)
CustomerType.create!(name: ‘reseller’)
end

And migration:

create_table “parties”, force: :cascade do |t|
t.integer “role_id”, limit: 4
t.string “name”, limit: 255
t.datetime “created_at”, null: false
t.datetime “updated_at”, null: false
end

create_table “party_relationships”, force: :cascade do |t|
t.integer “party_id”, limit: 4
t.integer “customer_type_id”, limit: 4
t.datetime “created_at”, null: false
t.datetime “updated_at”, null: false
end

create_table “roles”, force: :cascade do |t|
t.string “role_name”, limit: 255
t.datetime “created_at”, null: false
t.datetime “updated_at”, null: false
end

create_table “customer_types”, force: :cascade do |t|
t.string “name”, limit: 255
t.datetime “created_at”, null: false
t.datetime “updated_at”, null: false
end

Then you should be able to make association calls like

Party.find(1).party_relationships.customer

There may be many errors here, but the spirit is that one can perform
CRUD
given the Party and PartyRelationship model through their respective
controllers… FORGIVE me if I am wrong.

Liz

Hey Liz and Marco, thanks a lot for your inputs.

I´ll provide a few more details from what I already have and some needs:

  • A Party is an Organization or a Person. One of the parties is also
    defined as the “proprietary party”. It´s the organization actually
    running
    the app.
  • A Party have many relationships with other parties and there are
    many
    relationthip types: supplier, customer, employee, reseller, etc.
    • “John is employee at ACME CORP”
    • “Mary is employee at ACME CORP”
    • “ACME-CA is reseller from ACME CORP”
    • “XYZ is customer from ACME CORP”
    • PWL is customer from ACME CORP"

What I already have:

  • A STI based model, where a Party have the types: Organization and
    Person:

Party

class Party < ActiveRecord::Base
has_many :party_relationships
has_many :second_parties, :through => :party_relationships
scope :organizations, → { where(type: ‘Organization’) }
scope :people, → { where(type: ‘Person’) }

   def self.types
     %w(Organization Person)
   endend

Organization

class Organization < Partyend

Person

class Person < Partyend

  • A Party Relationship Model:

PartRelationship

class PartyRelationship < ActiveRecord::Base
belongs_to :party, :class_name=>‘Party’
belongs_to :second_party, :class_name => ‘Party’
enum relation: [ :customer, :supplier, :employee, :reseller ]end

  • I currently have on PartyController who deals with both party
    subtypes. What I need is just a “shorcut” to the crud model.
  • I ended up using these routes below, pointing to the same party
    controller and dealing with some conditions based on
    params[:relation]
    inside controller to know what to do:
  • resources :customers, controller: ‘parties’, relation: ‘customer’*
  • resources :suppliers, controller: ‘parties’, relation: ‘supplier’*

2015-08-23 18:44 GMT-03:00 Elizabeth McGurty [email protected]:

Your welcome… Good luck in your endeavors, and thanks for squandering
my
time with incomplete information…

Hi Elizabeth,

I did not want to spend your or anyone else’s time.
I only recognized that more information would help after I saw your
first
answer.
I´m sorry about that.

Anyway, I´m open to criticism and I´ll try to improve next time.

Regards.

2015-08-24 14:33 GMT-03:00 Elizabeth McGurty [email protected]:

ok… I do not know what a ‘STI based model’ is. And I do not see your
SecondParty class here. Pretty sure the matter of second-party can be
managed in Party with a field like is_second_party. Don’t understand
necessity of Classes Organization and Person

Addressing from what I understand:

class Party < ActiveRecord::Base
has_many :party_relationships

scope :organizations, → { where(type: ‘Organization’) } ## Haven’t
tested
scope :people, → { where(type: ‘Person’) } ## Haven’t tested

one to many party to types

SQL table parties should contain field ‘types’

rails generate migration add_type_to_parties type:string

rake db:migrate

<%= form_for @party … do |f| %>

<%= f.collection_select :type, Party::TYPES, :to_s, :humanize %>

TYPES = %w[Organization Person]

end

class PartyRelationship < ActiveRecord::Base
belongs_to :party

ActiveRecord::Enum

Declare an enum attribute where the values map to integers in the

database, but can be queried by name. So table PartyRelationship must

contain field relation

enum relation: [ :customer, :supplier, :employee, :reseller ]

eg, corresponding database values : 1:customer, 2:supplier,

3:employee, 4:reseller

With regard to CRUD, obviously the enum is hard-coded. Pretty

sure
that all will need to be done manually and very carefully as to respect
values

already stored on the database

With regard to PartyRelationship Controller, record using

relation,
you will have to be mindful of your enum structure, eg, order

Find

irb(main):003:0> PartyRelationship.find(1).relation

PartyRelationship Load (1.0ms) SELECT party_relationships.*

FROM
party_relationships WHERE party_relationships.id = 1 LIMIT 1

=> “supplier”

update

irb(main):008:0> PartyRelationship.find(1).update(relation: 3)

PartyRelationship Load (0.0ms) SELECT party_relationships.*

FROM
party_relationships WHERE party_relationships.id = 1 LIMIT 1

(0.0ms) BEGIN

SQL (13.0ms) UPDATE party_relationships SET relation = 3,

updated_at = ‘2015-08-25 14:00:58’ WHERE party_relationships.id =
1

(1.0ms) COMMIT

=> true

end

Hope this helps…

Check out ‘super’ on inheritance from Parent Model Class.

Thanks Elizabeth,

From STI, I mean I´m using Single Table Inheritance
http://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html ,
since
Person and Organization have many fields in common (name, addresses,
etc) ,
but some specific behaviors to be implemented in the future.
The SecondParty just maps the related party association on
PartyRelationship. Its is self-referential association
http://guides.rubyonrails.org/association_basics.html#self-joins.

I´ll check your suggestions on enum field and relationship controller.
Looks like the´ll help.

Thanks again,
Leandro

2015-08-25 12:19 GMT-03:00 Elizabeth McGurty [email protected]: