Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

default_scope for current_user

I'm trying to implement gem devise to my app. Before that my top model was Album but now it belongs_to :user (from devise).

Then I added to the albums_controller.rb:

before_action :authenticate_user!

It works great - user has to log in from now on. And now I wish him to do everything with albums in his scope. I found that insted of that method:

def index
  @albums = Album.all
end

I could use:

@albums = current_user.albums

and so on for every method I have. I was wondering if there's a better way - to set current_user as default scope for every action/method in the albums controller. Then I found something interesting here. I could add it to Album's model but I'm not sure how best costruct where clause for the current_user. Maybe something like this:

class Album < ActiveRecord::Base
  default_scope where(:user_id => current_user.id)
end

I'm not even sure if it's right direction. I would appreciate your advice.

like image 338
pawel7318 Avatar asked Sep 05 '26 23:09

pawel7318


1 Answers

I'm not sure why you want to do this at all. The best approach is to use the controller to scope your models. This type of thing doesn't belong to the model.

def index
  @albums = current_user.albums
end

If you want to avoid the repetition, create methods to retrieve the object. So instead of this:

def show
  @album = current_user.albums.find(params[:id])
end
def edit
  @album = current_user.albums.find(params[:id])
end
# etc...

You can do this:

def index
  albums
end
def show
  album
end
def update
  if album.update(album_params)
end
# etc...

private
def albums
  @albums ||= current_user.albums
end
def album
  @album ||= current_user.albums.find(params[:id)
end

You can even avoid calling the album method from the action by using a before_filter, but this is not a good way. You always tend to forget to add and remove actions from the filter.

before_action :set_album, only: [:show, :edit, :update, :destroy]
def set_album
  @album ||= current_user.albums.find(params[:id])
end

Then your instance variables are created in one place. As @wacaw suggested, if this appeals to you, you can take it further and use the decent_exposure gem. Personally, I am happy to stop at the controller and use instance methods in my views.

If you have more complex authorisation needs I suggest you use pundit or cancan, although the latter does not appear to be actively maintained.

There is more on decent_exposure on Rails Casts. If you really fancy this type of scoping, look at this Rails Cast on Multitenancy with Scopes. But that is meant for organisations that have many of users, not a single user.

like image 155
Mohamad Avatar answered Sep 07 '26 16:09

Mohamad



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!