Serving User Specific Data With Devise and Ruby On Rails
This is an extension of my
previous post here.
Linking Existing Models to New Devise Users
Now since we are doing this later rather than sooner, we have to now create a relationship between any models that need to be User specific or User created and the User. Let’s create a one-to-many relationship in the User model first;
** While not entirely specific to PostGres, the columns in the models may need to be different if you are using a different database!! **
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable has_many :routes
has_many :regions
has_many :workorders
end
The has_many lines are just links to whatever models need to be linked, mine are regions, routes and workorders for a delivery app in this example. They can be anything in yours.
And we are going to have to add a column into these models to link them by creating a migration for each one;
class AddUserToRegion < ActiveRecord::Migration[5.2]
def change
add_reference :regions, :user, foreign_key: true
end
end
*** WARNING !! I had some issues here and I’d hate to pass them on. I first tried the following and wish I hadn’t after getting type errors and such specific to PG DB. The example above is the correct one for me, but beware the ones below;
add_column :regions, :user, :reference
add_column :regions, :user_id, :reference
add_column :regions, :user, :uuid (**This is apparently a PG specifiec reference type? Didn’t work)
And many variations there in until I went back and started again. Use the first one first, if that doesn’t work in the end, try something else.
***
So once each of your models has a migration, run your;
rails db:migrate
as per usual and carry on!
Now we need to change our models to link them to each controller, specifically in the create action. We just need to add a merge call to the params like so;
def create
@region = Region.new(region_params.merge(user: current_user))
…
Devise gives us a couple handy helpers, but the one we are going to use for this is the current_user one. It can be tossed into any chunk of your controllers or .erb files and return the User! How handy! This means that since we created that link between our Users and the associated models, we can give our new record this id as a foreign key. Just repeat for any linked model!
Delivering User Specific Content
Since we’ve got that handy current_user tool, and all our records are linked to a user, all we need to do is change any line that has the word ‘find’ in it in the controllers;
def index
@regions = Region.all.where(user: current_user)
end
This pulls up all the Regions in the database, and only returns the ones where the User column is the same as the current_user! Easy as, eh? You just have to make this quick change to anywhere that does a search, like the index. You might also want to change your
show methods to ensure that Users can’t see other Users data by changing the URL manually.
And its as simple as that! You can now serve up user specific content!
Comments (Coming Soon)