user3193550
user3193550

Reputation: 21

Two very different user models in Devise

I have two different types of users in my application that uses Devise for authentication using Rails 4 but they have very different fields. One is a Buyer and the other is a Seller. The Buyer must have location and payment information while the Seller doesn't. Initially I thought it would be a good idea to create two separate Devise models but there has to be a better way. I thought about keeping it all in the same table and serializing the Buyer's payment data.

What would be a good solution?

Upvotes: 2

Views: 1573

Answers (2)

n0denine
n0denine

Reputation: 341

Honestly I use polymorphic relations instead. I keep my User model pretty much for authentication, then make two new models (Buyer and Seller) with the fields they don't share in common. This is very close to BroiSate's method shown above.

Example

class User < ActiveRecord::Base  
  belongs_to :authenticatable, polymorphic: true
end


class Buyer < ActiveRecord::Base  
  has_one :user, as: :authenticatable
  # Add buyer specific fields to this table
end

class Seller < ActiveRecord::Base   
  has_one :user, as: :authenticatable
  # Add seller specific fields to this table
end

Upvotes: 0

BroiSatse
BroiSatse

Reputation: 44715

Have a look at STI - in short you create one base model called User and then two subclasses User::Buyer and User::Seller (No need for namespacing, but it is recommended). Both models are stored in same table and everything applied to User model will affect both those classes. More about STI here

UPDATE:

If you don't want to have a number of empty table cells, you might use 1-1 association to keep all class-specific details. You can also add a wrapper to encapsulate it completely. It could look like this:

class User < ActiveRecord::Base
  belongs_to :details, polymorphic: true

  def method_missing(method, *args)
    return details.send(method, *args) if details.respond_to? method
    super
  end
end

class BuyerDetails < ActiveRecord::Base
  has_one :user, as: :details

  # buyer_attribute column
end

class SellerDetails < ActiveRecord::Base
  has_one :user, as: details

  #seller_attribute
end

You can then mix it with STI:

class User::Buyer < User
  def initialize(*args)
    super
    details = BuyerDetails.new
  end
end

class User::Seller < User
  def initialize(*args)
    super
    details = SelerDetails.new
  end
end

Then you can simple work using:

user = User::Buyer.new
user.buyer_attribute       #=> nil
user.seller_attribute      #=> NoMethod error!

Note: You will need to have details_type string column on your User model as well as details_id for polymorphic association to work. For STI, you will need another column type.

Upvotes: 1

Related Questions