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'
有帮助吗?

解决方案

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.

其他提示

Try adding resources :regular_users to your routes.rb file

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top