0

I am working on implementing unsubscribe link to my rails mailer. Unfortunately, my code breaks with this:

NoMethodError in Users#unsubscribe - undefined method `unsubscribe_hash' for nil:NilClass

which points to /app/views/users/unsubscribe.html.erb line #3

<h4>Unsubscribe from Mysite Emails</h4>
<p>By unsubscribing, you will no longer receive email...</p>
<%= simple_form_for(@user, unsubscribe_path(id: @user.unsubscribe_hash)) do |f| %>
    <%= f.hidden_field(:subscription, value: false) %>
    <%= f.submit 'Unsubscribe' %>
    <%= link_to 'Cancel', root_url %>
<% end %>

my user_controller is as shown below

class UsersController < ApplicationController
  protect_from_forgery

  def new
    @user = User.new
  end

  def create
    @user = User.new(secure_params)
    if @user.save
      flash[:notice] = "Thanks! You have subscribed #{@user.email} for Jobs Alert."
    else
      flash[:notice] = 'Error Subscribing! Kindly check your email and try again.'
    end
    redirect_to root_path
  end

  def unsubscribe
    user = User.find_by_unsubscribe_hash(params[:unsubscribe_hash])
    @user = User.find_by_unsubscribe_hash(user)
  end

  def update
    @user = User.find(params[:id])
    if @user.update(secure_params)
      flash[:notice] = 'Subscription Cancelled'
      redirect_to root_url
    else
      flash[:alert] = 'There was a problem'
      render :unsubscribe
    end
  end

  private

  def secure_params
    params.require(:user).permit(:email, :subscription)
  end

end

Route.rb

  resources :users, only: [:new, :create]
  get 'users/:unsubscribe_hash/unsubscribe' => 'users#unsubscribe', as: :unsubscribe
  patch 'users/update'

user.rb

class User < ActiveRecord::Base

  before_create :add_unsubscribe_hash, :add_true_to_users_table

  validates :email, :uniqueness => true
  validates_presence_of :email
  validates_format_of :email, :with => /\A[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i

  private

  def add_unsubscribe_hash
    self.unsubscribe_hash = SecureRandom.hex
  end

  def add_true_to_users_table
    self.subscription = true
  end

end

unsubscribe link in the email which calls unsubscribe action

# app/views/job_notifier/send_post_email.html.erb
...
<%= link_to "Unsubscribe", unsubscribe_url(id: @unsubscribe) %>.

diagrammatic view of the error

enter image description here

Its seems that I am missing something, do I need to define something in my users_controller? I have never in my life being able to solve NoMethodError or I don't understand what it's all about.

Afolabi Olaoluwa
  • 1,898
  • 3
  • 16
  • 37

2 Answers2

1

You get that error because @user (set in UsersController#unsubscribe) is nil. That is what the "for nil:NilClass" in undefined methodunsubscribe_hash' for nil:NilClass` is referring to.

This method doesn't seem correct:

def unsubscribe
  user = User.find_by_unsubscribe_hash(params[:unsubscribe_hash])
  @user = User.find_by_unsubscribe_hash(user)
end

You are looking up a user by unsubscribe_hash and assigning it to user, and then looking up user by unsubscribe_hash again but passing in user as the value to find_by_unsubscribe_hash.

I believe something like this is more as intended:

def unsubscribe
  @user = User.find_by_unsubscribe_hash(params[:unsubscribe_hash])
end
james246
  • 1,884
  • 1
  • 15
  • 28
  • even with this `@user = User.find_by_unsubscribe_hash(params[:unsubscribe_hash])` I get the same error. And whenever I try to do a workaround on it and use it as you suggested, I get `no implicit conversion of Symbol into Integer` error – Afolabi Olaoluwa Nov 15 '16 at 17:06
  • Have a look and check your `params[:unsubscribe_hash]` is the value you are submitting from the form, and that there is indeed a `User` in your database with that `unsubscribe_hash` value – james246 Nov 15 '16 at 17:18
  • YES it is the value. From all you said and explained which I have implemented, I now get `I get no implicit conversion of Symbol into Integer` error – Afolabi Olaoluwa Nov 15 '16 at 17:28
1

Whenever you see any error messages in ruby of the format:

undefined method 'method_name' for nil:NilClass

you are being told you are trying to call something on a nil object and so the focus of your attention should be on why is that object nil. You are also told in your log where the error occurs - in your case it refers to the line, which refers to @user in @user.unsubscribe_hash in your form declaration.

So @user is nil and in this case it's nil because your controller responsible for rendering the form isn't setting @user:

user = User.find_by_unsubscribe_hash(params[:unsubscribe_hash])
@user = User.find_by_unsubscribe_hash(user)

Now quite why you are attempting to find the user and then pass that user into the second line to find @user is beyond me, but anyway the real issue is that you have no user that matches params[:unsubscribe_hash]

So the issue is related to whatever is invoking your unsubscribe action ... you have neglected to add that to your question so I cannot help with that but that is where your focus start.

David
  • 3,510
  • 3
  • 21
  • 39
  • Thanks, well, I have refactored my unsubscribe action such that I have `@user = User.find_by_unsubscribe_hash(params[:unsubscribe_hash])`, however it leaves me with a new error saying `no implicit conversion of Symbol into Integer` – Afolabi Olaoluwa Nov 15 '16 at 17:32
  • read my solution again, i have made updates ... you need to investigate what is calling your action ... you didn't include that in your question. You might find using a debugger useful in situation like this too. – David Nov 15 '16 at 17:33
  • i have updated what calls the unsubscribe action which is in the mailer – Afolabi Olaoluwa Nov 15 '16 at 18:35
  • i think that link should be: `<%= link_to "Unsubscribe", unsubscribe_url(unsubscribe_hash: @unsubscribe) %>`, but I have to admit I'm a little confused by your screenshot - looking at that it does look like you are receiving the correct params. Worth checking your database just as a sanity check too, to ensure that unsubscribe_hash column exists. – David Nov 16 '16 at 09:13