Connecting a User(devise) to their Profile

21 views
Skip to first unread message

Jason Baguio

unread,
Sep 24, 2012, 12:43:27 PM9/24/12
to boston-r...@googlegroups.com
I am using Devise and am trying to allow each user to create 1 profile (they can currently create many).  I am able to send the the newly registered user to the page where they can create a profile, but when the User logs in it will not go to the Profile Show page - the error message is 

(Couldn't find Profile without an ID...
app/controllers/profiles_controller.rb:16:in `show')  

The code (sorted by files) is below…


user.rb

# == Schema Information
#
# Table name: users
#
#  id                     :integer          not null, primary key
#  email                  :string(255)      default(""), not null
#  encrypted_password     :string(255)      default(""), not null
#  reset_password_token   :string(255)
#  reset_password_sent_at :datetime
#  remember_created_at    :datetime
#  sign_in_count          :integer          default(0)
#  current_sign_in_at     :datetime
#  last_sign_in_at        :datetime
#  current_sign_in_ip     :string(255)
#  last_sign_in_ip        :string(255)
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#

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

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me
  # attr_accessible :title, :body

  has_one :profile
end


---------------------------------------

profile.rb

# == Schema Information
#
# Table name: profiles
#
#  id         :integer          not null, primary key
#  user_id    :integer
#  first_name :string(255)
#  last_name  :string(255)
#  created_at :datetime         not null
#  updated_at :datetime         not null
#

class Profile < ActiveRecord::Base
  attr_accessible :first_name, :last_name

  belongs_to :user
end

-------------------------------------------



profiles_controller.rb

class ProfilesController < ApplicationController
  # GET /profiles
  # GET /profiles.json
  def index
    @profiles = Profile.all

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @profiles }
    end
  end

  # GET /profiles/1
  # GET /profiles/1.json
  def show
    @profile = Profile.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @profile }
    end
  end

  # GET /profiles/new
  # GET /profiles/new.json
  def new
    @profile = Profile.new

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @profile }
    end
  end

  # GET /profiles/1/edit
  def edit
    @profile = Profile.find(params[:id])
  end

  # POST /profiles
  # POST /profiles.json
  def create
    @profile = Profile.new(params[:profile])

    respond_to do |format|
      if @profile.save
        format.html { redirect_to @profile, notice: 'Profile was successfully created.' }
        format.json { render json: @profile, status: :created, location: @profile }
      else
        format.html { render action: "new" }
        format.json { render json: @profile.errors, status: :unprocessable_entity }
      end
    end
  end

  # PUT /profiles/1
  # PUT /profiles/1.json
  def update
    @profile = Profile.find(params[:id])

    respond_to do |format|
      if @profile.update_attributes(params[:profile])
        format.html { redirect_to @profile, notice: 'Profile was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @profile.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /profiles/1
  # DELETE /profiles/1.json
  def destroy
    @profile = Profile.find(params[:id])
    @profile.destroy

    respond_to do |format|
      format.html { redirect_to profiles_url }
      format.json { head :no_content }
    end
  end
end


----------------------------------------------



registrations_controller.rb

class RegistrationsController < Devise::RegistrationsController
  protected

  def after_sign_up_path_for(resource)
    request.env['omniauth.origin'] || stored_location_for(resource) || new_profile_path
  end


end

-----------------------------------------

application_controller.rb

class ApplicationController < ActionController::Base
  def after_sign_in_path_for(resource)
    request.env['omniauth.origin'] || stored_location_for(resource) || show_path
  end
end

----------------------------------------



routes.rb

BaseApp::Application.routes.draw do
  resources :profiles

  get "users/show"

  devise_for :users, :controllers => { :registrations => "registrations" }
  resources :users

  match '/show', to: 'profiles#show'


  match '/signup',  to: 'users#new'

  root to: 'static_pages#home'

  match '/', to: 'static_pages#home'

  …
end

Dylan Cashman

unread,
Sep 24, 2012, 3:14:57 PM9/24/12
to boston-r...@googlegroups.com
The problem line here is in your application controller.  You have the following code that describes where to redirect a user to after logging in.
  
    def after_sign_in_path_for(resource)
      request.env['omniauth.origin'] || stored_location_for(resource) || show_path
    end

The problem is the last part, show_path. According to your routes file, show_path maps to the controller action #show in the profiles controller:

    match '/show', to: 'profiles#show'

However, the #show action is an action on a single 'member' of profiles, not on a 'collection' of profiles - it needs to know what profile to show.  So you need to pass that into the named route show_path.  Try this:

    def after_sign_in_path_for(resource)
      request.env['omniauth.origin'] || stored_location_for(resource) || show_path(resource)
    end


In general, stack overflow is a really fantastic resource when you're trying to get into different gems.  Hope this helped though!

-Dylan


--
 
 



--
Dylan Cashman
Annkissam - Mission Driven Systems
www.annkissam.com

One Broadway, 14th Floor
Cambridge, MA 02142
Cell (preferred): 617-999-3634
Office: 617-401-2480, ext. 708
Fax: 617-507-5922

Dylan Cashman

unread,
Sep 24, 2012, 3:17:42 PM9/24/12
to boston-r...@googlegroups.com
Oops - I made a mistake here, I think.  I haven't used this in Devise, but I'm assuming that the 'resource' that gets passed into after_sign_in_path_for is actually a User.  So you want to pass in the profile that belongs to the user, not the user itself.  So you would want:

    def after_sign_in_path_for(resource)
      request.env['omniauth.origin'] || stored_location_for(resource) || show_path(resource.profile)
    end

Note that you'd want to think about if a user could ever hit this if they didn't have a profile, in which case the line would through an error (probably an error like 'couldn't find a profile with id=nil').

Jason Leo Baguio

unread,
Sep 24, 2012, 5:06:36 PM9/24/12
to boston-r...@googlegroups.com
Thank you for your help.

I changed changed the application_controller.rb to:

class ApplicationController < ActionController::Base
  def after_sign_in_path_for(resource)
    request.env['omniauth.origin'] || stored_location_for(resource) || show_path(resource.profile)
  end
end

I signed up a new User and then created a Profile. After I logged out and signed back in it gave me the error:

ActiveRecord::RecordNotFound in ProfilesController#show

Couldn't find Profile without an ID

Any thoughts on the issue?



--
 
 



--
Warmest regards,

Jason L. Baguio

310.880.9059

Jason Leo Baguio

unread,
Sep 24, 2012, 9:47:22 PM9/24/12
to boston-r...@googlegroups.com
Thanks for the StackOverFlow advice...

Here is the link to the one I posted about this issue -

Reply all
Reply to author
Forward
0 new messages