Search code examples
ruby-on-railsruby-on-rails-4devisefriendly-id

Can only create one user profile - Rails 4.2.4


I'm using devise for my user auth and registration. I can register a user no problem. Im also using friendly. My issue is, I can only create one user profile.

The setup...

user.rb:

class User < ActiveRecord::Base
  extend FriendlyId
  friendly_id :name, use: :slugged
  validates :name, uniqueness: true, presence: true
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
 has_one :profile # each user should have just one profile
end

profile.rb:

class Profile < ActiveRecord::Base
 belongs_to :user
end

profiles_controller.rb:

class ProfilesController < ApplicationController
  before_action :authenticate_user!
  before_action :only_current_user

  def new
    # form where a user can fill out their OWN profile
    @user = User.friendly.find( params[:user_id] )
    @profile = Profile.new
  end

  def create
    @user = User.friendly.find( params[:user_id] )
    @profile = @user.build_profile(profile_params)
    if @profile.save # Not saving!!
      flash[:success] = 'Profile Created!'
      redirect_to user_path( params[:user_id] )
    else
      render action: :new # keeps rendering!
    end
  end

  private
    def profile_params
        params.require(:profile).permit(:first_name, :last_name, :avatar,       :job_title, :phone_number, :business_name)
    end
end

Why is it that only one user can create a profile and not others? Is it has to do with the relations?


Solution

  • We use this setup with some of our apps - User -> Profile.

    In short, you should build the profile at User creation. Then you can edit the profile as you need. Your problem of having a Profile.new method is very inefficient...


    #app/models/user.rb
    class User < ActiveRecord::Base
       has_one :profile 
       before_create :build_profile #-> saves blank associated "Profile" object after user create
    end
    

    This will mean that each time a User is created, their corresponding Profile object is also appended to the db.

    This will give you the capacity to edit the profile as required:

    #config/routes.rb
    resources :users, path_names: { edit: "profile", update: "profile" }, only: [:show, :edit, :update]
    

    This will give you the opportunity to use the following:

    #app/controllers/users_controller.rb
    class UsersController < ApplicationController
       before_action :authenticate_user!, only: [:edit, :update]
       before_action :authorize, only: [:edit, :update]
    
       def show
          @user = User.find params[:id]
       end
    
       def edit
          @user = current_user
       end
    
       def update
          @user = current_user
          @user.update user_params
       end
    
       private
    
       def authorize
          id = params[:id]
          redirect_to user_show_path(id) if current_user.id != id #-> authorization
       end
    
       def user_params
          params.require(:user).permit(:x, :y, :z, profile_attributes: [:homepage, :other, :profile, :attributes])
       end
    end
    

    The view/form would be the following:

    #app/views/users/edit.html.erb
    <%= form_for @user do |f| %>
       <%= f.fields_for :profile do |f| %>
           <%= f.text_field :homepage %>
           ...
       <% end %>
       <%= f.submit %>
    <% end %>
    

    In regards your current setup:

    def new
        @profile = current_user.profile.new
    end
    
    def create
        @profile = current_user.profile.new profile_params
        if @profile.save
          redirect_to user_path(params[:id]), notice: "Profile Created!"
        else
          render action: :new 
        end
    end
    
    private
    
    def profile_params 
       params.require(:profile).permit(:x, :y, :z)
    end