Question

I have implemented an oath object oriented approach to my rails application using this tutorial. I've also split my User Form into an Edit & Account Form.

User Edit Form

-Name
-Username
-AboutMe

User Account Form

-Email
-Password
-Password Confirmation

Everything seems to be working okay, until I try to Edit a Regular User's Account or Profile. For some reason I keep getting this error.

undefined method `regular_user_path' for #<#<Class:0x007fc1952f6da0>:0x007fc18bf350a8>

I am not sure why this may be happening. Here is my code below.

Models

class User < ActiveRecord::Base
  attr_accessible :name, :bio, :avatar, :username
end

class RegularUser < User

  has_secure_password

  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  VALID_UNAME_REGEX = /^[a-z](\w*[a-z0-9])*$/i

  validates :name, length: { maximum: 50 }

  validates :username, :presence   => true,
                     :length     => { :maximum => 15 },
                     :format     => { :with => VALID_UNAME_REGEX },
                     :uniqueness => { :case_sensitive => false }

  validates :bio, length: { maximum: 50 }

end

Controller

class UsersController < ApplicationController

  before_filter :signed_in_user, only: [:index, :profile, :update, :destroy, :following, :followers, :account]
  before_filter :correct_user,   only: [:edit, :update, :account]
  before_filter :admin_user,     only: [:destroy]

  def edit
    @user = User.find_by_username(params[:id])
  end

  def account
    @title = "Account"
    @user = User.find_by_username(params[:id])
  end

  def update
    @user = RegularUser.find(current_user.id)     ###I think this is causing it
    if @user.update_attributes(params[:user])
      flash[:success] = "Profile updated"
      sign_in @user
      redirect_to root_url
    else
      if URI(request.referer).path == edit_user_path ###redirects to appropriate page
        render 'edit'
      else
        render 'account'
      end
    end
  end

def destroy
  User.find_by_username(params[:id]).destroy
  flash[:success] = "User destroyed."
  redirect_to users_url
end

private

  def signed_in_user
    unless signed_in?
      store_location
      redirect_to (root_path), notice: "Please sign in."
    end
  end

  def correct_user
    @user = User.find_by_username(params[:id])
    redirect_to(root_path) unless current_user?(@user)
  end

  def admin_user
    redirect_to(root_path) unless current_user.admin?
  end

end

Views

Edit View

<%= form_for @user, :html => { :multipart => true } do |f| %>   ###error comes from this line
  <%= render 'shared/error_messages', object: f.object %>

  <div class="statictitle">Your Profile</div>

    <%= f.text_field :username, placeholder: "Username..", :class => "form-control" %>

    <%= f.text_field :name, placeholder: "Name", :class => "form-control" %>

    <%= f.text_area :bio, placeholder: "About yourself in 160 characters or less...", class: "textinput" %>

  <%= f.submit "Update Profile", class: "btn btn-primary" %><br>

<% end %>

Shared Errors

<% if object.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-error">
      The form contains <%= pluralize(object.errors.count, "error") %>.
    </div>
    <ul>
    <% object.errors.full_messages.each do |msg| %>
      <li>* <%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

Routes

resources :users do
  member do
    get :account
  end  
end

LOGS

Started PUT "/users/ClickOnComics" for 127.0.0.1 at 2014-02-20 17:17:50 -0800
Processing by UsersController#update as HTML

Parameters: {"utf8"=>"✓", "authenticity_token"=>"1CUMHhkE10ubS6uuc26fu1yTGn1bABKNqRIJ67EhEO4=",
"user"=>{"email"=>"clickoncomics@gmail.com", "password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]"}, "commit"=>"Update Account", "id"=>"ClickOnComics"}

User Load (0.9ms)  SELECT "users".* FROM "users" 
WHERE "users"."remember_token" = 'Wqodv-nd6EhKseqQf9FhqA' LIMIT 1

User Load (1.1ms)  SELECT "users".* FROM "users" 
WHERE "users"."username" = 'ClickOnComics' LIMIT 1

RegularUser Load (0.5ms)  SELECT "users".* FROM "users" 
WHERE "users"."id" = $1 LIMIT 1  [["id", 1]]

(0.2ms)  BEGIN
RegularUser Exists (2.7ms)  SELECT 1 AS one FROM "users" WHERE 
(LOWER("users"."username") = LOWER('ClickOnComics') AND "users"."id" != 1) 
LIMIT 1

RegularUser Exists (2.7ms)  SELECT 1 AS one FROM "users" 
WHERE (LOWER("users"."email") = LOWER('clickoncomics@gmail.com') AND "users"."id" != 1) LIMIT 1
(0.2ms)  ROLLBACK

CACHE (0.0ms)  SELECT "users".* FROM "users" WHERE "users"."username" = 'ClickOnComics' LIMIT 1
Completed 500 Internal Server Error in 237ms

NoMethodError (undefined method `errors=' for #<User:0x007fb6fadf87d0>):
app/controllers/users_controller.rb:40:in `update'
Was it helpful?

Solution

In your update action do as suggested below :

def update
    @user = RegularUser.find(current_user.id)     
    if @user.update_attributes(params[:user])
      flash[:success] = "Profile updated"
      sign_in @user
      redirect_to root_url
    else
      error_messages = @user.errors.messages       ### Capture the error messages
      @user = User.find_by_username(params[:id])   ### Add this line 
      @user.errors.messages.merge!(error_messages) ### Set the error messages hash 
      if URI(request.referer).path == edit_user_path 
        render 'edit'
      else
        render 'account'
      end
    end
  end 

When your update fails, you need to reset @user to User instance otherwise when you render edit view it will receive RegularUser instance rather than User instance whereas your form is expecting User instance.

OTHER TIPS

Try adding resources :regular_users to your routes.rb file

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top