1

My app has three types of profiles:

  • Provider
  • Professional
  • & Seeker

I display these profiles with a User index page to view all profiles.

The problem i am having is that I can see all profiles on the index page but cannot access them unless signed in as that type of profile.

Professional user profiles can see all profiles but can only access professional profiles.

How can I get around this? I can see why I get a NoMethodError in Users#show error as per the below show.html.erb code; however, I can't quite figure out how I can get around it.

Thank you in advance.

#show.html.erb

<div class="row">
<% if current_user.provider %>
    <div class="col-md-3 text-center">
        <%= image_tag @user.provider.avatar.url %>
    </div>
    <div class="col-md-6">
        <h1><%= @user.provider.company_name %></h1>
        <h3>Provider</h3>
        <div class="well provider-description">
            <h3>Description</h3>
            <%= @user.provider.description %>
        </div>
        <div class="well provider-contact">
            <h3>Contact Information</h3>
            <%= @user.provider.company_number %>
            <%= @user.provider.company_email %>
        </div>
    </div>


<% elsif current_user.professional %>
    <div class="col-md-3 text-center">
        <%= image_tag @user.professional.avatar.url %>
    </div>
    <div class="col-md-6">
        <h1><%= @user.professional.first_name %> <%= @user.professional.last_name %></h1>
        <h3>Professional</h3>
        <div class="well professional-description">
            <h3>Description</h3>
            <%= @user.professional.description %>
        </div>
        <div class="well professional-contact">
            <h3>Contact Information</h3>
            <%= @user.professional.phone_number %>
            <%= @user.professional.contact_email %>
        </div>
    </div> 

<% elsif current_user.seeker %> 
    <div class="col-md-3 text-center">
        <%= image_tag @user.seeker.avatar.url %>
    </div>
    <div class="col-md-6">
        <h1><%= @user.seeker.first_name %> <%= @user.seeker.last_name %></h1>
        <h3>Seeker</h3>  
          <div class="well seeker-description">
              <h3>Description</h3>
              <%= @user.seeker.description %>
          </div>
          <div class="well seeker-contact">
            <h3>Contact Information</h3>  
            <%= @user.seeker.phone_number %><br/>
            <%= @user.seeker.contact_email %><br/>
         </div>
    </div>
<% end %> 

#index.html.erb
    <div class="row">
<div class="col-md-8 col-md-offset-2">
<ul class="list-unstyled">
  <% @users.each do |user| %>
    <% if user.provider %>
    <li>
      <div class="well row <%= cycle('white-bg', '') %>">
        <div class="col-sm-4 text-center">
          <% if user.provider.avatar %>
            <%= link_to user do %>
              <%= image_tag user.provider.avatar.url(:thumb), class: 'user-index-avatar' %>
            <% end %>
          <% end %>
        </div>
        <div>
          <%= link_to user do %>
            <h2><%= user.provider.company_name %></h2>
          <% end %>
          <p><%= user.provider.description %>
        </div>
      </div>
    </li>
    <% elsif user.professional %>
    <li>
      <div class="well row <%= cycle('white-bg', '') %>">
        <div class="col-sm-4 text-center">
          <% if user.professional.avatar %>
            <%= link_to user do %>
              <%= image_tag user.professional.avatar.url(:thumb), class: 'user-index-avatar' %>
            <% end %>
          <% end %>
        </div>
        <div>
          <%= link_to user do %>
            <h2><%= user.professional.first_name %><%= user.professional.last_name %></h2>
          <% end %>
          <p><%= user.professional.description %>
        </div>
      </div>
    </li>
    <% elsif user.seeker %>
    <li>
      <div class="well row <%= cycle('white-bg', '') %>">
        <div class="col-sm-4 text-center">
          <% if user.seeker.avatar %>
            <%= link_to user do %>
              <%= image_tag user.seeker.avatar.url(:thumb), class: 'user-index-avatar' %>
            <% end %>
          <% end %>
        </div>
        <div>
          <%= link_to user do %>
            <h2><%= user.seeker.first_name %><%= user.seeker.last_name %></h2>
          <% end %>
          <p><%= user.seeker.description %>
        </div>            
      </div>
    </li>
    <% end %>
  <% end %>
</ul>

#users_controller
class UsersController < ApplicationController
before_action :authenticate_user!  

  def show
    @user = User.find( params[:id] )
  end

  def index
    @users = User.includes(:provider, :professional, :seeker)
  end


