Nick
Nick

Reputation: 3090

undefined local variable or method `object' for error_messages

I'm not sure where this error message is coming from. I'm following Hartl's railtutorial but adapting it to my own app. I'm working on chapter 10 and am adding password resets.

When I get the error: After on the server sending the email with the link to reset the password. I then enter the link in my browser and get the following error message:

undefined local variable or method `object'
Extracted source (around line #2):
<% if object.errors.any? %>

This refers to the shared error messages file, which hasn't changed and didn't cause problems before. I'm not sure what to send you to see what could be the cause.

\views\shared_error_messages.html.erb

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

views\passwords_resets\edit.html.erb (the page that is called upon when following the link):

<% provide(:title, 'Reset password') %>
<h1 class="center">Reset password</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(@user, url: password_reset_path(params[:id])) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= hidden_field_tag :email, @user.email %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Update password", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

app\controllers\password_resets_controller.rb:

class PasswordResetsController < ApplicationController
  before_action :get_user,   only: [:edit, :update]
  before_action :valid_user, only: [:edit, :update]

  def new
  end

  def create
    @user = User.find_by(email: params[:password_reset][:email].downcase)
    if @user
      @user.create_reset_digest
      @user.send_password_reset_email
      flash[:info] = "An email is sent to you with password reset instructions"
      redirect_to root_url
    else
      flash.now[:danger] = "Email address not found"
      render 'new'
    end
  end

  def edit
  end

  def update
    if password_blank?
      flash.now[:danger] = "Password can't be blank"
      render 'edit'
    elsif @user.update_attributes(user_params)
      log_in @user
      flash[:success] = "Password has been reset."
      redirect_to @user
    else
      render 'edit'
    end
  end

  private

    def user_params
      params.require(:user).permit(:password, :password_confirmation)
    end

    # Returns true if password is blank.
    def password_blank?
      params[:user][:password].blank?
    end

    # Before filters

    def get_user
      @user = User.find_by(email: params[:email])
    end

    # Confirms a valid user.
    def valid_user
      unless (@user && @user.activated? && @user.authenticated?(:reset, params[:id]))
        redirect_to root_url
      end

    # Checks expiration of reset token.
    def check_expiration
      if @user.password_reset_expired?
        flash[:danger] = "Password reset has expired."
        redirect_to new_password_reset_url
      end
    end
end

Update: While writing this question I found out that when I remove the line <%= render 'shared/error_messages' %> from \views\shared_error_messages.html.erb I no longer have the problem and the new view shows correctly. It then works correctly in that I can change the password. However, the error messages then don't show up anymore (e.g., when password and password confirmation don't match). What to do?

Upvotes: 0

Views: 2883

Answers (2)

Rob Mulholand
Rob Mulholand

Reputation: 899

You have to pass an object to the error messages template when you render it. Your call to render the error messages template should now include object: f.object, like so:

<%= render "shared/error_messages", object: f.object %>

Upvotes: 1

Ajit Singh
Ajit Singh

Reputation: 146

Your partial doesnt know anything about "object". You have to pass @user object to the partial:

<%= render 'shared/error_messages', locals: {object: @user %>

Upvotes: 0

Related Questions