Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple Models in Devise

I'm trying to create multiple models in Devise (using Ruby 2.0, Rails 4). I have searched Stack Overflow and tried Google, but most people end up using inheritance or CanCan.

The problem is that I need two entirely different models to be able to sign up and use my website, in two entirely different ways - one uses email or username to log in, and has all sorts of management abilities (such as seeing graphs of MobileUser usage, etc). The other will only access from a mobile device, uses a phone number to log in, and has a much simpler interface.

I tried to run Devise for both ('rails g devise WebUser' and 'rails g devise MobileUser'). I now have tables and columns for both, but only have routes and a model for the WebUser. I tried manually adding routes and a model for the MobileUser, but nothing works - the model doesn't connect to the table, the routes produce runtime errors ('WebUser does not respond to 'devise' method).

Everything I've read indicates that I can get Devise to work for two models on my one website - how do I implement this?

My routes:

Mailer::Application.routes.draw do
  devise_for :web_users
  # devise_for :mobile_users (doesn't work, so it is commented out)

  resources 'web_users', only: [:show, :index]
  resources 'mobile_users', only: [:show, :index]

  root 'static_pages#home'

  match '/contact',  to: 'static_pages#contact',  via: 'get'
  match '/faq',      to: 'static_pages#faq',      via: 'get'
end
like image 493
steelerose Avatar asked Jul 29 '26 13:07

steelerose


1 Answers

I know this is a very old question but maybe it will help to someone now in 2019 that Devise supports devise_group.

Thins makes really easy to work with multiple Devise models. I have three different devise models as show below:

User.rb

class User < ApplicationRecord
    has_many :messages

    # Include default devise modules. Others available are:
    # :confirmable, :lockable, :timeoutable and :omniauthable
    devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable
end

Organizer.rb

class Organizer < ApplicationRecord
    has_one :organizer_profile, dependent: :destroy, autosave: true, inverse_of: :organizer
    has_many :brochures, dependent: :destroy
    has_many :messages, as: :messageable

    # Include default devise modules. Others available are:
    # :confirmable, :lockable, :timeoutable and :omniauthable
    devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable
end

Sponsor.rb

class Sponsor < ApplicationRecord
    has_one :sponsor_profile, dependent: :destroy, autosave: true, inverse_of: :sponsor
    has_many :sponsorings
    has_many :brochures, through: :sponsorings

    # Include default devise modules. Others available are:
    # :confirmable, :lockable, :timeoutable and :omniauthable
    devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable

    scope :approved, -> { where(approved: true) }

    # Allow saving of attributes on associated records through the parent,
    # :autosave option is automatically enabled on every association
    accepts_nested_attributes_for :sponsor_profile
end

routes.rb

Rails.application.routes.draw do
    # Deviseable resources
    devise_for :organizers, controllers: {registrations: "organizers/registrations"}
    devise_for :sponsors, controllers: {registrations: "sponsors/registrations"}
    devise_for :users

    root "welcome#index"
end

Now I can not use the same authenticate_user!, user_signed_in? or even current_user. So now, how can I know if any user is logged in? We may need to do something like user_signed_in? || organizer_signed_in? || sponsor_signed_in? but that's too much repeating code.

Thanks to devise_group option, we can simplify this workflow!

In your application_controller.rb add this:

class ApplicationController < ActionController::Base
    # Devise working with multiple models.
    # Define authentication filters and accessor helpers for a group of mappings.
    devise_group :member, contains: [:organizer, :sponsor, :user]

    private

    def pundit_user
        # Make Pundit to use whichever Devise model [Organizer, Sponsor, User] as the 'current_user'
        # Just by using the offered helper method from Devise, 'devise_group' feature
        current_member
    end
end

Now you can use universal helpers authenticate_member!, member_signed_in? or even current_member to validate any Devise user when required. Or you can still user separated helper for each type of Devise user as normal.

Hope it could be useful for somebody!

like image 104
alexventuraio Avatar answered Aug 01 '26 04:08

alexventuraio



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!