Jump to content

The ultimate community for Ruby on Rails developers.


Photo

Devise, users should only see their own stuff

Devise named scopes

  • Please log in to reply
3 replies to this topic

#1 NerdcoreSteve

NerdcoreSteve

    Signalman

  • Members
  • 25 posts

Posted 04 June 2014 - 06:28 PM

I'm creating an app where users have many people and things and people and things belong to users. I'm using Devise for authentication. I want any person or thing created to be associated with the id of the current user and for users to only be able to view, modify, delete their own people and things.

 

I don't yet have an idea for how to do the former. I believe that for the latter I need to use named_scopes but I don't quite understand them enough to figure out how to use them in this context.

 

What's the easiest way to accomplish this?



#2 Jamie

Jamie

    Controller

  • Moderators
  • 140 posts
  • LocationNewcastle, UK

Posted 05 June 2014 - 06:25 PM

The easiest way to do this is when they're signed_in using current_user.whatever in replacement of User.find(....) etc..

 

If you provide some code from your project I'd happily change it so it works.

 

I'd suggest checking out http://railscasts.co...ion-with-cancan and http://railscasts.com/episodes/385-authorization-from-scratch-part-1 which may give you a hand. CanCan doesn't work with Rails 4 out of the box, so be warned.


Rails developer based in Newcastle, UK.


#3 NerdcoreSteve

NerdcoreSteve

    Signalman

  • Members
  • 25 posts

Posted 08 June 2014 - 05:55 PM

A buddy of mine suggested pundit. https://github.com/elabs/pundit

 

I believe all I have to do is modify the code for these two files

 

things_controller.rb

class ThingsController < ApplicationController
  before_action :set_thing, only: [:show, :edit, :update, :destroy]

  # GET /things
  # GET /things.json
  def index
    @things = Thing.all
  end

  # GET /things/1
  # GET /things/1.json
  def show
  end

  # GET /things/new
  def new
    @thing = Thing.new
  end

  # GET /things/1/edit
  def edit
  end

  # POST /things
  # POST /things.json
  def create
    @thing = Thing.new(thing_params)
    @thing.user = current_user
    respond_to do |format|
      if @thing.save
        format.html { redirect_to @thing, notice: 'Thing was successfully created.' }
        format.json { render action: 'show', status: :created, location: @thing }
      else
        format.html { render action: 'new' }
        format.json { render json: @thing.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /things/1
  # PATCH/PUT /things/1.json
  def update
    respond_to do |format|
      if @thing.update(thing_params)
        format.html { redirect_to @thing, notice: 'Thing was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: 'edit' }
        format.json { render json: @thing.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /things/1
  # DELETE /things/1.json
  def destroy
    @thing.destroy
    respond_to do |format|
      format.html { redirect_to things_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_thing
      @thing = Thing.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def thing_params
      params.require(:thing).permit(:name, :description, :status)
    end
end

 

thing_policy.rb

class ThingPolicy < ApplicationPolicy
  class Scope < Struct.new(:user, :scope)
    def resolve
      scope
    end
  end
end

 

Atm I'm trying to figure out what the Scope class and its resolve method do.



#4 NerdcoreSteve

NerdcoreSteve

    Signalman

  • Members
  • 25 posts

Posted 08 June 2014 - 10:24 PM   Best Answer

I think I have it working (I know I should be sure by using rspec so I can be sure it's working. it's on my to-do list :) )

The full code for my nascent app is here:
https://github.com/N...ve/splorf_coach

Users can create either people or things but can only view, edit or destroy their own stuff. In each relevant controller method I put this line at the top

authorize @thing

or

authorize @person

For the index method I do this:

@people = policy_scope(Person)

The scope method in application_policy.rb (both person_policy and thing_policy are blank and inherit all their behavior from application_policy) is:

scope.where(:user_id => user.id)

The show? update? and destroy? methods all call the private belongs_to_user? method which has this one line:

scope.where(:id => record.id).exists?

I'm fairly certain this checks that the record id is the same as the user id.

And that's it. The next thing I need to do is to have nicer-looking pages show up when the user tries to access stuff they ought not to.







Also tagged with one or more of these keywords: Devise, named scopes

1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users