1

I want to create a polymorphic friendship/network system.

For example

User can request or be requester to join multiple models like:

  • Company
  • Project
  • Group
  • Contacts(friends)

Some will be one to many e.g. a user is employed by one company but a company has many employees.

Others many to many e.g a user has many projects a project has many users

The relationships aren't to difficult to create using active recorded. The middle step, requesting(invitations) that has me baffled.

After bit of messing around this is what I came up with.

The example below will allow me to make requests from a profile(user) to a multiple models polymophically(Is that even a word?), including the profile model itself.

This is a sample of how the Controller could work.

@company = Company.find(params[:id])
@request = @company.requests.create!(status: "pending").build_profile 
@request.profile = current_user

How could I make @company more dynamic, say if it where a profile(user) requesting to join a project or a profile(user) requests to be friends with another profile(user)?

So I have solved this little problem I think with the following code in my controller.

requests_controller.rb

class RequestsController < ApplicationController
  before_filter :load_requestable

  def new
    @request = @requestable.requests.new
  end

  def create
    @request = @requestable.requests.new(params[:status])
  if @request.save
    redirect_to @requestable, notice: "Request sent."
  else
    render :new
  end
end

private

def load_resquestable
    resource, id = requests.path.split('/')[1, 2]
    @requestable = resource.singularize.classify.constantize.find(id)
end 

[sticking point] Now I'm trying to get the request button in my view happening and am getting the following error

undefined method `requests_path' for #<#<Class:0x007fe8b26667f8>:0x007fe8b26f40d0> 

Extracted source (around line #1):

1: <%= form_for [@requestsable, @request] do |f| %>
2:   <div class="field">
3:     <%= f.text_area :content, rows: 8 %>
4:   </div> 

Here is the code for the views

companies/show.html.erb

<%= @company.name %>
<% render 'requests/form' %>

requests/_form.html.erb

<%= form_for [@requestsable, @request] do |f| %>
  <div class="field">
    <%= f.text_area :content, rows: 8 %>
  </div>
  <div class="actions">
   <%= f.submit %>
  </div>
<% end %>

_models

profile.rb

class Profile < ActiveRecord::Base
  belongs_to :user
  belongs_to :company
  has_many :requests
  has_many :requested, as: :requestable

  attr_accessible :first_name, :last_name


  validates :first_name, presence: true
  validates :last_name, presence: true

end

request.rb

class Request < ActiveRecord::Base

   attr_accessible :status
   belongs_to :requestable , polymorphic: true
   belongs_to :profile

end

company.rb

class Company < ActiveRecord::Base
   has_many :employees, 
    :foreign_key => 'company_id', 
    :class_name => "Profile"

   has_many :requests, as: :requestable


  attr_accessible :name
  validates :name,  presence: true, length: { maximum: 50 }, uniqueness: true

end
Aaron Dufall
  • 1,177
  • 10
  • 34

2 Answers2

1

I think the it is not the User model that must be polymorphic.

What you can do is introduce another model UserRequest which will be a one to may association from User to UserRequest.

Then you can do the following:

class User < ActiveRecord::Base
  has_many :user_requests
  has_many :project_users
  has_many :projects, :through => :project_users
  has_many :group_users
  has_many :groups, :through => group_users
  has_many :contact_users
  has_many :contacts, :through => :contact_users
  belongs_to :company
end

And the RequestUser mdoel can keep a track of, what entities has a user requested for, also the RequestUser model will have a polymorphic association with Project, Company, Group and Contact models.

This way you can always have control over which user has request for which particular entity, and will also ease out the computations to be carried out.

Hope this architecture works for you. Let me know if you need any more assistance.

EDIT:

You can also implement a state change mechanism in the RequestUser model to check on the status of the request posted by a user.

Rohit
  • 5,631
  • 4
  • 31
  • 59
  • I have had similar thoughs but I feel that the fact that there is the repeated use of model_users it not very DRY. – Aaron Dufall Jun 28 '12 at 10:10
  • You can remove those models by using the `has_and_belongs_to_many` association. But personally I feel a join model(has_many through) association in between gives you a better control over both the associated models. You can refer this link here http://stackoverflow.com/questions/2780798/has-and-belongs-to-many-vs-has-many-through for more details – Rohit Jun 28 '12 at 10:24
-1

Yes of course AR supports polymorphic relations, and here's a link to RoR Guides.

http://guides.rubyonrails.org/association_basics.html

pkurek
  • 606
  • 4
  • 13
  • I think OP is aware that polymorphic relations exist in AR. Linking to the specific section instead of "here are AR associations" would have been nice and it'd show that this page probably won't help OP with their specific issue – AxelTheGerman Nov 19 '21 at 19:34