Moh
Moh

Reputation: 259

spree customizing the create user sessions action

I added inheritance to my Spree::User model class with STI. I have a :type column which can be (Spree::Guest, Spree::Writer, or Spree::Reader).

In my authentication in the admin side I want to authenticate only writer and reader. What would be the best option to solve this issue?

I tried to override the create action to something like:

def create
  authenticate_spree_user!

  if spree_user_signed_in? && (spree_current_user.role?(:writer) || spree_current_user.role?(:reader))
    respond_to do |format|
      format.html {
        flash[:success] = Spree.t(:logged_in_succesfully)
        redirect_back_or_default(after_sign_in_path_for(spree_current_user))
      }
      format.js {
        user = resource.record
        render :json => {:ship_address => user.ship_address, :bill_address => user.bill_address}.to_json
      }
    end
  else
    flash.now[:error] = t('devise.failure.invalid')
    render :new
  end
end

In this case when trying to authenticate with user of type :guest, it redirects to the new action with invalid failure message (ok) but somehow the user get authenticated (nok).

Upvotes: 0

Views: 1357

Answers (1)

zrl3dx
zrl3dx

Reputation: 7869

I don't think that is a good way to solve that, controller should be just a controller. I'd rather go that way:

Spree uses cancancan (or cancan in older branches) for authorization and that's how Spree implements that. I don't know why you want that STI solution - I would simply create new custom Spree::Role for that but as I said I don't know why you chose STI way - that should work fine too. Anyway, you can either just add a decorator for that ability file with additional checks for something like user.is_a? Spree::Guest and so on or register new abilities via register_ability - something like this.

Most important part of third link (or in case it goes off):

# create a file under app/models (or lib/) to define your abilities (in this example I protect only the HostAppCoolPage model):

Spree::Ability.register_ability MyAppAbility

class MyAppAbility
  include CanCan::Ability

  def initialize(user)
    if user.has_role?('admin')
      can manage, :host_app_cool_pages
    end
  end

end

Personally I would go with decorator option (code seems a bit unclear but is cleaner when it comes to determine what can be managed by who - remember about abilities precedence) but it is up to you. If you have any specific questions feel free to ask, I will help if I will be able to.

Edit: so if you want to disable authentication for some users maybe just leverage existing Devise methods? Something like this(in your user model):

def active_for_authentication?
  super && self.am_i_not_a_guest? # check here if user is a Guest or not
end

def inactive_message
  self.am_i_not_a_guest? ? Spree.t('devise.failure.invalid') : super # just make sure you get proper messages if you are using that module in your app
end

Upvotes: 1

Related Questions