How to link to a create action from email template

I have an ‘unsubscribe’ model where an unsubscribe record gets created when the user clicks on this link within the app:

link_to "Unsubscribe from comments on this post", post_unsubscribes_path(@post), method: :post

I would like to provide the same link in an email when the user gets notified of comments. The only problem is ‘method: post’ doesn’t work in an email (reverts to a ‘get’ request). Here is the controller:

class UnsubscribesController < ApplicationController
  def create
    post = Post.find(params[:post_id])
    current_user.unsubscribes.create(post: post)
    redirect_to post_path(post), :notice => 'You are now unsubscribed from comments on this post.'
  end
end

Any ideas on how to go about doing this from an email? I googled endlessly and I can’t find anything even though this seems like it would be pretty common. Do I need to change how I go about this in the controller?

Hey @savmac,

I believe the issue here is that post_unsubscribes_path in your link_to should be post_unsubscribe_path.

I hope that helps!
-Chad

Hmm, I get an undefined method error when I try that. post_unsubscribes_path works in the app’s view, but not in the sent email because it’s trying to use rails built in javascript form magic with method: post (I think).
Here’s the current route:

resources :posts do
  resources :likes, :only => [:create]
  resources :unsubscribes, :only => [:create]
end

So I figured out a way to do this, I changed the route to:

resources :posts do
  resources :likes, :only => [:create]
  resources :unsubscribes, :only => [:index]
end

so now it will accept a get request.
Then I changed the controller to:

class UnsubscribesController < ApplicationController
  before_action :authenticate_user!, :create_unsubscribe

  def index

  end

  def create_unsubscribe
    post = Post.find(params[:post_id])
    current_user.unsubscribes.create(post: post)
    redirect_to post_path(post), :notice => 'You are now unsubscribed from comments on this post.'
  end
end

This works but it seems kind of hacky, is this a bad way to go about it?

Hey @savmac, if I understand correctly I would consider following the same pattern as Rails does with GET new and POST create. This way your email would link to the GET new path of the UnsubscribeController where you can display a summary of what is being unsubscribed and then a big Unsubscribe link/button to complete the process. This is the usual unsubscribe flow from email with other services so it’s not unfamiliar.

# config/routes.rb
resources :posts do
  resources :likes, :only => [:create]
  # Using resource http://stackoverflow.com/a/9194930
  resource :unsubscribes, :only => [:new, :create]
end
class UnsubscribesController < ApplicationController
  before_action :authenticate_user!, :set_post

  def new
    # Create a view for this
  end

  def create
    current_user.unsubscribes.create!(post: post)
    redirect_to post_path(post), :notice => 'You are now unsubscribed from comments on this post.'
  end

  private

  def set_post
    @post = Post.find(params[:post_id])
  end
end

Unfortunately emails will only use GET routes as forms are ignored and JS is not available.

I also wonder about why you’ve gone for an opt-out pattern instead of opt-in as I would have imagined it being ‘cleaner’ to have a join table for Subscribers to Posts instead of the other way round, then you could be GET show the subscription and DELETE destroy the subscription that makes a bit more sense to me – but I don’t know enough about this project to pass any judgment in that respect :smile:

Hope that helps anyway.

Thanks @createdbypete! Your approach is clear and makes sense.

I guess I was just looking for a way to do this in one step, similar to the way you would connect with someone from a linkedin email or even the way devise uses email/user confirmations. I think those methods though are probably a bit more complex for what is needed here by using tokens, additional fields etc.