I am building a Rails marketplace application using TDD. I would like to get advice on the way in which I have built the User
associated Profile
associations and way in which these are then handled in the controllers.
User model
class User < ActiveRecord::Base
has_one :profile, dependent: :destroy
has_many :listings, dependent: :destroy
has_many :watches, dependent: :destroy
has_many :watched_listings, -> { uniq }, :through => :watches, dependent: :destroy
# Include default devise modules. Others available are:
acts_as_messageable
def mailboxer_email(object)
email
end
def self.search(search)
where("email ILIKE ?", "%#{search}%")
end
after_create :build_profile
end
Profile model
class Profile < ActiveRecord::Base
belongs_to :user
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
end
Users controller
class UsersController < ApplicationController
def index
@users = User.all
if params[:search]
@users = User.search(params[:search]).order("created_at DESC")
else
@users = User.all.order('created_at DESC')
end
end
def show
@user = User.find(params[:id])
end
def watchlist
@watched_listings = current_user.watched_listings.all
end
end
Profiles controller
class ProfilesController < ApplicationController
before_filter :authenticate_user!, :only [:edit, :update]
before_filter :correct_user, :only [:edit, :update]
def show
@profile = Profile.find_by(user_id: params[:user_id])
end
def edit
@profile = Profile.find_by user_id: current_user.id
end
def update
@profile = Profile.find_by user_id: current_user.id
if @profile.update(profile_params)
flash[:notices] = ["Your profile was successfully updated"]
render 'show'
else
flash[:notices] = ["Your profile could not be updated"]
render 'edit'
end
end
private
def profile_params
params.require(:profile).permit(:city, :country, :avatar)
end
def correct_user
@profile = Profile.find_by(user_id: params[:user_id])
redirect_to(root_path) unless current_user?(@profile)
end
end
I have also defined:
Profiles helper
module ProfilesHelper
def current_user?(user)
user == current_user
end
end
Within my Application Controller:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def after_sign_in_path_for(resource)
edit_user_profile_path(resource)
end
def after_sign_up_path_for(resource)
edit_user_profile_path(resource)
end
end
I'm very keen to get any feedback on:
If the use of the
after_create :build_profile
is appropriate. Does this violate SRP principles by making the user model responsible for the creation of a profile?The best way to validate the correct user in the profile controller - to enforce whether a user can edit a profile or not.
Mainly whether it is required that I be finding profiles by
Profile.find_by(user_id: params[:user_id])
rather than by aProfile
ID.Any other improvements to the code!
I have RSpec and Capybara tests to back this here.