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

63 views
Skip to first unread message

Leandro França

unread,
Aug 22, 2015, 4:59:00 PM8/22/15
to Ruby on Rails: Talk
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


Marco Antonio Almeida

unread,
Aug 23, 2015, 4:40:25 PM8/23/15
to Ruby on Rails: Talk
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

--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
To post to this group, send email to rubyonra...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/8d2660cd-1d4a-47b7-9425-c903c56a4bf6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Elizabeth McGurty

unread,
Aug 23, 2015, 5:44:51 PM8/23/15
to Ruby on Rails: Talk
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

Elizabeth McGurty

unread,
Aug 23, 2015, 5:58:23 PM8/23/15
to Ruby on Rails: Talk
Sorry... I am addressing Marco.. ;)
Liz

Leandro França

unread,
Aug 24, 2015, 12:59:45 PM8/24/15
to rubyonra...@googlegroups.com
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)
        end
    end

    Organization

    class Organization < Party
    end

    Person

    class Person < Party
    end

  • 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'



Message has been deleted

Leandro França

unread,
Aug 24, 2015, 2:07:30 PM8/24/15
to Elizabeth McGurty, Ruby on Rails: Talk
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 <emcg...@gmail.com>:
Your welcome.... Good luck in your endeavors, and thanks for squandering my time with incomplete information...



Elizabeth McGurty

unread,
Aug 25, 2015, 11:19:50 AM8/25/15
to Ruby on Rails: Talk, leandro...@pobox.com
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
   ## http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html
   ## 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...


Leandro França

unread,
Aug 25, 2015, 10:48:57 PM8/25/15
to Elizabeth McGurty, Ruby on Rails: Talk
Thanks Elizabeth,

From STI, I mean I´m using Single Table Inheritance , 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.

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

Thanks again,
Leandro

Elizabeth McGurty

unread,
Aug 26, 2015, 7:10:17 PM8/26/15
to Ruby on Rails: Talk, emcg...@gmail.com, leandro...@pobox.com
Check out 'super' on inheritance from Parent Model Class.
Reply all
Reply to author
Forward
0 new messages