3
\$\begingroup\$

I'm running into an issue while playing around with some models in a Rails app. Namely issues of the polymorphic variety. I think I may have solved it, more or less looking for an approval.

I have the following models in my app:

class Issue < ActiveRecord::Base
  belongs_to :creator, class_name: 'User', foreign_key: 'creator_id'
  has_many :user_issues
  has_many :helpers, through: :user_issues, source: :users
end

class User < ActiveRecord::Base
  has_many :issues, foreign_key: 'creator_id'
  has_many :user_issues
  has_many :issues_helped, through: :user_issues, source: :issues
end

class UserIssues < ActiveRecord::Base
  belongs_to :user
  belongs_to :issue
end

Scenario:

UserOne creates an issue and is saved as the IssueOne's creator. UserTwo decides to help UserOne and joins/follows IssueOne (has_many :issues_helped declared in the model) and is allowed to post a comment. UserTwo is a helper in this instance.

Well, UserTwo is now in need of some help and creates a new issue of his own. UserTwo is the creator of IssueTwo. UserOne decides to help out his new buddy UserTwo on his issue and joins/follows IssueTwo, and is allowed to post a comment. UserOne has now become a helper in this instance.

  1. Is this the Rails way of doing it? This is the best solution I have come up with, so far.

  2. Am I misusing the power of has_many :x, through: :y, source: :z?

\$\endgroup\$
1
\$\begingroup\$

The foreign key is not needed for belongs_to :creator since rails will infer this foreign key from the association name. The source has to point to the relation for UserIssue (you pluralized this name but active record class names should be singularized in most cases) so instead of source: users, and source: issues, you want source: user, source: issue.

Another way you could have accomplished the same thing, which IMO is a bit cleaner is the following:

class Issue < ActiveRecord::Base
  belongs_to :creator, class_name: 'User'
  has_many :helpings, :foreign_key => 'issue_helped_id'
  has_many :helpers, through: :helpings
end

class User < ActiveRecord::Base
  has_many :issues, foreign_key: 'creator_id'
  has_many :helpings, foreign_key: 'helper_id'
  has_many :issues_helped, through: :helpings
end

class Helping < ActiveRecord::Base
  belongs_to :helper, class_name: 'User'
  belongs_to :issue_helped, class_name: 'Issue'
end

It also gives the join table a more descriptive name. For this to work you need to modify your inflections since rails cannot pluralize issue_helped or singularize issues_helped out of the box. To do this, in config/initializers/inflections.rb add:

ActiveSupport::Inflector.inflections do |inflect|
  inflect.plural 'issue_helped', 'issues_helped'
  inflect.singular 'issues_helped', 'issue_helped'
end
\$\endgroup\$
0
\$\begingroup\$

I can't for the life of me come up with a name but your code could definitely benefit so I'm going to use an analogous example of how one would use comments(assume User exists -- perhaps making use of devise or similar framework)

   class Image < ActiveRecord::Base
      belongs_to :user
      include Commentable
    end 

   class Post < ActiveRecord::Base
      belongs_to :user
      include Commentable 
   end 
   class Comments < Active::Record::Base
      belongs_to :commentable, :polymorphic => true 
      belongs_to :user
   end


  module Commentable 
     extend ActiveSupport::Concern

     included do
       has_many :comments, :as => :commentable
       accepts_nested_attributes_for :comments #allows for you to do @image.comments  
     end
  end

Now you've DRY'd up your code and it looks clean...and if you wanted to make a Video resource -- you can do the same and it looks clean. I'm not sure if it's premature in your case, I'm just learning myself and figured I'd share what I'm learning. <3

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Welcome to Code Review! We're looking for extended answers that are more than just a link. \$\endgroup\$ – mleyfman Aug 22 '14 at 20:01
  • \$\begingroup\$ I've edited it to be more concrete and included an example...PS a code editor would be nice on StackExchange :-) \$\endgroup\$ – robbyoconnor Aug 22 '14 at 20:31
  • \$\begingroup\$ You could in your example make it Helpable but putting code that will be repeated potentially in a concern is good practice \$\endgroup\$ – robbyoconnor Aug 22 '14 at 20:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.