1

I have a table CLIENTS with id, name and email fields and I am sending them emails using ActionMailer with 3rd party SMTP.

Now I want the clients to have subscription option too so I added "subscription" column with default value as true.

Now how to generate a link which can be put in views mailer template so when the user clicks on it, the subscription value changes to false so in future the client dont' get any email ? Do note that these clients are not my rails app users so I can't uses what is been suggested here Rails 3.2 ActionMailer handle unsubscribe link in emails

I found this link how to generate link for unsubscribing from email too which looked helpful but I thought may be in 3 years, we might have got a better solution

Here is my Complete Code -

#client.rb

attr_accessible :name, :company, :email

belongs_to :user
has_many :email_ids
has_many :emails, :through => :email_ids

before_create :add_unsubscribe_hash

private

def add_unsubscribe_hash
  self.unsubscribe_hash = SecureRandom.hex
end  

Here is Clients_controller.rb file

# clients_controller.rb

  def new
    @client = Client.new

    respond_to do |format|
      format.html
      format.json { render json: @client }
      format.js
    end
  end

  def create
    @client = current_user.clients.new(params[:client])
    respond_to do |format|
      if @client.save
        @clients = current_user.clientss.all
        format.html { redirect_to @client }
        format.json { render json: @client }
        format.js
      else
        @clients = current_user.clients.all
        format.html { render action: "new" }
        format.json { render json: @client.errors, status: :error }
        format.js
      end
    end
  end

def unsubscribe
  @client = Client.find_by_unsubscribe_hash(params[:unsubscribe_hash])
  @client.update_attribute(:subscription, false)
end

The code is working fine for existing records and the unsubscription is working perfectly, I am only having problem in creating new clients.

I have used @client in unsubscribe method as I am using this object in client_mailer.rb template (using @client or just using client, both are working!)

EDIT 2 - _form.html.erb

<%= simple_form_for(@client, :html => {class: 'form-horizontal'}) do |f| %>

    <%= f.input :name, :label => "Full Name" %>
    <%= f.input :company %>
    <%= f.input :email %>
    <%= f.button :submit, class: 'btn btn-success' %>
<% end %>

I have copied the full track stack at http://jsfiddle.net/icyborg7/dadGS/

Community
  • 1
  • 1
iCyborg
  • 4,699
  • 15
  • 53
  • 84

1 Answers1

6

Try associating each client with a unique, but obscure, identifier which can be used to look up (and unsubscribe) the user via the unsubscribe link contained within the email.

Start by adding another column to your clients table called unsubscribe_hash:

# from command line
rails g migration AddUnsubscribeHashToClients unsubscribe_hash:string

Then, associate a random hash with each client:

# app/models/client.rb
before_create :add_unsubscribe_hash

private

def add_unsubscribe_hash
    self.unsubscribe_hash = SecureRandom.hex
end

Create a controller action that will toggle the subscription boolean to true:

# app/controllers/clients_controller.rb
def unsubscribe
    client = Client.find_by_unsubscribe_hash(params[:unsubscribe_hash])
    client.update_attribute(:subscription, false)
end

Hook it up to a route:

# config/routes.rb
match 'clients/unsubscribe/:unsubscribe_hash' => 'clients#unsubscribe', :as => 'unsubscribe'

Then, when a client object is passed to ActionMailer, you'll have access to the unsubscribe_hash attribute, which you can pass to a link in the following manner:

# ActionMailer view
<%= link_to 'Unsubscribe Me!', unsubscribe_url(@user.unsubscribe_hash) %>

When the link is clicked, the unsubscribe action will be triggered. The client will be looked up via the passed in unsubscribe_hash and the subscription attribute will be turned to false.

UPDATE:

To add a value for the unsubscribe_hash attribute for existing clients:

# from Rails console
Client.all.each { |client| client.update_attribute(:unsubscribe_hash, SecureRandom.hex) }
zeantsoi
  • 25,857
  • 7
  • 69
  • 61
  • Thanks @Zeantsoi, I am going through the code and implementing it, looks really good. I will come back in 24 hours to accept the answer – iCyborg Jul 26 '13 at 16:47
  • hi @zeantsoi - It looks to be working but I am getting template missing error "Missing template clients/unsubscribe", so do I need to create a view or can I do some redirection ? how to do it. – iCyborg Jul 27 '13 at 09:14
  • alright i created the template, now it is working fine, the problem is, the url /clients/unsubscribe/xxxxxxxxx93411842d asks for login first where as the ppl getting the emails are not site users so how to show them the message ? – iCyborg Jul 27 '13 at 10:56
  • Hi @zeantsoi - while creating new clients, I am getting this error "undefined local variable or method `add_unsubscribe_hash'" ? any idea why ? – iCyborg Jul 27 '13 at 13:46
  • You should check your code for typos, particularly in your `Client` model. `add_unsubscribe_hash` should not be an object attribute – it's an ActiveRecord callback. I just tested the code as depicted and it works fine. – zeantsoi Jul 27 '13 at 16:12
  • @iCyborg, please **do not contact me at my personal address for Stack Overflow issues**. It is _extremely_ intrusive and, quite frankly, makes me feel weird about contributing to the site. Had you considered that I had yet to comment because I've been extremely busy, or perhaps live across the globe **and have been asleep**? – zeantsoi Jul 27 '13 at 16:15
  • my apologies @zeantsoi - that was my mistake, it won't happen again. I checked the code for typo mistakes but I am sure there is no problem there. I am getting this error "undefined local variable or method `add_unsubscribe_hash' for #" at @client.save line in client_controller.rb – iCyborg Jul 27 '13 at 17:55
  • Update your question to display your entire controller action and model. – zeantsoi Jul 27 '13 at 18:19
  • Post your stack trace and form view. – zeantsoi Jul 27 '13 at 18:53
  • I have put the _form.html.erb code and have posted the full stack trace too http://jsfiddle.net/icyborg7/dadGS/ – iCyborg Jul 27 '13 at 19:21
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/34304/discussion-between-zeantsoi-and-icyborg) – zeantsoi Jul 27 '13 at 19:25
  • @zeantsoi, I like to make reference to this solution as it throws an error `NoMethodError in Rails::Mailers#preview` `undefined method 'unsubscribe_hash' for #` after implementing this solution. How do I fix this? – Afolabi Olaoluwa Nov 15 '16 at 07:24