Arjun Bharadwaj
Arjun Bharadwaj

Reputation: 41

Rails: NoMethodError on creating has_one association with devise model

I am a complete beginner in Rails as such and I am trying to build a page to add extra profile data once the user logs in.

I am using Devise for authentication purposes and that works fine. I get this error and I have been stuck here.

undefined method `profiles'

Can you please help?

Codes

profiles_controller.rb

class ProfilesController < ApplicationController

  before_action :authenticate_user!, only: [:new, :create, :show]

  def new
    @profile = current_user.profiles.build
  end

  def create
    @profile = current_user.profiles.build(profile_params)
    if @profile.save
      format.html {redirect_to @profile, notice: 'Post was successfully created.'}
    else
      format.html {render 'new'}
    end

  end

  def show
    @profile = current_user.profiles
  end

  private

  def profile_params
    params.require(:profile).permit(:content)
  end
end

The error seems to be coming from these lines in particular

  def new
    @profile = current_user.profiles.build
  end

Other codes for reference:

/views/profiles/new.html.erb

<h1>Profiles#new</h1>
<p>Find me in app/views/profiles/new.html.erb</p>

<h3>Welcome <%= current_user.email %></h3>

<%= form_for(@profile) do |f| %>

  <div class="field">
    <%= f.label :content %><br />
    <%= f.text_field :text, autofocus: true %>
  </div>

  <div class="actions">
    <%= f.submit "Sign up" %>
  </div>
<%end%>

routes.rb

Rails.application.routes.draw do
  get 'profiles/new'

  get 'profiles/create'

  get 'profiles/show'

  get 'profiles/update'

  get 'pages/home'

  get 'pages/dashboard'

  devise_for :users,  controllers: { registrations: "registrations" }
  resources :profiles


  root 'pages#home'

  devise_scope :user do
    get "user_root", to: "page#dashboard"
  end
end

models/user.rb

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 :profile, dependent: :destroy
end

models/profile.rb

class Profile < ActiveRecord::Base

  belongs_to :user
end

Upvotes: 1

Views: 470

Answers (3)

Jorge de los Santos
Jorge de los Santos

Reputation: 4633

You are trying to call an undefined relationship:

  def new
    @profile = current_user.profiles.build
  end

  has_one :profile

You should be calling:

  def new
    @profile = current_user.build_profile
  end

Upvotes: 1

StanisLove Sid
StanisLove Sid

Reputation: 322

1) If your user must have many profiles. Set in your app/models/user.rb has_many :profiles

2) In your ProfilesController in new method instead of @profile = current_user.profiles use @profile = Profile.new

3) In your routes.rb delete

  get 'profiles/new'

  get 'profiles/create'

  get 'profiles/show'

  get 'profiles/update'

because you have already used resources :profiles

4) To stay with rules of DRY you can render form from a partial. Just add in views/profiles/_form.html.erb with the same content in your new.html.erb and after this you can delete everything im new.htm.erb and paste <%= render "form" %>. In future it will help you to render edit form if you want.

5) In your ProfilesController you can add method index with all profiles

def index
  @profiles = Profile.all
end

Upvotes: 1

Arjun Bharadwaj
Arjun Bharadwaj

Reputation: 41

I just figured it out!

As the relationship is has_one, we should be using

def new
   @profile = current_user.build_profile
end

instead of

def new
   @profile = current_user.profiles.build
end

according to the documentation -
http://guides.rubyonrails.org/association_basics.html#has-one-association-reference

Upvotes: 2

Related Questions