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
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]
add_reference :regions, :user, foreign_key: true
*** 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;
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;
@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;
@regions = Region.all.where(user: current_user)
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!