end

#user.rb (model)
 class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable

  has_one :provider
  has_one :professional
  has_one :seeker
  end
L.P
  • 19
  • 3
  • You will have to remove any references to current_user from the view as current_user is defined only after successful login. – Alok Swain Feb 03 '16 at 06:00
  • Where do u get `NoMethodError` ? – Harry Bomrah Feb 03 '16 at 06:06
  • when accessing profiles through the User index view. The show fucntion works perfectly fine everywhere else. I can see all profiles and access profiles of the same profile type , but when i attempt to access a different profile type i get the error because the current user is not of that profile type – L.P Feb 03 '16 at 06:08
  • you want to access index without signing in? is that what you wanted to do? – mrvncaragay Feb 03 '16 at 06:39
  • 2
    You are displaying all types of profiles in the index, whereas the current user should only see the appropriate type. For example, you should have "if user.professional && current_user.professional" instead of only the first. I would also refactor all the duplicate code (for example by using a partial), but that is a whole other subject. – Peter de Ridder Feb 03 '16 at 06:57

4 Answers4

0

I'm not exactly sure what your desired behaviour is; however, you may want to try changing the following line:

<% elsif user.seeker %>

to this:

<% elsif current_user.seeker %>

You might be getting the NoMethodError because there is no user.seeker method available.

Andrew Hendrie
  • 6,205
  • 4
  • 40
  • 71
  • Each user can have one of three profiles .... Everything is working fine except for the index which for example if I'm using a professional I can see all providers, professionals and seekers but can only access other professionals – L.P Feb 03 '16 at 07:02
  • that's because of your conditional logic. Remove the `<% if current_user.professional %>` and `<% if current_user.provider %>` and that should be fine? – Andrew Hendrie Feb 03 '16 at 07:04
  • also - not sure why you're using the :has_one association in your user model – Andrew Hendrie Feb 03 '16 at 07:05
0

I think the problem is before_action :authenticate_user! it authenticate all the action you define inside your User controller meaning it wants the user to sign in.

try changing it to: before_action :authenticate_user!, except: [:index] so it doesn't require the user to sign in.

If i misunderstood your question, ignore this answer.

mrvncaragay
  • 1,240
  • 1
  • 8
  • 15
0

The error has nothing to do with current_user - you're evaluating if current_user.professional, and then calling @user.professional:

<% elsif current_user.professional %>
  <%= image_tag @user.professional.avatar.url %>

The error - which you haven't posted - will likely be that @user doesn't have a .professional object associated with it. Maybe I'm wrong, but your pattern just doesn't look very efficient to me.

--

How can I get around this?

Sounds like you'd benefit from implementing authorization.

I'd strongly recommend refactoring your User model:

#app/models/user.rb
class User < ActiveRecord::Base
   has_one :profile
   delegate :profile_type, :professional?, :seeker?, :provider?, to: :profile
end

#app/models/profile.rb
class Profile < ActiveRecord::Base
   belongs_to :user
   enum profile_type: [:provider, :professional, :seeker] #-> requires "profile_type" int column
end

You mention the user can be one of the profile types. If you used the enum above, you'd get the following methods:

current_user.provider?
current_user.professional? 
current_user.seeker?

The issue you have now is that user has_one :professional does nothing to define whether the user is a professional etc -- it just gives you 3 potential options on whether the user is an x.

You're trying to evaluate @user.professional and it's just not working. You need to use the following (cancancan):

#Gemfile
gem "cancancan"

#app/models/ability.rb
class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    if user
      can :read, User do |user_eval|
         user_eval.profile_type == user.profile_type
      end 
    end
  end
end

#app/controllers/users_controller.rb
class UsersController < ApplicationController
   load_and_authorize_resource
end

#app/views/users/index.html.erb
<%= render @users %>

#app/views/users/show.html.erb
<%= render @user %>

#app/views/users/_user.html.erb
<% if can? :read, user %>
   ...
<% end %>

Good ref

Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
0

Update: On the user/show.html.erb i removed the following,

<% if current_user.provider %>
......
<% if current_user.professional %>
......
<% if current_user.seeker %>
......

and replaced with,

<% if @user.provider %>
......
<% elsif @user.professional %>
......
<% elsif @user.seeker %>
......

the application is functioning exactly how i want it to now. does anyone see a problem with this?? besides to repeat code I am going to tidy up with some partials. thank you for your patience i am new to rails.

L.P
  • 19
  • 3